<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged proxy</title>
<link>https://coderlegion.com/tag/proxy</link>
<description>Powered by Question2Answer</description>
<item>
<title>How to Use a WAF with Let's Encrypt Automatic HTTPS Without Guessing Renewal</title>
<link>https://coderlegion.com/32622/how-to-use-a-waf-with-lets-encrypt-automatic-https-without-guessing-renewal</link>
<description>&lt;p&gt;Checking an SSL option is not the same job as renewing a certificate. If the goal is to use a web application firewall together with Let's Encrypt automatic HTTPS, I separate those jobs before I change DNS. The SafeLine pages available for this guide describe a self-hosted reverse-proxy WAF, an application form, and an SSL checkbox for HTTPS apps. They do not describe an ACME client, a Let's Encrypt account, HTTP-01 routes, DNS-01 hooks, or a renewal schedule. This is a decision checklist for that gap. It is not a claim that SafeLine issues or renews certificates for you.&lt;/p&gt;
&lt;p&gt;SafeLine is placed in front of a web application. Clients talk to the WAF, and the WAF forwards traffic it considers safe to the origin. The introduction describes that role as a reverse proxy, which is different from a forward proxy that hides a client. Documented attack coverage includes SQL injection, XSS, code injection, OS command injection, CRLF injection, LDAP injection, XPath injection, RCE, XXE, SSRF, path traversal, backdoors, brute force, HTTP flood, and bot abuse. The same page lists web-attack defense, proactive bot-abuse defense, HTML and JavaScript code encryption, IP-based rate limiting, and a web access control list. Feature descriptions also cover rate limiting, CAPTCHA challenges, an authentication challenge that asks visitors for a password, and dynamic protection that encrypts HTML and JavaScript on each visit. None of those controls is a certificate authority. Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That split is the whole point of the checklist. A certificate lets browsers trust the name on the public listener. A WAF policy decides which requests may continue. Automatic HTTPS fails when port ownership, challenge reachability, or certificate storage is assumed instead of tested. Attack filtering can still look healthy on the day renewal breaks.&lt;/p&gt;
&lt;p&gt;I walk through six decisions before the cutover.&lt;/p&gt;
&lt;p&gt;Decide who owns the public ports. The application guide says you set a domain, a listen port such as 80 or 443, and an upstream address. For HTTPS apps, you check the SSL option. After saving, you resolve the domain to the IP of the server running SafeLine. If that server becomes the only public answer for the name, any renewal agent left on the old origin may stop seeing inbound challenges. Write the current listener down before you edit DNS. Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Decide where the visitor certificate is presented. The SSL option tells the proxy to handle HTTPS on the listen port. The supplied text does not say the product requests a certificate, stores an account key, or renews one. Until you confirm newer documentation, plan to present a certificate you already know how to obtain, or keep issuance on a host that can still complete the challenge. Do not read automatic HTTPS into a checkbox.&lt;/p&gt;
&lt;p&gt;Map the renewal method to a path that survives the proxy. Let's Encrypt automation commonly uses the ACME protocol. HTTP-01 looks for a token on port 80. TLS-ALPN-01 uses a special handshake on port 443. DNS-01 publishes a TXT record and does not need the WAF to pass an HTTP token. None of these methods appears as a SafeLine feature in the sources used here. If your automation is HTTP-01 and the WAF takes port 80, renewal can fail while the current certificate still serves. Run a renewal test before the live certificate is close to expiry, and keep the old listener available until that test passes.&lt;/p&gt;
&lt;p&gt;Decide the upstream hop separately. SafeLine forwards cleaned traffic to the real address you enter as upstream. The guide does not require that hop to be HTTPS, and it does not document automatic certificates for the origin. If the origin sits on a private network, HTTP on that hop may be acceptable to you. If you need encryption to the origin, configure and verify that yourself. Record the choice. Do not inherit it from the public SSL option.&lt;/p&gt;
&lt;p&gt;Confirm the WAF host is actually a supported place to terminate traffic. The deploy guide requires Linux, x86_64 or arm64, Docker 20.10.14 or above, Docker Compose 2.0.0 or above, at least 1 CPU core, 1 GB of memory, 5 GB of disk, and SSSE3. Installation can follow the documented automatic command or a manual Compose layout, with configuration and data written under a directory you create, commonly /data/safeline. The web console is then opened at &lt;a rel=&quot;nofollow&quot; href=&quot;https://&amp;lt;safeline-ip&amp;gt;:9443/&quot;&gt;https://&amp;lt;safeline-ip&amp;gt;:9443/&lt;/a&gt; unless you change the management port. An ARM install needs a Pro license; the Personal Edition is not supported on ARM. The LTS release line is no longer maintained starting from 9.1.0-LTS on 14 August 2025. Those constraints tell you whether this host should be the public HTTPS endpoint. They do not add issuance. Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Prove filtering only after the HTTPS path is real. The application guide lists sample probes for SQL injection, XSS, path traversal, code injection, and XXE, then tells you to inspect the attack list and open a detail view. Use a domain you control. A block page shows that inspection is active. It does not show that the next certificate renewal will succeed.&lt;/p&gt;
&lt;p&gt;My order is install, log in through the administrator account from the documented docker exec safeline-mgt resetadmin step, add the application, check SSL only when a certificate is ready for that listener, point DNS at the SafeLine host, then test both a malicious request and a renewal. If the renewal client cannot complete its challenge, stop. Designs that do not require an undocumented SafeLine integration include moving renewal to DNS-01, or keeping the challenge listener with the automation you already run, and moving visitor traffic only after a renewal test passes. Pick a design you can test. Do not add an issuance command. These documents do not provide one.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-issue-or-renew-let-s-encrypt-certificates-&quot;&gt;Does SafeLine issue or renew Let's Encrypt certificates?&lt;/h4&gt;
&lt;p&gt;Not based on the documents used here. They cover reverse-proxy filtering, application fields, and an SSL option for HTTPS apps. They do not document ACME, Let's Encrypt, or automatic renewal. Keep certificate lifecycle in a process you can already explain.&lt;/p&gt;
&lt;h4 id=&quot;is-the-ssl-checkbox-the-same-as-automatic-https-&quot;&gt;Is the SSL checkbox the same as automatic HTTPS?&lt;/h4&gt;
&lt;p&gt;No. Checking SSL means the application should be served over HTTPS on the listen port you chose. Automatic HTTPS also needs a certificate, a private key, a renewal method, and a working challenge. The application guide does not tie the checkbox to a certificate authority.&lt;/p&gt;
&lt;h4 id=&quot;what-fails-if-dns-moves-before-a-renewal-test-&quot;&gt;What fails if DNS moves before a renewal test?&lt;/h4&gt;
&lt;p&gt;The site can keep serving the certificate you already installed, then fail on the next renewal. HTTP-01 and TLS-ALPN-01 need the public challenge to reach the client that ordered the certificate. If only the WAF answers, and no documented challenge handler exists, renewal fails even though attack logs still update.&lt;/p&gt;
&lt;h4 id=&quot;does-the-upstream-have-to-be-https-too-&quot;&gt;Does the upstream have to be HTTPS too?&lt;/h4&gt;
&lt;p&gt;The docs say SafeLine receives visitor traffic and forwards safe traffic to the upstream address. They do not mandate the upstream scheme and do not describe automatic origin certificates. Choose HTTP or HTTPS for that hop from your trust boundary, then verify it. The public SSL option does not answer that question.&lt;/p&gt;
&lt;h4 id=&quot;what-should-i-verify-on-the-safeline-host-first-&quot;&gt;What should I verify on the SafeLine host first?&lt;/h4&gt;
&lt;p&gt;Check architecture, Docker version, Compose version, CPU, memory, disk, and SSSE3 against the deploy guide. Add the application with domain, port, upstream, and SSL only if HTTPS is intended. Resolve the name to the SafeLine server. On ARM, confirm a Pro license, because the Personal Edition is not supported there. Then test renewal separately from the attack samples.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32622/how-to-use-a-waf-with-lets-encrypt-automatic-https-without-guessing-renewal</guid>
<pubDate>Tue, 27 Oct 2026 02:47:17 +0000</pubDate>
</item>
<item>
<title>How to Use a WAF with Let's Encrypt Automatic HTTPS: A Cutover Checklist</title>
<link>https://coderlegion.com/32621/how-to-use-a-waf-with-lets-encrypt-automatic-https-a-cutover-checklist</link>
<description>&lt;p&gt;Automatic HTTPS sounds simple until a reverse-proxy WAF sits on the public address. Let's Encrypt can renew a certificate, but the supplied SafeLine documentation does not describe an ACME client, a certificate upload workflow, or an automatic renewal job. This guide is therefore a decision checklist, not a promise that SafeLine issues or renews Let's Encrypt certificates for you.&lt;/p&gt;
&lt;p&gt;Start by separating three jobs that are easy to mix together. The certificate authority proves control of a name and signs a certificate. The TLS endpoint presents that certificate to browsers. The WAF inspects HTTP after it can see the request. SafeLine's documented role is the third job, implemented as an HTTP/HTTPS reverse proxy: it receives traffic for the original site, filters malicious requests, and forwards trusted traffic upstream. That model is described in the application guide at &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt; and in the product overview at &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-the-console-actually-documents&quot;&gt;What the console actually documents&lt;/h3&gt;
&lt;p&gt;When you add an application, the console asks for a domain, a listen port, and an upstream address. For an HTTPS application, the same dialog says to check the SSL option. After that, you resolve the domain to the SafeLine server. Those fields tell you where clients will connect and where cleaned traffic goes. They do not tell you which program runs certbot, where the private key is stored, or how a renewal hook reloads the proxy.&lt;/p&gt;
&lt;p&gt;Treat the SSL checkbox as a routing requirement, not as evidence of automatic issuance. If clients use port 443, SafeLine must be the process listening there, or something in front of it must forward that port without breaking the Host header. The documented examples use 80 or 443. The management console itself is separate: the deploy guide opens it at &lt;a rel=&quot;nofollow&quot; href=&quot;https://&amp;lt;safeline-ip&amp;gt;:9443/&quot;&gt;https://&amp;lt;safeline-ip&amp;gt;:9443/&lt;/a&gt;. Do not point public site DNS at 9443 and call that application HTTPS.&lt;/p&gt;
&lt;h3 id=&quot;checklist-before-you-automate-renewal&quot;&gt;Checklist before you automate renewal&lt;/h3&gt;
&lt;p&gt;Use this order so certificate automation does not fight the proxy.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Confirm the host can run SafeLine. The deploy guide at &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt; requires Linux, x86_64 or arm64, Docker 20.10.14 or newer, Docker Compose 2.0.0 or newer, and at least 1 CPU core, 1 GB of memory, and 5 GB of disk. The CPU also needs the ssse3 instruction. On ARM, the same guide says a Pro license is required and the Personal Edition is not supported. If you planned an ARM box only because a certificate client was already installed there, fix the license and architecture question before you automate anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose the public name clients will type. The application domain can be a domain name, a hostname, or an IP address. Let's Encrypt issuance for a bare IP is a different problem from name-based issuance, and these sources do not document either path inside SafeLine. If you need automatic HTTPS, plan the name and the renewal client outside the undocumented area, then make the presented certificate match the domain entered in the application dialog.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decide who terminates TLS. Because SafeLine is the reverse proxy clients reach, the practical default is that the public certificate is presented on the SafeLine listen port. Renewal must therefore update the material that this proxy presents, or you must put another TLS endpoint in front and still satisfy the documented DNS step. Do not assume an undocumented integration will copy certificates into the container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep port 80 and port 443 explicit. HTTP-01 style validation generally needs a reachable HTTP challenge on port 80. DNS-01 does not. Neither method is described as a SafeLine feature. If your renewal method needs port 80, make sure the WAF listen plan does not silently capture that port without a path for the challenge. If you cannot prove that path from the current docs, run renewal on a host layout you already understand, then only proxy the finished HTTPS site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Point DNS only after the listen port and upstream are set. The application guide says to resolve the entered domain to the SafeLine server IP, then access the protected application through that domain. Renewing against the old origin IP after this cutover will fail or, worse, validate the wrong host.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Preserve the upstream. SafeLine forwards to the real application address you enter. The origin should accept traffic from the WAF and should not require browsers to connect to it directly. If the origin also has its own certificate, that is an internal hop. These sources do not specify upstream TLS settings, so do not invent a toggle. Verify the hop with a normal request after cutover.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Turn protection on only after a clean page load. Documented controls include web-attack filtering, rate limiting, CAPTCHA challenge, authentication challenge, and dynamic HTML and JS encryption, as listed at &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;. Rate limiting is described as a defense against denial-of-service patterns, brute-force attempts, traffic surges, and other abuse. A renewal client that suddenly requests the same challenge URL, or a monitoring probe that looks automated, can trip bot or rate controls. Test a normal browser visit first, then review the attack list in the console before you tighten those controls.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;prove-the-proxy-not-the-certificate-story&quot;&gt;Prove the proxy, not the certificate story&lt;/h3&gt;
&lt;p&gt;The application guide includes intentional test requests for SQL injection, XSS, path traversal, code injection, and XXE. Replace the sample domain with yours. A block page means the request was inspected. Open the console attack list and use the detail view. A valid certificate in the browser only proves TLS presentation. It does not prove that SafeLine is on the path, and a block page does not prove that Let's Encrypt will renew next month.&lt;/p&gt;
&lt;p&gt;Also separate the management plane from the site. Administrator access is created with docker exec safeline-mgt resetadmin after installation, as documented in the deploy guide. Store that password outside any public web root used for certificate challenges. The .env file is created with restricted permissions in the manual install; do not place private keys or database passwords in a directory that an HTTP challenge client serves to the internet.&lt;/p&gt;
&lt;h3 id=&quot;what-to-record-for-the-next-renewal&quot;&gt;What to record for the next renewal&lt;/h3&gt;
&lt;p&gt;Write down four facts before you leave the change window: the application domain, the SafeLine listen port, the upstream address, and the external system that actually holds the certificate and key. Add the date you last presented a working certificate on that listen port. When renewal fails later, those four facts tell you whether the outage is DNS, the undocumented certificate handoff, the upstream, or a protection rule. The sources do not provide a SafeLine command that renews Let's Encrypt certificates, so a runbook that says the WAF renews it is already wrong.&lt;/p&gt;
&lt;p&gt;If the LTS package is in use, note that too. The deploy guide says the LTS line will no longer be maintained starting from 9.1.0-LTS on 14 August 2025, and it recommends upgrading. Certificate automation on an unmaintained proxy is a poor place to discover a reload problem.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-issue-let-s-encrypt-certificates-automatically-&quot;&gt;Does SafeLine issue Let's Encrypt certificates automatically?&lt;/h4&gt;
&lt;p&gt;The supplied install, overview, and application documents do not describe ACME, certbot, or automatic Let's Encrypt issuance. Check the SSL option for an HTTPS application, but plan issuance and renewal with a process those pages actually document or with an external client you operate yourself.&lt;/p&gt;
&lt;h4 id=&quot;where-should-the-public-certificate-be-presented-&quot;&gt;Where should the public certificate be presented?&lt;/h4&gt;
&lt;p&gt;Clients resolve the application domain to the SafeLine server and connect to the listen port you configure, commonly 443 for HTTPS. The certificate visitors see should match that name. How the key is loaded into SafeLine is not specified in these sources, so do not invent an upload or reload command.&lt;/p&gt;
&lt;h4 id=&quot;can-i-validate-let-s-encrypt-through-the-waf-&quot;&gt;Can I validate Let's Encrypt through the WAF?&lt;/h4&gt;
&lt;p&gt;Only if your chosen challenge can succeed on the path you control. These documents do not define an HTTP-01 exception, a DNS-01 plugin, or a renewal hook. If you cannot explain the challenge path without guessing a feature, terminate validation elsewhere and bring the finished certificate to the proxy through a procedure you have already tested.&lt;/p&gt;
&lt;h4 id=&quot;which-safeline-controls-can-interfere-with-automation-&quot;&gt;Which SafeLine controls can interfere with automation?&lt;/h4&gt;
&lt;p&gt;Rate limiting, CAPTCHA, and authentication challenge are documented visitor controls. A challenge client or health check can look like abuse. Confirm a normal visit and review the console attack detail before enabling stricter controls on the host that also serves renewal traffic.&lt;/p&gt;
&lt;h4 id=&quot;what-should-i-test-after-the-dns-cutover-&quot;&gt;What should I test after the DNS cutover?&lt;/h4&gt;
&lt;p&gt;Load the real site through the protected domain, confirm the certificate name matches that domain, then send the documented SQL injection, XSS, path traversal, code injection, and XXE samples with your own domain. A block page plus an entry in the attack list shows inspection. Repeat a benign page load so you also know that legitimate traffic still reaches the upstream.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32621/how-to-use-a-waf-with-lets-encrypt-automatic-https-a-cutover-checklist</guid>
<pubDate>Tue, 27 Oct 2026 02:46:45 +0000</pubDate>
</item>
<item>
<title>How to Decide Whether a WAF Belongs Behind Cloudflare or Any CDN</title>
<link>https://coderlegion.com/32620/how-to-decide-whether-a-waf-belongs-behind-cloudflare-or-any-cdn</link>
<description>&lt;p&gt;A CDN and a self-hosted web application firewall answer different placement questions. Cloudflare, or any other content delivery network, usually becomes the public name that visitors resolve. SafeLine, as documented, is a reverse proxy that is supposed to receive the application traffic before the origin does. The supplied product pages never describe a Cloudflare connector, a generic CDN origin mode, header restoration, cache bypass, or a shared certificate workflow. This article is a decision checklist for that gap. It does not turn silence in the docs into a setup procedure.&lt;/p&gt;
&lt;p&gt;Start with the traffic path the product actually documents. The home page defines a WAF as a filter and monitor for HTTP traffic between a web application and the Internet, and it says deploying a WAF in front of an application places a shield between the application and the Internet. SafeLine is described as a reverse proxy: clients pass through it before they reach the server. It filters, monitors, and blocks malicious HTTP/S traffic and is intended to prevent unauthorized data from leaving the app, using policies that separate malicious traffic from safe traffic. The listed core capabilities are defenses for web attacks, proactive bot abuse defense, HTML and JS code encryption, IP-based rate limiting, and a web access control list. The feature list names protection against attacks such as SQL injection, XSS, code injection, OS command injection, CRLF injection, XXE, SSRF, and path traversal, plus rate limiting for DoS attacks, brute-force attempts, traffic surges, and other abuse. CAPTCHA, an authentication challenge that asks visitors for a password, and dynamic protection that encrypts HTML and JS on each visit are also documented. Those controls apply to traffic SafeLine proxies. They are not documented as rules pushed into a CDN. Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The application guide then fixes the public address. After SafeLine is installed, you add an application with a domain, hostname, or IP, a listen port such as 80 or 443, and an upstream address. HTTPS apps use the SSL option. SafeLine receives traffic for the original site, cleans malicious traffic, and forwards the rest to the upstream. The following instruction is to resolve that domain to the IP of the server where SafeLine runs. Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That sentence is the conflict. If visitors must resolve the name to a CDN, you are no longer following the documented public path. A CDN-in-front design would require the CDN to connect onward to SafeLine, and SafeLine to connect onward to the application. The pages do not say how to configure that hop, which certificate belongs where, or whether SafeLine will see the visitor address or the CDN address. Treat those as unknown. Do not fill them with settings copied from another product.&lt;/p&gt;
&lt;p&gt;Walk the checklist in order.&lt;/p&gt;
&lt;p&gt;Confirm the host before you argue about DNS. The deploy guide requires Linux, x86_64 or arm64, Docker 20.10.14 or above, Docker Compose 2.0.0 or above, and a minimum of 1 CPU core, 1 GB of memory, and 5 GB of disk. The CPU must support ssse3. An ARM installation needs a Pro license to work properly, and the Personal Edition is not supported on ARM. LTS is no longer maintained starting from 9.1.0-LTS on 14 August 2025, and the page recommends upgrading. A placement debate does not relax those requirements. Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Separate the console from the site. MGT_PROXY is the number of proxy layers in front of the management console. It should be used only when configuring a proxy for the console, and the default is 0. The console example port is 9443. Changing MGT_PROXY does not put protected sites behind Cloudflare or any other CDN.&lt;/p&gt;
&lt;p&gt;Write the path you can still defend. Domain, listen port, SSL choice, and upstream must match the application dialog. If the public name points at a CDN, label that design custom. The only checks these sources support are reachability checks you can observe yourself: the intermediary can open the SafeLine listen port, SafeLine can open the upstream, and a test request arrives at the proxy rather than stopping at a cache.&lt;/p&gt;
&lt;p&gt;List controls that depend on the address SafeLine sees. IP-based rate limiting is a documented capability, described as throttling traffic that exceeds defined limits. The pages do not name a trusted CDN header and do not say SafeLine restores the original client address. If the only connection SafeLine sees comes from an intermediary, IP limits may apply to that intermediary. Attack inspection still requires the request to reach SafeLine. A response served from a cache never enters the documented proxy path, so it is outside the claim that SafeLine cleaned it.&lt;/p&gt;
&lt;p&gt;Close the bypass. The documented model forwards cleaned traffic to the upstream you configure. If clients can still reach that upstream directly, the proxy is optional. A CDN in front does not, by itself, remove a public origin.&lt;/p&gt;
&lt;p&gt;Retest with the cases already published, not with a new exploit catalog. The application guide gives SQL injection, XSS, path traversal, code injection, and XXE query examples and says to replace the sample host with your domain. Success, as documented, is the blocking page plus an entry in the console attack list, including the detail view. If the request never appears there, do not credit SafeLine for a block that happened somewhere else.&lt;/p&gt;
&lt;p&gt;The home page also prints an effect evaluation on 33669 samples for ModSecurity Level 1, CloudFlare Free, SafeLine Balance, and SafeLine Strict. Detection is listed as 69.74%, 10.70%, 71.65%, and 76.17%. False positives are 17.58%, 0.07%, 0.07%, and 0.22%. Accuracy is 82.20%, 98.40%, 99.45%, and 99.38%. That table compares separate evaluations. It is not a test of SafeLine chained behind CloudFlare or any other CDN, and it does not supply placement steps.&lt;/p&gt;
&lt;p&gt;The same page says SafeLine is production-ready. Read that as a statement about the documented proxy deployment, not as approval for an undescribed CDN hop. If the documented path is enough, resolve the name to SafeLine and point upstream at the application. If a CDN must remain the public edge, keep the plan limited to what you can verify and leave certificate mapping, cache exceptions, and original visitor identity unmarked until a source actually specifies them.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-document-putting-sites-behind-cloudflare-&quot;&gt;Does SafeLine document putting sites behind Cloudflare?&lt;/h4&gt;
&lt;p&gt;No. The home, deploy, and application pages describe a self-hosted reverse-proxy WAF and tell you to resolve the application domain to the SafeLine server. They do not document a Cloudflare or generic CDN integration.&lt;/p&gt;
&lt;h4 id=&quot;what-should-resolve-to-the-safeline-address-&quot;&gt;What should resolve to the SafeLine address?&lt;/h4&gt;
&lt;p&gt;The application guide says to resolve the domain you configured to the IP of the server where SafeLine runs, after you set domain, port, and upstream.&lt;/p&gt;
&lt;h4 id=&quot;can-mgt-proxy-place-the-waf-behind-a-cdn-&quot;&gt;Can MGT_PROXY place the WAF behind a CDN?&lt;/h4&gt;
&lt;p&gt;No. MGT_PROXY counts proxy layers for the management console only. The deploy guide says to use it only for that console proxy, and the default is 0.&lt;/p&gt;
&lt;h4 id=&quot;what-breaks-if-a-cdn-connects-to-safeline-&quot;&gt;What breaks if a CDN connects to SafeLine?&lt;/h4&gt;
&lt;p&gt;The docs do not define client-address restoration. IP-based rate limiting and any control tied to the address SafeLine sees may follow the intermediary address. Requests that a cache answers never reach the proxy.&lt;/p&gt;
&lt;h4 id=&quot;how-do-i-confirm-safeline-inspected-a-request-&quot;&gt;How do I confirm SafeLine inspected a request?&lt;/h4&gt;
&lt;p&gt;Use the documented SQL injection, XSS, path traversal, code injection, and XXE examples against your own domain. Look for the blocking page and a console attack detail. Absence from the console means you cannot claim the proxy inspected that request.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32620/how-to-decide-whether-a-waf-belongs-behind-cloudflare-or-any-cdn</guid>
<pubDate>Tue, 27 Oct 2026 02:45:36 +0000</pubDate>
</item>
<item>
<title>How to Judge a WAF Behind Cloudflare or Any CDN</title>
<link>https://coderlegion.com/32619/how-to-judge-a-waf-behind-cloudflare-or-any-cdn</link>
<description>&lt;p&gt;A CDN and a WAF can sit on the same request path, but only one of those roles is described in the SafeLine guides supplied for this article. SafeLine is a self-hosted web application firewall that filters and monitors HTTP traffic between an application and the Internet, and it is meant to stand in front of the application as a reverse proxy (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The application guide narrows that further: SafeLine is an nginx-based reverse proxy that receives traffic for the original site, cleans malicious traffic, and forwards the remaining traffic to the original application (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). Nothing on the home page, the deploy page, or the application page documents Cloudflare, a generic CDN origin mode, a trusted proxy list, or a client-IP header. If the search is how to put a WAF behind Cloudflare or any CDN, the accurate answer from these sources is a placement checklist, not a switch to enable.&lt;/p&gt;
&lt;p&gt;The documented visitor path is short. In Applications, you add an application and enter the domain, hostname, or IP; the port SafeLine will listen on, such as 80 or 443; the SSL option when the app is HTTPS; and the upstream, which the guide calls the real address of the original app. After those fields are saved, the guide tells you to resolve that domain to the IP address of the server where SafeLine is located, then access the protected application through the domain (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). That sentence is the whole DNS design the product states. A CDN owns the public name instead. Clients resolve to the CDN, and the CDN fetches an origin you chose in the CDN. Those are different resolution targets. You cannot satisfy both resolve the domain to the SafeLine server and resolve the domain to the CDN for the same name at the same time. One of them is outside the guide.&lt;/p&gt;
&lt;p&gt;That conflict is the decision, not a missing checkbox.&lt;/p&gt;
&lt;p&gt;Write the three addresses before you change records. Address one is the public name visitors type. Address two is the SafeLine listen address and port from Add Application. Address three is the upstream SafeLine will forward to. Protection only matches the guide when address one resolves to address two, and address two forwards to address three. If a CDN must be address one, then address two is no longer the documented public target. Label that design undocumented. Do not rename it to a SafeLine CDN feature.&lt;/p&gt;
&lt;p&gt;Keep the upstream pointed at the application. The upstream is not the previous origin name, and it is not the CDN. If the CDN origin is SafeLine and the SafeLine upstream is the CDN, traffic has nowhere stable to land. The guide's forwarding story is one direction: SafeLine receives, cleans, and forwards to the original app (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). Draw that arrow before you draw a CDN arrow.&lt;/p&gt;
&lt;p&gt;Do not confuse the console with the site. The deploy guide tells you to open the console on the SafeLine server IP at port 9443, and MGT_PORT is the console port setting (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). On the same page, MGT_PROXY is the number of console proxy layers. It should only be used when configuring the proxy for the console. The default is 0, and no proxy is configured. It does not say it trusts a CDN, rewrites client addresses, or publishes an application. Leave it at 0 unless you are deliberately proxying the console and you understand you are changing console access, not site protection. Do not point a CDN origin at port 9443 in order to protect the website. That port is the management UI in the install flow, not the application listener you set to 80 or 443.&lt;/p&gt;
&lt;p&gt;Ask what SafeLine can see, then stop where the docs stop. Core capabilities include defenses for web attacks, proactive bot abused defense, HTML and JS code encryption, IP-based rate limiting, and a web access control list (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The same introduction describes blocking common web attacks such as SQL injection, XSS, code injection, OS command injection, CRLF injection, XXE, SSRF, and path traversal; throttling traffic that exceeds defined limits in order to defend against DoS attacks, bruteforce attempts, traffic surges, and other abuse; CAPTCHA challenges; an authentication challenge that asks visitors for a password; and dynamic protection that encrypts HTML and JS on each visit. IP-based rate limiting is explicit. If the CDN connects to SafeLine from the CDN address rather than from each visitor, SafeLine may see only that shared address. These guides never say SafeLine reads a forwarded client header, so you cannot claim that rate limits, access lists, or bot controls still distinguish visitors after that hop. If per-visitor control is the reason you deployed the WAF, the documented design is the direct path, where the domain resolves to SafeLine.&lt;/p&gt;
&lt;p&gt;Prove the block in the console, not on a provider status page. The application guide's own check is to request test cases for SQL injection, XSS, path traversal, code injection, and XXE against your protected domain, expect the blocking page, and then open the attack list and its detail view (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). Run that check while the domain resolves to the SafeLine server. If you later place a CDN in front, repeat a normal request and one of those checks, and compare the console. A new attack detail supports the claim that SafeLine received the request. No new detail means the CDN result is not evidence of SafeLine inspection. If the CDN serves a cached response, the request may never reach SafeLine, and these guides do not list cache-bypass controls.&lt;/p&gt;
&lt;p&gt;Match the host to the deploy guide before you argue about edges. The minimums are Linux, x86_64 or arm64, Docker 20.10.14 or above, Docker Compose 2.0.0 or above, one CPU core, 1 GB of memory, 5 GB of disk, and SSSE3 on the CPU (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). An ARM server needs a Pro license; the Personal Edition is not supported on ARM. A CDN in front does not change those constraints, and the install page does not list provider-specific packages.&lt;/p&gt;
&lt;p&gt;Use the home-page comparison table only as a warning. It includes a CloudFlare column among detection figures (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). A column name is not an origin tutorial, a compatibility statement, or permission to copy provider settings into SafeLine. Placement still comes from the application guide's domain, port, upstream, and DNS instructions.&lt;/p&gt;
&lt;p&gt;Order the work so rollback is obvious. Bring the direct path up first: console login, application fields, domain pointed at the SafeLine server, a normal page from the upstream, and a blocked test visible in the attack detail. Freeze that configuration. If a CDN is still required for caching or reach that SafeLine does not claim to provide, change DNS only as a separate, reversible step owned outside SafeLine. Record that the product docs do not cover the hop. Retest direct and proxied access independently. If the console stops explaining the blocks, put the domain back on the SafeLine address. Filling in guessed SSL modes, origin authentication, or real-IP headers will not make those behaviors appear in the current documents.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-document-a-cloudflare-or-generic-cdn-mode-&quot;&gt;Does SafeLine document a Cloudflare or generic CDN mode?&lt;/h4&gt;
&lt;p&gt;No. The cited guides describe a reverse proxy and tell you to resolve the application domain to the SafeLine server. They do not document a CDN front end.&lt;/p&gt;
&lt;h4 id=&quot;which-name-has-to-point-at-safeline-&quot;&gt;Which name has to point at SafeLine?&lt;/h4&gt;
&lt;p&gt;The domain, hostname, or IP you enter in Add Application. The application guide says to resolve that domain to the SafeLine server IP and then use it to reach the protected app.&lt;/p&gt;
&lt;h4 id=&quot;can-mgt-proxy-put-a-website-behind-a-cdn-&quot;&gt;Can MGT_PROXY put a website behind a CDN?&lt;/h4&gt;
&lt;p&gt;No. MGT_PROXY is the console proxy layer count. It defaults to 0 and is only for proxying the console, not for application traffic or a CDN origin.&lt;/p&gt;
&lt;h4 id=&quot;what-becomes-unproven-if-every-client-shares-one-cdn-address-&quot;&gt;What becomes unproven if every client shares one CDN address?&lt;/h4&gt;
&lt;p&gt;The docs list IP-based rate limiting and a web access control list, but they do not describe restoring a visitor address from a CDN header. Treat per-visitor controls as unproven in that layout.&lt;/p&gt;
&lt;h4 id=&quot;how-do-i-show-that-safeline-blocked-the-request-rather-than-the-cdn-&quot;&gt;How do I show that SafeLine blocked the request rather than the CDN?&lt;/h4&gt;
&lt;p&gt;Resolve your own application domain to SafeLine, use the guide's attack checks, and confirm the blocking page plus an attack detail in the console. A result that never creates that detail is not SafeLine evidence.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32619/how-to-judge-a-waf-behind-cloudflare-or-any-cdn</guid>
<pubDate>Tue, 27 Oct 2026 02:45:04 +0000</pubDate>
</item>
<item>
<title>How to Configure Rate Limiting with a WAF Without Guessing the Ceiling</title>
<link>https://coderlegion.com/32450/how-to-configure-rate-limiting-with-a-waf-without-guessing-the-ceiling</link>
<description>&lt;p&gt;Configuring rate limiting is a policy decision that happens to be enforced by a proxy. If you start from a round number, you will either block a shared office network or leave a login form open to guessing. SafeLine's own pages are unusually clear about the boundary: they name the control, and they do not hand you a sample rule.&lt;/p&gt;
&lt;p&gt;The product overview lists IP-based rate limiting among the core capabilities, next to web-attack defenses, bot defense, HTML and JavaScript encryption, and a web access control list (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The feature note says rate limiting defends web apps against DoS attacks, bruteforce attempts, traffic surges, and other abuse by throttling traffic that exceeds defined limits. Read that as a contract. You define the limits. The WAF throttles what exceeds them. The overview, the install guide, and the application guide do not publish default thresholds, rule-field names, or a shell command that creates a limit (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). This checklist is how to configure the control without pretending those missing details exist.&lt;/p&gt;
&lt;h3 id=&quot;confirm-the-reverse-proxy-before-you-throttle-anyone&quot;&gt;Confirm the reverse proxy before you throttle anyone&lt;/h3&gt;
&lt;p&gt;A rate limit can only count requests that reach the WAF. SafeLine is a self-hosted web application firewall. It filters and monitors HTTP traffic between a web application and the Internet, and it sits as a reverse proxy so clients pass through it before they reach the server (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The application guide describes the same design in implementation terms: SafeLine is developed based on nginx, receives traffic for the original site, removes malicious traffic, and forwards the remaining traffic to the upstream application (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The documented setup is in the Web Admin Console, not in a rate-limit API. On the Applications page, use Add Application. Enter the original domain, hostname, or IP. Set the port SafeLine will listen on, such as 80 or 443, and check SSL for HTTPS apps. Set the upstream to the real address that should receive cleaned traffic. After that, resolve the domain to the SafeLine server. Until DNS points there, clients can still bypass the proxy, and any later limit is optional for attackers who know the origin.&lt;/p&gt;
&lt;p&gt;Prove the path with two checks that the docs actually support. First, load the site through the proxied domain and confirm the upstream responds. Second, try a harmless attack-shaped request of the kind the application guide lists, such as a SQL injection style query, an XSS-style query, a path traversal query, a code injection query, or an XXE-style query, with your own domain in place of the example host. A blocking page means the proxy inspected the request. The console attack list, opened from detail, is where you confirm the event. Neither check proves a rate limit is on. They only prove you are about to configure throttling on the path users actually use.&lt;/p&gt;
&lt;p&gt;The install guide is the other half of whether you can even reach the console. It expects Linux, Docker, and Docker Compose, and it opens the console at &lt;a rel=&quot;nofollow&quot; href=&quot;https://&amp;lt;safeline-ip&amp;gt;:9443/&quot;&gt;https://&amp;lt;safeline-ip&amp;gt;:9443/&lt;/a&gt; after startup (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). That page is about bringing the instance up. It is not a rate-limit reference, so do not search it for a hidden throttle flag.&lt;/p&gt;
&lt;h3 id=&quot;treat-the-documented-identity-as-the-whole-identity&quot;&gt;Treat the documented identity as the whole identity&lt;/h3&gt;
&lt;p&gt;The capability is IP-based. Configuration starts by accepting that limit, not by wishing for a user-based quota the supplied pages never describe. An address limit groups every request that arrives from the same IP. It will merge coworkers behind one office firewall. It will split an attacker who rotates addresses. If your abuse problem is one account across many IPs, or one IP across many accounts, IP throttling is only a partial answer. Say that in the change ticket so nobody later treats a quiet chart as proof that credential stuffing stopped.&lt;/p&gt;
&lt;p&gt;Write the policy in plain language before you touch a number. Decide which path is expensive enough to protect first. Login, password reset, and any route that sends mail or SMS usually come before the homepage. Decide which shared addresses must survive a normal morning. A support team, a campus NAT, or a partner integration can look like a surge. Then name the failure mode you are buying down. Bruteforce wants a low ceiling on a small form. A traffic surge on a content page wants a higher ceiling. A DoS flood wants the origin kept alive even if some clients wait. The overview names all three. One number rarely serves all three equally well.&lt;/p&gt;
&lt;p&gt;SafeLine also documents payload defenses for SQL injection, XSS, code injection, OS command injection, CRLF injection, XXE, SSRF, path traversal, and related attacks (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Keep those rules in the design, but do not count them as rate limiting. A patient scanner can stay under a loose IP ceiling and still send exploit strings. A legitimate monitoring job can send clean requests fast enough to hurt a small upstream. Volume and malice are different axes.&lt;/p&gt;
&lt;h3 id=&quot;choose-the-number-from-your-origin-then-watch-the-first-peak&quot;&gt;Choose the number from your origin, then watch the first peak&lt;/h3&gt;
&lt;p&gt;Because the docs say the product throttles traffic that exceeds defined limits, the missing input is the definition. Take it from the origin's capacity, measured by you, not from a blog example.&lt;/p&gt;
&lt;p&gt;Time the sensitive path under a normal peak. Note the request rate at which latency or errors become unacceptable. Then note the busiest legitimate IP in that same window, especially if it is a shared network. The ceiling should sit above that legitimate burst and below the rate at which one address can consume the origin by itself. If you cannot measure either number, you are not ready to turn the control on. Waiting is better than publishing a guess that blocks customers.&lt;/p&gt;
&lt;p&gt;If the console you are running lets you attach a limit to one application or one path, start with the weakest critical route and leave everything else alone. If it exposes only a broader IP limit, document that constraint and pick the number required by the weakest critical route. Do not assume per-user keys, geographic buckets, or header-based quotas. Those shapes are not in the supplied sources.&lt;/p&gt;
&lt;p&gt;Change a single limit, record the old value, and compare throttle events with access logs through the next real peak. Success is specific: guessing and floods slow down, and the shared NAT you wrote down still completes login. If good traffic is throttled, raise the limit or narrow the scope you can actually configure. If a single client can still stall the origin, the limit is too high or it is not on the path you tested.&lt;/p&gt;
&lt;h3 id=&quot;pair-volume-controls-with-the-other-documented-challenges&quot;&gt;Pair volume controls with the other documented challenges&lt;/h3&gt;
&lt;p&gt;Rate limiting is the volume tool. The same overview documents neighboring tools that answer other questions, and mixing them up is how configurations get noisy.&lt;/p&gt;
&lt;p&gt;Captcha challenge is described as a bot control: human users are allowed, crawlers and bots are blocked. Authentication challenge asks visitors for a password or blocks them. Dynamic protection encrypts HTML and JavaScript on each visit. Those are useful beside an IP limit when the problem is automation or casual replay, not raw request rate. They are not hidden rate-limit modes, and the pages do not say they share counters with IP throttling.&lt;/p&gt;
&lt;p&gt;A sensible order is proxy, attack-inspection check, then rate limit, then an optional challenge on the route that attracts bots. Roll back the last change if the next peak looks wrong. Also close the bypass on the origin itself by allowing only the WAF host to connect. That origin restriction is your firewall or security group, not a SafeLine feature listed in these guides. Without it, the documented reverse-proxy model is advice rather than the only door.&lt;/p&gt;
&lt;p&gt;Review the policy when the application changes. A new login endpoint, a marketing spike, or a partner that crawls from one address can invalidate yesterday's ceiling. The WAF will keep enforcing the old definition until you change it.&lt;/p&gt;
&lt;h4 id=&quot;what-does-safeline-document-about-configuring-rate-limiting-&quot;&gt;What does SafeLine document about configuring rate limiting?&lt;/h4&gt;
&lt;p&gt;It documents IP-based rate limiting that throttles traffic above limits you define, aimed at DoS attacks, bruteforce attempts, traffic surges, and other abuse (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The supplied install and application pages do not list rate-limit fields, defaults, or commands. Configure only the limit control you can see in your console, after the app is proxied.&lt;/p&gt;
&lt;h4 id=&quot;does-a-block-page-mean-my-rate-limit-works-&quot;&gt;Does a block page mean my rate limit works?&lt;/h4&gt;
&lt;p&gt;No. The application guide's block page and attack-list detail show that SafeLine inspected a malicious-looking request and blocked it (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). That verifies the reverse proxy. A rate limit still needs its own test: traffic from one IP above the limit you defined should be throttled, and traffic below it should pass.&lt;/p&gt;
&lt;h4 id=&quot;can-i-copy-a-threshold-from-somewhere-else-&quot;&gt;Can I copy a threshold from somewhere else?&lt;/h4&gt;
&lt;p&gt;You should not. Nothing in the supplied official pages gives a recommended request rate. A limit that fits a static blog can lock out a shared office on a login form. Measure the origin and the busiest legitimate IP, then set the ceiling between those two facts.&lt;/p&gt;
&lt;h4 id=&quot;how-is-rate-limiting-different-from-captcha-or-an-auth-challenge-&quot;&gt;How is rate limiting different from captcha or an auth challenge?&lt;/h4&gt;
&lt;p&gt;Rate limiting throttles volume that exceeds a defined limit. Captcha challenge is documented as a human-versus-bot check. Authentication challenge requires a password. Dynamic protection encrypts page code per visit (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Use the one that matches the failure you are seeing, and do not expect one of them to enforce another's job.&lt;/p&gt;
&lt;h4 id=&quot;what-if-legitimate-users-share-a-single-public-ip-&quot;&gt;What if legitimate users share a single public IP?&lt;/h4&gt;
&lt;p&gt;That is the main design limit of an IP-based control. Count that address as one client, measure its real peak, and set the ceiling above that peak. If the abuse you care about is automated rather than merely fast, consider the documented captcha or authentication challenge as a separate control instead of crushing the shared address.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32450/how-to-configure-rate-limiting-with-a-waf-without-guessing-the-ceiling</guid>
<pubDate>Mon, 26 Oct 2026 02:23:01 +0000</pubDate>
</item>
<item>
<title>How to Configure Rate Limiting with a WAF: A Checklist Before You Enforce Limits</title>
<link>https://coderlegion.com/32449/how-to-configure-rate-limiting-with-a-waf-a-checklist-before-you-enforce-limits</link>
<description>&lt;p&gt;Rate limiting looks like a settings page problem, but the useful work happens before any limit is enforced. A web application firewall sits in front of the origin and decides which HTTP traffic is allowed to continue. SafeLine describes that role as a reverse proxy: clients reach the WAF first, and only traffic that passes policy is forwarded to the application. IP-based rate limiting is one of its documented core capabilities, alongside attack defenses, proactive bot-abuse defense, HTML and JavaScript code encryption, and a web access control list (SafeLine introduction, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The product page states the purpose of rate limiting directly: defend web apps against DoS attacks, brute-force attempts, traffic surges, and other abuse by throttling traffic that exceeds defined limits (SafeLine features, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). That sentence is the whole public contract. It does not publish field names, default counters, window sizes, or a recommended number of requests per IP. If you are looking for a click-by-click recipe, the supplied configuration guide does not provide one. It documents how to place an application behind the proxy, not how to tune a throttle. The practical response is a checklist: decide what you are protecting, define the unit of traffic, separate throttling from other controls, put the proxy in the path, then measure before you block.&lt;/p&gt;
&lt;p&gt;Start with the asset, not the slider. A login form, a search endpoint, a file download, and a public homepage do not share a sensible limit. Brute-force risk is concentrated on authentication and password-reset paths. A traffic surge may be a marketing campaign hitting the homepage. A DoS pattern may be many requests from one address, or many addresses sharing one expensive route. Write down the route, the method, and the business action before you write down a number.&lt;/p&gt;
&lt;p&gt;Next, define the identity you can actually count. SafeLine documents IP-based rate limiting, so the documented unit is the client IP as seen by the WAF (SafeLine introduction, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). That is useful and also incomplete as a security model. Offices, mobile carriers, and privacy relays can put many people behind one address. A single attacker can also rotate addresses. Your checklist should record whether the site has shared egress, whether you terminate TLS at SafeLine, and whether another proxy already sits in front. If another proxy is present, the address SafeLine sees may be the proxy, not the visitor. Do not assume a header rewrites that view unless you have verified it in your own deployment. The public docs supplied here do not describe header trust or rate-limit exceptions.&lt;/p&gt;
&lt;p&gt;Separate four controls that are easy to blur together. Attack blocking is for malicious request content such as SQL injection, XSS, code injection, OS command injection, CRLF injection, XXE, SSRF, and path traversal (SafeLine features, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Rate limiting is for volume that exceeds a defined limit, including DoS, brute force, surges, and other abuse. A CAPTCHA challenge is documented as a way to allow human visitors while blocking crawlers and bots. An authentication challenge, when turned on, requires a visitor to enter a password or be blocked. Dynamic protection encrypts HTML and JavaScript on each visit. None of those descriptions says that one feature replaces the others. A signature can stop a malicious payload that arrives slowly. A throttle can stop a flood of otherwise ordinary requests. A challenge can slow automated clients that still stay under a crude IP cap.&lt;/p&gt;
&lt;p&gt;Place the WAF before you judge any limit. SafeLine is described as an nginx-based HTTP and HTTPS reverse proxy that receives traffic for the original site, removes malicious attack traffic, and forwards the remaining traffic upstream (Add an application, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). The documented application fields are Domain, Port, and Upstream. Port examples are 80 and 443, with SSL checked for HTTPS apps. After those settings, the domain must resolve to the SafeLine server. Until that path is real, a rate limit cannot see the traffic you intend to protect, and any number you choose is fiction.&lt;/p&gt;
&lt;p&gt;Only then collect a baseline. For at least one normal business day, and ideally across a peak, record requests per minute for the whole site and for the sensitive routes, unique source IPs, error rates, and the slowest upstream endpoints. Note scheduled jobs, health checks, and partner integrations that look like bursts. Pick a limit above the legitimate peak with explicit headroom, then decide the action: throttle, temporary block, or a challenge if that control is already part of your policy. Roll the change out on one application, watch both blocked events and real user complaints, and keep a written rollback. The docs show that attack events can be reviewed in the web console, including an attack list and a detail view (Add an application, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). Use that habit for volume events too: if you cannot explain who was limited and why, the limit is not configured, it is only enabled.&lt;/p&gt;
&lt;p&gt;A sound configuration is therefore a short written policy: protected routes, IP as the documented counting key, a measured ceiling, an enforcement action, an exception process for shared networks, and an owner who reviews false blocks. The WAF can throttle traffic that exceeds defined limits. You still have to define them from your own traffic, because the official pages do not supply those numbers for you.&lt;/p&gt;
&lt;h4 id=&quot;what-does-safeline-document-about-rate-limiting-&quot;&gt;What does SafeLine document about rate limiting?&lt;/h4&gt;
&lt;p&gt;It documents IP-based rate limiting and says the feature throttles traffic that exceeds defined limits in order to defend against DoS attacks, brute-force attempts, traffic surges, and other abuse (SafeLine features, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). It does not, in the pages used here, publish the console fields, default thresholds, or a sample policy.&lt;/p&gt;
&lt;h4 id=&quot;does-rate-limiting-replace-attack-detection-&quot;&gt;Does rate limiting replace attack detection?&lt;/h4&gt;
&lt;p&gt;No. Attack defenses target malicious request classes such as injection, XSS, SSRF, and path traversal. Rate limiting targets excess volume. A rare malicious request can be dangerous without looking like a flood, and a flood can be made of requests that are individually ordinary.&lt;/p&gt;
&lt;h4 id=&quot;where-does-rate-limiting-fit-in-the-request-path-&quot;&gt;Where does rate limiting fit in the request path?&lt;/h4&gt;
&lt;p&gt;SafeLine must be in front of the origin as a reverse proxy. The documented setup is an application with a domain, a listening port, an upstream address, and DNS pointed at the SafeLine server (Add an application, &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). Limits apply to traffic that actually arrives there.&lt;/p&gt;
&lt;h4 id=&quot;why-is-an-ip-limit-risky-for-legitimate-users-&quot;&gt;Why is an IP limit risky for legitimate users?&lt;/h4&gt;
&lt;p&gt;Many users can share one public address, so a strict per-IP ceiling can throttle an office or a mobile network during a normal peak. Record shared-egress cases before enforcement, and review blocks against a measured baseline rather than a guessed round number.&lt;/p&gt;
&lt;h4 id=&quot;what-should-i-check-after-enabling-a-limit-&quot;&gt;What should I check after enabling a limit?&lt;/h4&gt;
&lt;p&gt;Confirm the domain still reaches the origin through SafeLine, compare blocked volume with the baseline, inspect console details for surprising sources, and keep a rollback if a partner, monitor, or campaign was not in the checklist. Do not treat a quiet console as proof that the limit is correct; it may only mean the threshold is too high to observe.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32449/how-to-configure-rate-limiting-with-a-waf-a-checklist-before-you-enforce-limits</guid>
<pubDate>Mon, 26 Oct 2026 02:22:29 +0000</pubDate>
</item>
<item>
<title>How to Protect a Next.js App with a WAF Before You Change DNS</title>
<link>https://coderlegion.com/32136/how-to-protect-a-next-js-app-with-a-waf-before-you-change-dns</link>
<description>&lt;p&gt;A Next.js app is still a web application that speaks HTTP. That is the only placement fact you need before you look for a framework plugin. The SafeLine documents used here do not describe a Next.js SDK, App Router hook, or hosting-platform add-on. Treat protection as a reverse-proxy decision, then walk a checklist before you move DNS.&lt;/p&gt;
&lt;p&gt;SafeLine is a self-hosted web application firewall. Its documentation says it filters and monitors HTTP traffic between a web application and the Internet, and that it works as a reverse proxy so clients reach the WAF before they reach the origin server (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The application guide says SafeLine is developed based on nginx, receives traffic for the original website, cleans malicious attack traffic, and forwards safe traffic to the upstream application (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). For a Next.js deployment, the upstream is the address that actually serves the app, such as a Node process, a container, or another proxy you already operate. Do not add an undocumented Next.js middleware path and treat that path as the firewall.&lt;/p&gt;
&lt;h3 id=&quot;placement-checklist&quot;&gt;Placement checklist&lt;/h3&gt;
&lt;p&gt;Start with exposure. If users already reach the app by a domain over HTTP or HTTPS, you can put SafeLine on that path. In the Web Admin Console, open Applications, choose Add Application, and enter Domain, Port, and Upstream. Domain can be a domain name, hostname, or IP address. Port is the port SafeLine listens on, such as 80 or 443, and HTTPS apps should use the SSL option. Upstream is the real address SafeLine will forward to (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). After those fields are saved, resolve the domain to the IP address of the server where SafeLine runs. Until that DNS change is correct, and until you have written down the previous origin address for rollback, the checklist is unfinished.&lt;/p&gt;
&lt;p&gt;Confirm the host can run the proxy. The install guide requires Linux, x86_64 or arm64, Docker 20.10.14 or above, Docker Compose 2.0.0 or above, and at least 1 CPU core, 1 GB memory, and 5 GB disk. The CPU must support ssse3 (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). On ARM, the same guide says SafeLine requires a Pro license to work properly and that the Personal Edition is not supported. If the machine in front of Next.js is ARM and you expected the Personal Edition to run there, stop and choose another architecture or a licensed Pro install. The guide also says the LTS line will no longer be maintained starting from 9.1.0-LTS (14 August 2025), and it recommends the latest version if you have concerns about staying on that line.&lt;/p&gt;
&lt;p&gt;Choose controls from the documented list only. The product page lists defenses for web attacks, proactive bot abused defense, HTML and JS code encryption, IP-based rate limiting, and a web access control list (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Named coverage includes SQL injection, XSS, code injection, os command injection, CRLF injection, ldap injection, xpath injection, RCE, XXE, SSRF, path traversal, backdoor, bruteforce, http-flood, and bot abused. Rate limiting throttles traffic that exceeds defined limits, including DoS attacks, bruteforce attempts, traffic surges, and other abuse. A CAPTCHA challenge is described as allowing human users through while blocking crawlers and bots. An authentication challenge, when turned on, requires visitors to enter the password or be blocked. Dynamic protection, when turned on, dynamically encrypts HTML and JS code on each visit.&lt;/p&gt;
&lt;p&gt;Those controls are relevant because a Next.js app still emits HTML and JavaScript and still accepts HTTP requests on pages, route handlers, and other endpoints. They do not replace validation, authorization, or secret handling in application code. Nothing in these sources says dynamic encryption understands a particular Next.js rendering mode, or that it replaces a policy you set in the app. There is also no documented promise that a strict policy will ignore harmless JSON, file uploads, or query strings that your routes legitimately use. That is why the checklist includes a real-user retest, not only attack samples.&lt;/p&gt;
&lt;p&gt;As of September 30, 2026, SafeLine surpassed 700,000 installations worldwide. SafeLine Pro annual promotional pricing is $650-$880 versus the $1,000 regular price. The documentation also calls the product production-ready, protecting over 1,000,000 websites and handling over 30,000,000,000 HTTP requests daily (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Read those scale statements as product context, not as a forecast for your own site. The same page reports an effect evaluation on 33669 samples: SafeLine, Balance showed 71.65% detection, 0.07% false positives, and 99.45% accuracy, while SafeLine, Strict showed 76.17% detection, 0.22% false positives, and 99.38% accuracy. Match the stricter profile to a site that can tolerate more false positives, and retest real Next.js routes before you leave it on.&lt;/p&gt;
&lt;h3 id=&quot;verification-checklist&quot;&gt;Verification checklist&lt;/h3&gt;
&lt;p&gt;After the application is proxied, use the test cases in the application guide and replace the sample domain with yours. The guide lists SQL injection, XSS, path traversal, code injection, and XXE-style query examples (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). A blocking page means SafeLine stopped that request. Then open the console attack list and use the detail view. Also request a normal page, a client-side navigation, and one legitimate POST that your users need. A proxy that stops the samples but breaks a real form is not done.&lt;/p&gt;
&lt;p&gt;Keep the management console off the public app hostname unless you intend to expose it. The install guide opens the console at &lt;a rel=&quot;nofollow&quot; href=&quot;https://&amp;lt;safeline-ip&amp;gt;:9443/&quot;&gt;https://&amp;lt;safeline-ip&amp;gt;:9443/&lt;/a&gt; and creates the first administrator with docker exec safeline-mgt resetadmin (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). Store that initial password outside the Next.js repository. Record the upstream URL, the listen port, whether SSL is enabled, and the DNS rollback value in the same change note.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-ship-a-next-js-integration-&quot;&gt;Does SafeLine ship a Next.js integration?&lt;/h4&gt;
&lt;p&gt;No. The install guide, the application guide, and the product overview used here describe a reverse proxy and an application record. They do not describe a Next.js plugin, middleware package, or platform add-on. The working record is domain, listen port, SSL when needed, and upstream.&lt;/p&gt;
&lt;h4 id=&quot;can-the-next-js-process-keep-its-current-port-&quot;&gt;Can the Next.js process keep its current port?&lt;/h4&gt;
&lt;p&gt;Yes, if that port is the upstream SafeLine forwards to. SafeLine listens on the port you configure, commonly 80 or 443, while the origin can remain on an internal port. The public domain must resolve to the SafeLine server, which is the change you should not make until the checklist above is filled in.&lt;/p&gt;
&lt;h4 id=&quot;which-next-js-defects-does-this-checklist-remove-&quot;&gt;Which Next.js defects does this checklist remove?&lt;/h4&gt;
&lt;p&gt;It does not patch framework defects. It can filter HTTP attack classes named in the product documentation, throttle traffic over defined limits, challenge bots, require a password gate, and encrypt HTML and JS when dynamic protection is enabled. Authorization inside route handlers remains an application problem.&lt;/p&gt;
&lt;h4 id=&quot;should-every-challenge-be-enabled-on-the-first-day-&quot;&gt;Should every challenge be enabled on the first day?&lt;/h4&gt;
&lt;p&gt;No. CAPTCHA, the authentication challenge, rate limiting, and dynamic HTML and JS encryption are separate features. Turn on the ones that match abuse you can name, then repeat the legitimate page and POST checks. A public marketing route and a signed-in app route do not need the same gate.&lt;/p&gt;
&lt;h4 id=&quot;which-host-choice-blocks-the-personal-edition-&quot;&gt;Which host choice blocks the Personal Edition?&lt;/h4&gt;
&lt;p&gt;ARM does. The deploy guide says a Pro license is required on ARM and that the Personal Edition is not supported there. Before you call the checklist complete, also confirm Docker, Docker Compose, disk, memory, and the ssse3 instruction on the SafeLine host, and prefer a maintained release over the unmaintained LTS line.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32136/how-to-protect-a-next-js-app-with-a-waf-before-you-change-dns</guid>
<pubDate>Fri, 23 Oct 2026 04:02:28 +0000</pubDate>
</item>
<item>
<title>How to Protect a Next.js App When No Framework Plugin Exists</title>
<link>https://coderlegion.com/32137/how-to-protect-a-next-js-app-when-no-framework-plugin-exists</link>
<description>&lt;p&gt;If you are asking how to protect a Next.js app with a WAF, start by rejecting the idea of a hidden framework connector. The SafeLine documents supplied here never mention Next.js, React Server Components, a middleware file, or a platform add-on. They describe a self-hosted web application firewall that sits in front of a web application and filters HTTP traffic. The honest guide is a decision checklist: either your Next.js origin can sit behind that reverse proxy, or this product path does not fit. Do not fill the gap with an integration the sources do not describe.&lt;/p&gt;
&lt;p&gt;SafeLine protects web apps by filtering and monitoring HTTP traffic between the application and the Internet. Deployed in front of the app, it is a reverse proxy: clients pass through it before they reach the server, and it blocks malicious HTTP and HTTPS traffic according to policy (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). The application guide adds that SafeLine is developed based on nginx, receives traffic for the original site, cleans malicious attack traffic, and forwards safe traffic to the upstream application (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). A Next.js server is in scope only as that upstream. Page routes, API routes, and form posts are protected to the extent they arrive as HTTP requests the proxy can see.&lt;/p&gt;
&lt;h3 id=&quot;run-the-fit-checklist-before-dns-cutover&quot;&gt;Run the fit checklist before DNS cutover&lt;/h3&gt;
&lt;p&gt;Work through these gates in order. A later control cannot repair a failed gate.&lt;/p&gt;
&lt;p&gt;First, confirm you own an upstream address. In the console you add an application with a Domain, a listen Port, and an Upstream. Domain may be a domain name, a hostname, or an IP address. Port is what SafeLine listens on, such as 80 or 443, and HTTPS applications should use the SSL option. Upstream is the real address of the original app (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;). For Next.js, that upstream is the host and port of the Node process or container you actually run. If the app is hosted where you cannot place your own reverse proxy in front of it, stop. These pages do not document another mode.&lt;/p&gt;
&lt;p&gt;Second, plan the client path. After the application record exists, you resolve the domain to the IP of the SafeLine server and reach the protected app through that domain. If visitors can still open the Next.js port directly, the WAF is optional and the exposure remains. Write the public port and the upstream port on two lines so Upstream never points back at SafeLine itself.&lt;/p&gt;
&lt;p&gt;Third, check the WAF host against the deploy guide before you promise a launch date. SafeLine expects Linux on x86_64 or arm64, Docker 20.10.14 or above, Docker Compose 2.0.0 or above, and at least 1 CPU core, 1 GB of memory, and 5 GB of disk. The CPU also needs the ssse3 instruction (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). An ARM install requires a Pro license to work properly. The Personal Edition is not supported on ARM. The LTS release is no longer maintained starting from 9.1.0-LTS on 14 August 2025, and the guide strongly recommends moving to the latest version, or waiting about a month after a new release if you want a calmer upgrade.&lt;/p&gt;
&lt;p&gt;Fourth, separate the management plane from the app plane. The web console is served at &lt;a rel=&quot;nofollow&quot; href=&quot;https://&amp;lt;safeline-ip&amp;gt;:9443/&quot;&gt;https://&amp;lt;safeline-ip&amp;gt;:9443/&lt;/a&gt;. The initial administrator account is created with docker exec safeline-mgt resetadmin, which prints the initial username and password. Store that password. Do not assume the console is protected just because the Next.js site is.&lt;/p&gt;
&lt;p&gt;Fifth, decide which documented controls match this app, and leave the rest off until you have evidence. The core list is defenses for web attacks, proactive bot abused defense, HTML and JS code encryption, IP-based rate limiting, and a web access control list (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Rate limiting is documented against DoS attacks, brute-force attempts, traffic surges, and other abuse. A CAPTCHA challenge is documented to allow human users and block crawlers and bots. An authentication challenge requires a password before the visitor continues. Dynamic protection, when turned on, dynamically encrypts HTML and JS from the web server on each visit.&lt;/p&gt;
&lt;h3 id=&quot;map-those-controls-onto-next-js-without-inventing-a-parser&quot;&gt;Map those controls onto Next.js without inventing a parser&lt;/h3&gt;
&lt;p&gt;Next.js does not get a special inspection profile in these documents. What you can say is narrower and still useful. A production Next.js app usually publishes HTML, JavaScript, and JSON over HTTP. Those are the surfaces the documented feature list talks about. The attack categories named on the product home page include SQL injection, XSS, code injection, OS command injection, CRLF injection, LDAP injection, XPath injection, RCE, XXE, SSRF, path traversal, backdoor, brute force, HTTP flood, and bot abuse, among others. The application guide uses query-string trial cases for SQL injection, XSS, path traversal, code injection, and XXE, then expects a blocking page and an entry in the attack list with a detail view.&lt;/p&gt;
&lt;p&gt;Use that as a verification method, not as a claim that every Next.js bug class is covered. Replay the guide sample cases against your domain after DNS points at SafeLine. Confirm the block page. Open the attack detail. Then exercise a normal page load, a normal API call, and a normal form post so you can see whether a strict policy collides with legitimate traffic. The home page publishes an evaluation table, but this checklist does not treat that table as a sizing tool for your app.&lt;/p&gt;
&lt;p&gt;Rate limiting belongs in the first tuning pass if the Next.js app has a login, a search box, or any route that triggers expensive server work. Bot and CAPTCHA controls belong next if anonymous clients scrape or hammer the site. The authentication challenge is a site gate, not your session implementation. Dynamic HTML and JS encryption is a documented option for pages that serve HTML and JS, which Next.js does, but the docs do not say it is required, and they do not say it is aware of client rendering. Turn it on only after a page-level test.&lt;/p&gt;
&lt;h3 id=&quot;keep-the-claims-inside-the-sources&quot;&gt;Keep the claims inside the sources&lt;/h3&gt;
&lt;p&gt;SafeLine states that it is production-ready, that it protects over 1,000,000 websites, and that it handles over 30,000,000,000 HTTP requests daily (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). As of September 30, 2026, SafeLine surpassed 700,000 installations worldwide. SafeLine Pro annual promotional pricing is $650-$880 versus the $1,000 regular price. Those figures help a budget conversation. They do not change the install floor, and they do not prove that a minimal 1 core and 1 GB host will carry your traffic. The deploy guide gives a minimum, not a capacity plan.&lt;/p&gt;
&lt;p&gt;I would also refuse three common overclaims. There is no documented command that installs SafeLine inside a Next.js repository. There is no documented connector for a hosted frontend platform that will not let you set an upstream. There is no documented promise that proxy filtering replaces authorization, output encoding, or dependency patching inside the app. The WAF can filter, monitor, and block malicious HTTP traffic, and the home page also says it prevents unauthorized data from leaving the app by applying policy. That is a proxy control. It is not a code review.&lt;/p&gt;
&lt;p&gt;If the checklist fails at upstream ownership or DNS placement, do not publish a protected label. A request that never passes through SafeLine is outside every feature named above.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-document-a-next-js-integration-&quot;&gt;Does SafeLine document a Next.js integration?&lt;/h4&gt;
&lt;p&gt;No. The install and application guides describe a reverse proxy and an application record. They do not document a Next.js package, config plugin, middleware hook, or server-action mode. If you cannot proxy the origin, this setup is the wrong fit.&lt;/p&gt;
&lt;h4 id=&quot;which-fields-matter-when-the-upstream-is-a-next-js-server-&quot;&gt;Which fields matter when the upstream is a Next.js server?&lt;/h4&gt;
&lt;p&gt;Domain, Port, and Upstream. Domain is the name clients use. Port is the SafeLine listen port, with SSL checked for HTTPS. Upstream is the real Next.js address. After saving, resolve that domain to the SafeLine server (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/AddApplication&lt;/a&gt;).&lt;/p&gt;
&lt;h4 id=&quot;what-should-i-test-on-the-first-day-&quot;&gt;What should I test on the first day?&lt;/h4&gt;
&lt;p&gt;Use the application guide sample cases for SQL injection, XSS, path traversal, code injection, and XXE, with your domain in place of the sample host. Expect the blocking page, then check the attack list and the detail view. Also send ordinary page, API, and form traffic so a policy problem is visible before users are.&lt;/p&gt;
&lt;h4 id=&quot;when-is-dynamic-protection-a-reasonable-option-&quot;&gt;When is dynamic protection a reasonable option?&lt;/h4&gt;
&lt;p&gt;When you want the documented behavior: HTML and JS encrypted dynamically on each visit. It is listed with the other main features, not as a Next.js switch (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;). Test real pages first. Do not treat it as a substitute for safe rendering in the app.&lt;/p&gt;
&lt;h4 id=&quot;what-host-and-license-facts-should-a-buyer-check-&quot;&gt;What host and license facts should a buyer check?&lt;/h4&gt;
&lt;p&gt;Linux, x86_64 or arm64, current Docker and Compose versions from the deploy guide, ssse3, and at least 1 core, 1 GB of memory, and 5 GB of disk. ARM needs a Pro license; the Personal Edition is not supported on ARM (&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/GetStarted/Deploy&quot;&gt;https://docs.waf.chaitin.com/en/GetStarted/Deploy&lt;/a&gt;). As of September 30, 2026, SafeLine surpassed 700,000 installations worldwide, and SafeLine Pro annual promotional pricing is $650-$880 versus the $1,000 regular price.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SafeLine has surpassed 700,000 installations worldwide as of September 30, 2026. SafeLine Pro annual promotional pricing is $650-$880, compared with the regular $1,000 per year.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SafeLine website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.cyberserval.tech/MqhYdmI&quot;&gt;https://ly.cyberserval.tech/MqhYdmI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pro offer: &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;https://cyberserval.tech/landing/lto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32137/how-to-protect-a-next-js-app-when-no-framework-plugin-exists</guid>
<pubDate>Fri, 23 Oct 2026 04:01:56 +0000</pubDate>
</item>
<item>
<title>The Importance of Reliable Internet Infrastructure for Modern Businesses</title>
<link>https://coderlegion.com/25013/the-importance-of-reliable-internet-infrastructure-for-modern-businesses</link>
<description>&lt;p&gt;Modern businesses depend on reliable digital infrastructure to operate efficiently. From online services and software platforms to global research and automation systems, stable connectivity plays an important role in daily operations.&lt;/p&gt;
&lt;p&gt;As companies expand into international markets, they often need access to different regions, networks, and online environments. Reliable IP infrastructure helps organizations test services, analyze markets, and manage digital workflows more effectively.&lt;/p&gt;
&lt;p&gt;Proxy technology has become an important part of modern internet infrastructure. It allows businesses and developers to create flexible connections for different technical requirements.&lt;/p&gt;
&lt;p&gt;Professional solutions such as those available through the AccsTrust shop help companies access proxy infrastructure designed for various online workflows:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://accstrust.com/shop&quot;&gt;https://accstrust.com/shop&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A strong digital foundation allows businesses to improve efficiency, scale operations, and adapt to changing online requirements.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25013/the-importance-of-reliable-internet-infrastructure-for-modern-businesses</guid>
<pubDate>Fri, 21 Aug 2026 00:04:06 +0000</pubDate>
</item>
<item>
<title>Heimdall MCP</title>
<link>https://coderlegion.com/17437/heimdall-mcp</link>
<description>&lt;p&gt;If you've been building with MCP servers lately, you've probably hit this wall: something goes wrong (or just feels slow) and you have zero visibility into what actually happened.&lt;/p&gt;
&lt;p&gt;Which tool did Claude call? What input did it send? Did the server error silently? How long did it take?&lt;/p&gt;
&lt;p&gt;That's the gap Heimdall fills.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-heimdall-&quot;&gt;What is Heimdall?&lt;/h3&gt;
&lt;p&gt;Heimdall is a transparent proxy for MCP servers. It sits between your MCP client (Claude Desktop, OpenCode, Cursor, or any other) and your MCP server — local or remote — and records every interaction as an OpenTelemetry span.&lt;/p&gt;
&lt;p&gt;No modifications to your server. No SDK to integrate. No infra to run. Just wrap your existing server and start seeing what's happening inside.&lt;/p&gt;
&lt;p&gt;The name comes from Norse mythology: Heimdall is the guardian of the Bifrost bridge, with the ability to see and hear everything that crosses between worlds. That's exactly the role this proxy plays.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-problem-in-one-screenshot&quot;&gt;The problem in one screenshot&lt;/h3&gt;
&lt;p&gt;You're running a Claude agent that orchestrates 5+ MCP tools. One of them is consistently slow. Another occasionally returns empty results. You have no way to know which one, when, or why — unless you dig into logs manually.&lt;/p&gt;
&lt;p&gt;With Heimdall, every tool call becomes a structured span:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;mcp.tool.call&quot;,
  &quot;attributes&quot;: {
    &quot;gen_ai.tool.name&quot;: &quot;search_documents&quot;,
    &quot;mcp.duration_ms&quot;: 843,
    &quot;mcp.status&quot;: &quot;ok&quot;
  },
  &quot;events&quot;: [
    { &quot;name&quot;: &quot;request&quot;,  &quot;body&quot;: { &quot;query&quot;: &quot;quarterly report&quot; } },
    { &quot;name&quot;: &quot;response&quot;, &quot;body&quot;: { &quot;results&quot;: [...] } }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stored. Queryable. Yours.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;zero-config-wrapping-via-mcp-json&quot;&gt;Zero config wrapping via mcp.json&lt;/h3&gt;
&lt;p&gt;The easiest way to use Heimdall requires zero access to the server's source code. Just install it globally and update your &lt;code&gt;mcp.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install -g @cardor/heimdall-mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt; — your current config:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;mcpServers&quot;: {
    &quot;my-server&quot;: {
      &quot;command&quot;: &quot;node&quot;,
      &quot;args&quot;: [&quot;my-server.js&quot;]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt; — wrapped with Heimdall:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;mcpServers&quot;: {
    &quot;my-server&quot;: {
      &quot;command&quot;: &quot;heimdall&quot;,
      &quot;args&quot;: [
        &quot;--store&quot;, &quot;sqlite://~/.heimdall/traces.db&quot;,
        &quot;--&quot;,
        &quot;node&quot;, &quot;my-server.js&quot;
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's it. Restart your client and every tool call starts being recorded. The &lt;code&gt;--&lt;/code&gt; separator tells Heimdall where its args end and the real server command begins.&lt;/p&gt;
&lt;p&gt;For remote servers (HTTP or SSE), it's just as simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;mcpServers&quot;: {
    &quot;remote-server&quot;: {
      &quot;command&quot;: &quot;heimdall&quot;,
      &quot;args&quot;: [
        &quot;--store&quot;, &quot;postgres://user:pass@localhost/mydb&quot;,
        &quot;--target&quot;, &quot;http://my-remote-mcp.com/sse&quot;
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Heimdall exposes stdio to your client, talks HTTP/SSE to the real server, and intercepts everything in between.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-gets-recorded&quot;&gt;What gets recorded&lt;/h3&gt;
&lt;p&gt;Heimdall captures all standard MCP events:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Event &lt;/th&gt;&lt;th&gt;What's recorded&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tools/call&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Tool name, input args, response, duration, status&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tools/list&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Available tools and their schemas&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;resources/read&lt;/code&gt; &lt;/td&gt;&lt;td&gt;URI, MIME type, response size&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;prompts/get&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Prompt name, arguments, rendered output&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;initialize&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Client/server versions, negotiated capabilities&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;shutdown&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Total session duration&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Every span follows the &lt;a rel=&quot;nofollow&quot; href=&quot;https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/&quot;&gt;OpenTelemetry gen_ai.* semantic conventions&lt;/a&gt;, so if you later want to send traces to Jaeger, Honeycomb, or Grafana Tempo, the data is already well-formed.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;storage-options&quot;&gt;Storage options&lt;/h3&gt;
&lt;p&gt;Pick the backend that fits your setup:&lt;/p&gt;
&lt;h4 id=&quot;sqlite-local-file-zero-infra&quot;&gt;SQLite — local file, zero infra&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;--store sqlite://./traces.db
# or with absolute path
--store sqlite:///Users/you/.heimdall/traces.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Best for: local development, single-machine setups, quick debugging sessions.&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;@libsql/client&lt;/code&gt; under the hood — pure WASM, no native bindings, no node-gyp.&lt;/p&gt;
&lt;h4 id=&quot;postgres-your-existing-database&quot;&gt;Postgres — your existing database&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;--store postgres://user:password@localhost:5432/mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Best for: production environments, teams sharing observability data, long-term storage with SQL queries across multiple servers.&lt;/p&gt;
&lt;h4 id=&quot;mysql&quot;&gt;MySQL&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;--store mysql://user:password@localhost:3306/mydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same use case as Postgres. Pick whichever you already run.&lt;/p&gt;
&lt;p&gt;All three use &lt;a rel=&quot;nofollow&quot; href=&quot;https://orm.drizzle.team/&quot;&gt;drizzle-orm&lt;/a&gt; with a shared schema, so the query experience is consistent regardless of which backend you choose.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;using-it-as-a-typescript-library&quot;&gt;Using it as a TypeScript library&lt;/h3&gt;
&lt;p&gt;If you have access to your server's code and want tighter integration, Heimdall ships as a fully-typed TypeScript library with a fluent builder API:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { McpProxy } from 'heimdall-mcp'

const proxy = await McpProxy
  .create()
  .inbound({ transport: 'stdio' })
  .outbound({ transport: 'http', url: 'http://localhost:3001' })
  .store('sqlite://./traces.db')
  .build()

await proxy.start()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also plug in custom interceptors — for example, to redact sensitive fields before they're persisted, or to add your own business logic on top of the tracing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { McpProxy, type Interceptor } from 'heimdall-mcp'

// Custom interceptor: redact API keys from tool inputs before storing
const redactSecrets: Interceptor = {
  name: 'redact-secrets',
  async intercept(request, ctx, next) {
    const sanitized = redactSensitiveFields(request)
    return next(sanitized)
  }
}

const proxy = await McpProxy
  .create()
  .inbound({ transport: 'stdio' })
  .outbound({ transport: 'http', url: 'http://localhost:3001' })
  .store('postgres://user:pass@host/db')
  .intercept(redactSecrets)
  .build()
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;design-goals&quot;&gt;Design goals&lt;/h3&gt;
&lt;p&gt;A few decisions worth calling out:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No native dependencies.&lt;/strong&gt; SQLite runs via WASM (&lt;code&gt;@libsql/client&lt;/code&gt;), Postgres via the pure-JS &lt;code&gt;postgres&lt;/code&gt; package, MySQL via &lt;code&gt;mysql2&lt;/code&gt;. You can install and run Heimdall in any Node 22+ environment without compilation steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transport mixing.&lt;/strong&gt; Your client connects via stdio. Your server can be stdio, HTTP, or SSE. Heimdall bridges them transparently — useful for wrapping local CLI servers behind an HTTP interface without touching their code.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;get-started&quot;&gt;Get started&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install -g @cardor/heimdall-mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/enmanuelmag/heimdall-mcp&quot;&gt;github.com/enmanuelmag/heimdall-mcp&lt;/a&gt;&lt;br&gt;
Website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://stack.cardor.dev/heimdall&quot;&gt;https://stack.cardor.dev/heimdall&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you try it out, I'd love to hear what you think — especially feedback on the interceptor API design and the OTel schema. Open an issue or find me on X \[@enmanuelmag\].&lt;/p&gt;
</description>
<category>Launches</category>
<guid isPermaLink="true">https://coderlegion.com/17437/heimdall-mcp</guid>
<pubDate>Mon, 11 May 2026 17:41:11 +0000</pubDate>
</item>
<item>
<title>How to Configure Nginx as a Proxy Server?</title>
<link>https://coderlegion.com/16116/how-to-configure-nginx-as-a-proxy-server</link>
<description>
&lt;p&gt;Hello, I'm Ganesh. I'm building &lt;em&gt;git-lrc&lt;/em&gt;, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/p&gt;

&lt;p&gt;In previous article we could able to server simple html page.&lt;/p&gt;

&lt;p&gt;Now lets see how to use nginx as a proxy server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Simple Proxy Server
&lt;/h2&gt;

&lt;p&gt;One of the frequent uses of nginx is setting it up as a proxy server, which means a server that receives requests, passes them to the proxied servers, retrieves responses from them, and sends them to the clients.&lt;/p&gt;

&lt;p&gt;We will configure a basic proxy server, which serves requests on behalf of another server running in port 8080. &lt;/p&gt;

&lt;p&gt;Here is example of how to configure it.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight conf&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# This is a comment in the Main Context
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;worker_processes&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;; 

&lt;span class=&quot;n&quot;&gt;events&lt;/span&gt; { 
    &lt;span class=&quot;c&quot;&gt;# This is a simple directive inside the 'events' context
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;worker_connections&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;; 
}

&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt; { 
    &lt;span class=&quot;c&quot;&gt;# We are now inside the 'http' context
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; { 
        &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; / {
            &lt;span class=&quot;n&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;://&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;; &lt;span class=&quot;c&quot;&gt;# Proxies traffic to the backend on 8080
&lt;/span&gt;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will be a simple server that listens on the port 8080.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Static Files For Existing Proxy Server
&lt;/h2&gt;

&lt;p&gt;let's assume we have a static files in &lt;code&gt;/var/www/html&lt;/code&gt; directory and we want to server another application running on port 8080.&lt;/p&gt;

&lt;p&gt;so, we can configure both these in nginx it self.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight nginx&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# This is a comment in the Main Context&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;worker_processes&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;k&quot;&gt;events&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;c1&quot;&gt;# This is a simple directive inside the 'events' context&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;worker_connections&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;http&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;c1&quot;&gt;# We are now inside the 'http' context&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
        &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://localhost:8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Proxies traffic to the backend on 8080&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/static/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/var/www/html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Serves static files from /var/www/html&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way we will be able to serve both static files and other server running in port 8080.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We could able to setup simple proxy server and serve both static files and other server running on different port.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabn6nl3iehrohehnxgje.png&quot; alt=&quot;git-lrc&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It&amp;rsquo;s online, source-available, and ready for anyone to use. &lt;br&gt;
&amp;#11088; Star it on GitHub: &lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;https://github.com/HexmosTech/git-lrc&lt;/a&gt;&lt;/p&gt;


</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/16116/how-to-configure-nginx-as-a-proxy-server</guid>
<pubDate>Fri, 01 May 2026 11:10:59 +0000</pubDate>
</item>
<item>
<title>My favorite failed attempt at JS syntax sugar—TS unions via BigInt masks and proxies.</title>
<link>https://coderlegion.com/5593/my-favorite-failed-attempt-at-js-syntax-sugar-ts-unions-via-bigint-masks-and-proxies</link>
<description>&lt;h2 id=&quot;pipetype-typescript-unions-bitwise-operators-and-my-favorite-failed-experiment&quot;&gt;Pipetype: TypeScript Unions ≈ Bitwise Operators, and My Favorite Failed Experiment&lt;/h2&gt;
&lt;hr&gt;
&lt;blockquote&gt;&lt;p&gt;Note: This is an actual library: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/overthemike/pipetype&quot;&gt;https://github.com/overthemike/pipetype&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;1-a-tale-of-two-pipes-&quot;&gt;1. A Tale of Two Pipes &lt;code&gt;|&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;JavaScript is full of quirks, but few quirks are as weird and interesting as humble vertical bar: &lt;code&gt;|&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;TypeScript&lt;/strong&gt;, &lt;code&gt;|&lt;/code&gt; is the union operator:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ID = string | number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;→ “Either-or.” A value can be a string, or a number.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;JavaScript’s bitwise world&lt;/strong&gt;, &lt;code&gt;|&lt;/code&gt; flips switches:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;1  |  2  //  3

0001 | 0010  ←  `|` tells you to look at each bit of both numbers and if either are present, mark it: 1, otherwise: 0
Let's put organize them vertically to make it easier to see.

0001  ←  1
0010  ←  2
  ↓↓
0011  ←  3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;→ “Both at once.” A new number with two switches turned on.&lt;/p&gt;
&lt;p&gt;Two worlds. Same symbol. Different vibes.&lt;br&gt;
And yet… they kind of rhyme.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TypeScript unions = a value can be validated by &lt;em&gt;any of these types.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Bitwise OR = turn on &lt;em&gt;any combination of these flags.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This has all of the markings of my newest rabbit hole experiment. How much and how close could we replicate TypeScript syntax at runtime?&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;2-bigint-joins-the-party&quot;&gt;2. BigInt Joins the Party&lt;/h4&gt;
&lt;p&gt;Bitwise tricks are fun, but JavaScript numbers only give you &lt;strong&gt;53 safe bits&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That’s like having a switchboard with only 53 buttons:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  [ 1 ]  [ 2 ]  [ 3 ]  ...  [ 53 ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great for a small project. Terrible when you want an arbitrary number of unions.&lt;/p&gt;
&lt;p&gt;Enter &lt;strong&gt;BigInt&lt;/strong&gt;. No limit on bits.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  [ 1 ]  [ 2 ]  [ 3 ]  ...  [ 1,000,000+ ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Infinite lockers. Infinite switches. No more ceiling.&lt;/p&gt;
&lt;p&gt;BigInt became the foundation: every validator gets its own bit in an infinite skyline.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;3-bits-as-pointers-the-validator-map&quot;&gt;3. Bits as Pointers: The Validator Map&lt;/h4&gt;
&lt;p&gt;The whole trick works because each validator needs a &lt;strong&gt;unique bit&lt;/strong&gt; — like giving every locker in a hallway its own light switch.&lt;/p&gt;
&lt;hr&gt;
&lt;h5 id=&quot;3-1-bit-shifting-101&quot;&gt;3.1 Bit Shifting 101&lt;/h5&gt;
&lt;p&gt;We start with the number &lt;code&gt;1n&lt;/code&gt;. In binary, that looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1n = 0b0001
// '0b' is the prefix for binary
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now apply a &lt;strong&gt;left shift (&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1n &amp;lt;&amp;lt; 0n&lt;/code&gt; → don’t move it → &lt;code&gt;0001&lt;/code&gt; (still 1n)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1n &amp;lt;&amp;lt; 1n&lt;/code&gt; → move left once → &lt;code&gt;0010&lt;/code&gt; (2n)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1n &amp;lt;&amp;lt; 2n&lt;/code&gt; → move left twice → &lt;code&gt;0100&lt;/code&gt; (4n)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1n &amp;lt;&amp;lt; 3n&lt;/code&gt; → move left three times → &lt;code&gt;1000&lt;/code&gt; (8n)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each shift is multiplying by 2 — giving us the sequence of &lt;strong&gt;powers of 2&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1n, 2n, 4n, 8n, 16n, ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s why shifting is so useful here: every shift guarantees only one bit is on, so no two validators collide.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Start:  0001  (1n)

&amp;lt;&amp;lt; 1 →  0010  (2n)

&amp;lt;&amp;lt; 1 →  0100  (4n)

&amp;lt;&amp;lt; 1 →  1000  (8n)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h5 id=&quot;3-2-using-shifts-for-validators&quot;&gt;3.2 Using Shifts for Validators&lt;/h5&gt;
&lt;p&gt;This is how we assign unique “slots” for our validators:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const validators = new Map&amp;lt;bigint, (x: unknown) =&amp;gt; boolean&amp;gt;()

validators.set(1n &amp;lt;&amp;lt; 0n, (x) =&amp;gt; typeof x === &quot;string&quot;) // 0001
validators.set(1n &amp;lt;&amp;lt; 1n, (x) =&amp;gt; typeof x === &quot;number&quot;) // 0010
validators.set(1n &amp;lt;&amp;lt; 2n, (x) =&amp;gt; Array.isArray(x))      // 0100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, combining them is easy with &lt;code&gt;|&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;string | number → 0001 | 0010 = 0011 (3n)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And testing is easy with &lt;code&gt;&amp;amp;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0011 &amp;amp; 0010 = 0010 → includes &quot;number&quot;
0011 &amp;amp; 0100 = 0000 → does NOT include &quot;array&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h5 id=&quot;3-3-feels-like-math-homework&quot;&gt;3.3 Feels Like Math Homework&lt;/h5&gt;
&lt;p&gt;This works, but writing &lt;code&gt;1n &amp;lt;&amp;lt; 0n&lt;/code&gt;, &lt;code&gt;1n &amp;lt;&amp;lt; 1n&lt;/code&gt;, &lt;code&gt;1n &amp;lt;&amp;lt; 2n&lt;/code&gt; everywhere gets old fast.&lt;/p&gt;
&lt;p&gt;So, we add a helper: &lt;code&gt;getNextFlag()&lt;/code&gt; — so we can just ask for “the next available bit” instead of shifting by hand.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;let lastFlag = 0n;

function getNextFlag(): bigint {
  lastFlag = lastFlag === 0n ? 1n : lastFlag &amp;lt;&amp;lt; 1n;
  return lastFlag;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h5 id=&quot;3-4-cleaner-validator-setup&quot;&gt;3.4 Cleaner Validator Setup&lt;/h5&gt;
&lt;p&gt;Now assigning validators looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const validators = new Map&amp;lt;bigint, (x: unknown) =&amp;gt; boolean&amp;gt;();

validators.set(getNextFlag(), (x) =&amp;gt; typeof x === &quot;string&quot;) // 0001
validators.set(getNextFlag(), (x) =&amp;gt; typeof x === &quot;number&quot;) // 0010
validators.set(getNextFlag(), (x) =&amp;gt; Array.isArray(x))      // 0100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much easier to read, but you still know what’s happening under the hood: each new flag is just another &lt;strong&gt;power of 2&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;4-proxy-turning-math-into-sugar&quot;&gt;4. Proxy: Turning Math into Sugar&lt;/h4&gt;
&lt;p&gt;All of this is neat, but nobody wants to write flags all day.&lt;/p&gt;
&lt;p&gt;That’s where &lt;strong&gt;Proxy&lt;/strong&gt; shines: we intercept property access and generate flags on the fly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const Type = new Proxy({}, {
  get(_, key: string) {
    const bit = getNextFlag()
    validators.set(bit, (x) =&amp;gt; typeof x === key)
    return bit
  }
})

const myType = Type.string | Type.number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it &lt;em&gt;looks&lt;/em&gt; like TypeScript.&lt;/p&gt;
&lt;p&gt;Runtime JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// defined elswhere
const string = Type.string((val) =&amp;gt; typeof val === 'string')
const number = Type.number((val) =&amp;gt; typeof val === 'number')

// your file
import { Type, string, number } from './types'

Type.StringOrNumber = string | number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Underneath:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;0001 | 0010 → 0011
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s really just syntactic sugar. JavaScript pretending to be TypeScript.&lt;/p&gt;
&lt;p&gt;Well, it was. It's not really that useful. &lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;5-the-dream-vs-the-reality&quot;&gt;5. The Dream vs. The Reality&lt;/h4&gt;
&lt;p&gt;At this point, the experiment felt magical:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ergonomic unions at runtime.&lt;/li&gt;
&lt;li&gt;BigInt masks for infinite validators.&lt;/li&gt;
&lt;li&gt;Syntax that looked like TypeScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But then reality hit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TypeScript’s compiler can’t see through BigInt.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;From the type system’s perspective, these masks were just numbers. Opaque. Un-inferable.&lt;/p&gt;
&lt;p&gt;The magic broke. Without inference, the ergonomics collapsed.&lt;br&gt;
TypeScript couldn’t narrow. Couldn’t hint. Couldn’t help.&lt;/p&gt;
&lt;p&gt;What started as sweet sugar ended as brittle runtime math.&lt;/p&gt;
&lt;p&gt;There are ways of doing it, but they get kind of ugly. We already have fantastic and full-featured libraries like &lt;a rel=&quot;nofollow&quot; href=&quot;https://zod.dev&quot;&gt;zod&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://valibot.dev/&quot;&gt;valibot&lt;/a&gt; that bring inference for free for just a small syntax fee comparatively.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;6-my-favorite-failed-experiment&quot;&gt;6. My Favorite Failed Experiment&lt;/h4&gt;
&lt;p&gt;That’s when I had to admit it: Pipetype failed.&lt;/p&gt;
&lt;p&gt;It wasn’t the tool that would unify runtime and compile-time unions. It was a clever curiosity that buckled under TypeScript’s strict compiler gaze.&lt;/p&gt;
&lt;p&gt;But I still love it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It taught me how far &lt;code&gt;|&lt;/code&gt; can stretch.&lt;/li&gt;
&lt;li&gt;It showed me how BigInt changes the playground.&lt;/li&gt;
&lt;li&gt;It reminded me how Proxies can cosplay as syntax.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sometimes your best experiments are the ones that fail, because they teach you where the limits really are.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;appendix-deep-cuts&quot;&gt;Appendix: Deep Cuts&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bitwise as Lockers:&lt;/strong&gt; OR (&lt;code&gt;|&lt;/code&gt;) opens multiple lockers. AND (&lt;code&gt;&amp;amp;&lt;/code&gt;) checks if a locker belongs.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;0101 &amp;amp; 0001 → true  (locker 0 included)
0101 &amp;amp; 0010 → false (locker 1 not included)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BigInt for Infinite Validators:&lt;/strong&gt; Beyond 53 bits, normal numbers wobble. BigInt? Infinite switches.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Proxy for Sugar:&lt;/strong&gt; &lt;code&gt;Type.string&lt;/code&gt; wasn’t a string. It was a BigInt mask.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why It Failed:&lt;/strong&gt; No TypeScript inference. Without narrowing, runtime unions lost their edge.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt; That’s Pipetype: a mash-up of unions and bitmasks, Proxies and sugar, BigInts and dreams — and the lesson that sometimes failure is the most fun of all.&lt;/p&gt;
</description>
<category>Type Coercion</category>
<guid isPermaLink="true">https://coderlegion.com/5593/my-favorite-failed-attempt-at-js-syntax-sugar-ts-unions-via-bigint-masks-and-proxies</guid>
<pubDate>Fri, 26 Sep 2025 02:22:54 +0000</pubDate>
</item>
<item>
<title>Under the hood explanation of Immer library.</title>
<link>https://coderlegion.com/3454/under-the-hood-explanation-of-immer-library</link>
<description>&lt;blockquote&gt;&lt;p&gt;Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;— Immer Documentation&lt;/p&gt;
&lt;p&gt;Immer uses Proxies under the hood and therefore to understand the details of this library we need to know a little about proxies. So..&lt;/p&gt;
&lt;p&gt;What is a Proxy? Let’s refer to javascript.info&lt;/p&gt;
&lt;p&gt;A Proxy object wraps another object and intercepts operations, like reading/writing properties and others&lt;/p&gt;
&lt;p&gt;The syntax to create a Proxy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let proxy = new Proxy(target, objectTrap)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice in the above snippet I have introduced a term called objectTrap. We need to understand it because it is one of the key ideas used by the library to do its deeds. So..&lt;/p&gt;
&lt;p&gt;Let’s google what does a object trap in proxy do?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In the context of JavaScript Proxies, a “trap” refers to a handler function that intercepts and modifies how specific operations are performed on the target object.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;An example to understand how exactly this works.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; let user = {
  name: &quot;John&quot;,
  _password: &quot;***&quot;
};
user = new Proxy(user, {
  get(target, prop) {
    if (prop.startsWith('_')) {
      throw new Error(&quot;Access denied&quot;);
    }
    return target[prop];
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above snippet, user is born as an object but is eventually christened into a proxy with an objectTrap that has a get function defined on it. Now, when we call user[“_password”], the get method inside the objectTrap will be triggered and give us an error. I hope you all get the basic idea of proxy.&lt;/p&gt;
&lt;p&gt;Now, let’s look at the relevant objectTrap code in the library:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const objectTraps = {
    get(target, prop) {
      if (prop === isProxySymbol) return target;
      return createProxy(target)[prop];
    },
    set(target, prop, value) {
      const current = createProxy(target)[prop];
      const newValue = createProxy(value);
      if (current !== newValue) {
        const copy = getOrCreateCopy(target);
        copy[prop] = isProxy(newValue) ? newValue[isProxySymbol] : newValue;
      }
      return true;
    }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For now, all that we must understand is that the above objectTrap is overriding reading and writing of object properties via the get and set methods and these methods are purely working with proxies rather than the direct objects which we provide to the library. Now, it is time to look at an example code which uses immer to mutate an object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const baseState = {
  name: &quot;John&quot;,
  age: 20,
  address: {
    city: &quot;New York&quot;,
  },
};

const thunk = (draft) =&amp;gt; {
  draft.name = &quot;Jane&quot;;
  draft.address.city = &quot;Los Angeles&quot;;
  draft.newKey = &quot;newKey&quot;;
};

const newState = immer(baseState, thunk);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, let’s try to understand the above code which uses Immer to mutate an object.&lt;/p&gt;
&lt;p&gt;Here, we are trying to update the name and city which is a property inside address and add a new property called newKey. Notice that the callback provided to the immer function directly mutates the draft object. This is the power of the library-it allows us to update the object directly, without having to create a copy as we typically do when updating a React state object.&lt;/p&gt;
&lt;p&gt;Let’s now dig into the immer function.&lt;/p&gt;
&lt;p&gt;The immer function first creates a proxy object from the given baseState and here is the library code that does that:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const rootClone = createProxy(baseState);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;let’s look at the implementation of createProxy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function createProxy(base) {
    if (isPlainObject(base) || Array.isArray(base)) {
      if (isProxy(base)) return base; // avoid double wrapping
      if (proxies.has(base)) return proxies.get(base);
      const proxy = new Proxy(base, objectTraps);
      proxies.set(base, proxy);
      return proxy;
    }
    return base;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, createProxy creates a proxy for the base state and adds it to a private map called proxies. This is used by the library to track all the proxies that have been created.&lt;/p&gt;
&lt;p&gt;After createProxy the library invokes the thunk function like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;thunk(rootClone);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, what is happening?&lt;/p&gt;
&lt;p&gt;rootClone, which is a proxy, is passed to the callback we provided to the Immer function. For now, it may not be clear what is happening, so let's look at the last function that Immer calls and then come back here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return finalize(baseState);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The library is invoking the final function with baseState which is confusing. At this point, I had the following question in my mind:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;How does it track all the changes made to the proxy and how does it&lt;br&gt;
merge with the baseState?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Its time, let’s take a look at what happens when we invoke the thunk with the proxy called rootClone&lt;/p&gt;
&lt;p&gt;Take a look at the thunk again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const thunk = (draft) =&amp;gt; {
  draft.name = &quot;Jane&quot;;
  draft.address.city = &quot;Los Angeles&quot;;
  draft.newKey = &quot;newKey&quot;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, the draft object that the library passes to the thunk is a proxy. We also know that when we access or assign a property on the proxy, the object trap is invoked. For example, in draft.name = &quot;Jane&quot;;, we are assigning a property, so the set trap is triggered. Let’s take another look at the set trap:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set(target, prop, value) {
      const current = createProxy(target)[prop];
      const newValue = createProxy(value);
      if (current !== newValue) {
        const copy = getOrCreateCopy(target);
        copy[prop] = isProxy(newValue) ? newValue[isProxySymbol] : newValue;
      }
      return true;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For draft.name = &quot;Jane&quot;; let’s log the values of target, prop, value.&lt;/p&gt;
&lt;p&gt;console.logs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;target { name: 'John', age: 20, address: { city: 'New York' } }
prop name
value Jane
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s walk through the code of set trap. First, it creates a proxy for the target object and looks up its name property and then assign it to current and then creates a proxy for value and assign it to newValue&lt;/p&gt;
&lt;p&gt;If current and newValue are different it invokes getOrCreateCopy on target and assign it to copy. So let’s stop here and dig a little deeper on the implementation details of the function getOrCreateCopy&lt;/p&gt;
&lt;p&gt;Implementation of getOrCreateCopy in the library:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function getOrCreateCopy(base) {
    let copy = copies.get(base);
    if (!copy) {
      copy = Array.isArray(base) ? base.slice() : Object.assign({}, base);
      copies.set(base, copy);
    }
    return copy;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice, the copies map. copies along with proxies keeps track of the changes made to the baseState.&lt;/p&gt;
&lt;p&gt;The above function is straightforward: if base is not found in copies, a copy of that object is made and copies is updated.&lt;/p&gt;
&lt;p&gt;Now, let’s go back to set trap. When current and newValue is different it creates a copy for that target by invoking getOrCreateCopy function and updates the given prop value of that copy with the newValue and returns true.&lt;/p&gt;
&lt;p&gt;So what have we learnt till now. Let’s summarise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;immer invokes the thunk by passing it a proxy. &lt;/li&gt;
&lt;li&gt;whenever a proxy is created the proxies map is updated accordingly. &lt;/li&gt;
&lt;li&gt;when we try to get or set any property on the proxy, it is intercepted by the corresponding&lt;br&gt;
trap functions, which update the copies map accordingly. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, let’s simplify this ongoing agony and assume that the thunk has completed its execution and therefore the proxies map and copies map are updated accordingly.&lt;/p&gt;
&lt;p&gt;Let’s log the final proxies after the thunk gets executed:&lt;/p&gt;
&lt;p&gt;Let’s log the final proxies after the thunk gets executed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map(2) {
  { name: 'John', age: 20, address: { city: 'New York' } } =&amp;gt; { name: 'John', age: 20, address: { city: 'New York' } },
  { city: 'New York' } =&amp;gt; { city: 'New York' }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, Let’s log the final copies&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map(2) {
  { name: 'John', age: 20, address: { city: 'New York' } } =&amp;gt; {
    name: 'Jane',
    age: 20,
    address: { city: 'Los Angeles' },
    newKey: 'newKey'
  },
  { city: 'New York' } =&amp;gt; { city: 'Los Angeles' }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let’s again go back to the final function call in the immer function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return finalize(baseState);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Implementation of finalize:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function finalize(thing) {
    if (!hasChanges(thing)) return thing;
    const copy = getOrCreateCopy(thing);
    Object.keys(copy).forEach((prop) =&amp;gt; {
      copy[prop] = finalize(copy[prop]);
    });
    return copy;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Implementation of hasChanges:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function hasChanges(base) {
    const proxy = proxies.get(base);
    if (!proxy) return false; // nobody did read this object
    if (copies.has(base)) return true; // a copy was created, so there are changes
    // look deeper
    const keys = Object.keys(base);
    for (let i = 0; i &amp;lt; keys.length; i++) {
      const value = base[keys[i]];
      if (isPlainObject(value) &amp;amp;&amp;amp; hasChanges(value)) return true;
    }
    return false;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we meet recursion. So, in simple words finalize checks if there is a change in the given object and peaks into copies and return the appropriate value by recursively walking through the copy object.&lt;/p&gt;
&lt;p&gt;Just read through the implementation of finalize and hasChanges, it’s easy to see how they use proxies and copies to reconstruct the given baseState with its updated parts and return it to the user.&lt;/p&gt;
&lt;p&gt;That is all for now. This is a hobby blogpost to document by diggings into the source code of various libraries that I have used or come to admire. At the current amount I am trying to understand fixi.js and preact/signals. I hope that I would be able to write a more clear blogpost on these libraries in the future.&lt;/p&gt;
&lt;p&gt;Thanks for reading and for being patient. I’m open to any feedback!&lt;/p&gt;
</description>
<category>Functions</category>
<guid isPermaLink="true">https://coderlegion.com/3454/under-the-hood-explanation-of-immer-library</guid>
<pubDate>Tue, 24 Jun 2025 15:26:14 +0000</pubDate>
</item>
</channel>
</rss>