<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged selfhosted</title>
<link>https://coderlegion.com/tag/selfhosted</link>
<description>Powered by Question2Answer</description>
<item>
<title>Why I Protect Only Some Homelab Services With a WAF</title>
<link>https://coderlegion.com/32229/why-i-protect-only-some-homelab-services-with-a-waf</link>
<description>&lt;p&gt;A public hostname changes what a homelab service is. A notes app, a media index, or an admin panel that answers from outside the house is no longer a LAN convenience. It is a web application on the internet, and it can be probed for the same injection, traversal, and abuse patterns aimed at any other site. I place a self-hosted WAF in front of those services when, and only when, I can publish them as HTTP or HTTPS through a reverse proxy. I do not treat that choice as a blanket rule for every container on the network.&lt;/p&gt;
&lt;p&gt;SafeLine is a self-hosted web application firewall meant to protect web apps by filtering and monitoring HTTP traffic between the application and the internet. Deployed in front of the app, it works as a reverse proxy: clients pass through it before they reach the server, and it blocks malicious HTTP and HTTPS traffic while forwarding what its policies treat as safe. The same description says it also aims to prevent unauthorized data from leaving the app. Those statements are the product model I rely on, and they come from the project documentation 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;p&gt;The attack list is specific enough to use as a decision filter. The introduction names 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. Core capabilities listed alongside that coverage are defenses for web attacks, proactive bot-abuse defense, HTML and JS code encryption, IP-based rate limiting, and a web access control list. Rate limiting throttles traffic above defined limits to defend against DoS attacks, brute-force attempts, traffic surges, and other abuse. A CAPTCHA challenge is documented as allowing human users while blocking crawlers and bots. An authentication challenge blocks visitors who do not enter the required password. Dynamic protection, when turned on, encrypts HTML and JS from the web server on each visit. I cite that feature set from &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; rather than assuming extra homelab plugins.&lt;/p&gt;
&lt;p&gt;That scope also tells me what not to expect. The configuration guide says SafeLine is developed on nginx and acts as an HTTP and HTTPS reverse proxy: it receives traffic for the original site, cleans malicious traffic, and forwards the rest to the upstream application, as described 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;. A database port or an SSH listener is not that kind of application. Putting a WAF hostname in front of them is not a documented protection path, so I leave them off this design.&lt;/p&gt;
&lt;p&gt;Before I move a self-hosted service, I run a short go or no-go list.&lt;/p&gt;
&lt;p&gt;The app must be reachable as a web origin. In the console, Add Application asks for a domain, hostname, or IP, a listen port such as 80 or 443, and an upstream address. HTTPS apps need the SSL option checked. After saving, the domain must resolve to the IP of the SafeLine server. If I cannot make that DNS change, I do not pretend the app is protected.&lt;/p&gt;
&lt;p&gt;The host must meet the install floor in &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 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 of memory, and 5 GB of disk. The CPU must support ssse3. I confirm those facts with the documented commands: uname -m, docker version, docker compose version, cat /proc/cpuinfo | grep &quot;processor&quot;, free -h, df -h, and lscpu | grep ssse3. A homelab node that fails any line is not a candidate, even if the web app itself is small.&lt;/p&gt;
&lt;p&gt;Architecture has a license constraint I do not skip. For ARM, the guide sets ARCH_SUFFIX to -arm and uses the ARM Postgres image. It also states that SafeLine on ARM requires a Pro license to work properly, and that the Personal Edition is not supported on ARM. An ARM box can look ideal for a quiet homelab and still be the wrong edition.&lt;/p&gt;
&lt;p&gt;Release choice is part of the same checklist. Setting RELEASE to -lts selects the LTS build, but the deploy guide says the LTS version will no longer be maintained starting from 9.1.0-LTS on 14 August 2025, and it strongly recommends upgrading to the latest version. I stay on the current release unless I have a concrete reason not to.&lt;/p&gt;
&lt;p&gt;The recommended install is the automated English command from that same deploy page, and it needs root: bash -c &quot;$(curl -fsSLk &lt;a rel=&quot;nofollow&quot; href=&quot;https://waf.chaitin.com/release/latest/manager.sh&quot;&gt;https://waf.chaitin.com/release/latest/manager.sh&lt;/a&gt;)&quot; -- --en. Manual setup is also documented: create /data/safeline with at least 5 GB free, download the compose file, write .env, generate a 64-character hex detector management token, a 64-character hex management internal token, and a 16-character alphanumeric detector AES key, lock down permissions, then start with docker compose up -d. The console opens 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 comes from docker exec safeline-mgt resetadmin, and the printed username and password have to be saved then. The deploy page remains the source for SAFELINE_DIR, IMAGE_TAG, MGT_PORT, POSTGRES_PASSWORD, SUBNET_PREFIX, and the remaining variables.&lt;/p&gt;
&lt;p&gt;Once the console is up, I add one application, point DNS at the SafeLine host, and test with the sample requests in the application guide: a SQL injection query string, an XSS payload, a path traversal payload, a code injection payload, and an XXE payload, with my domain in place of the example host. A blocking page means the request was stopped. I then open the attack list and click detail so the event is confirmed in the console, not only in the browser.&lt;/p&gt;
&lt;p&gt;Published evaluation numbers are a policy warning, not a promise about my apps. On 33,669 samples, &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; reports SafeLine Balance at 71.65 percent detection, 0.07 percent false positives, and 99.45 percent accuracy, and SafeLine Strict at 76.17 percent detection, 0.22 percent false positives, and 99.38 percent accuracy. Strict handling detects more and also raises the false-positive figure. After I enable stricter handling, I retest ordinary actions such as login and upload before I call the site done. The docs call the product production-ready; I still watch the first real clients.&lt;/p&gt;
&lt;p&gt;I also keep the management plane boring. MGT_PORT defaults to 9443 in the sample environment, and MGT_PROXY is only for extra proxy layers in front of the console. It should stay at 0 unless I am actually configuring that proxy. If I retire the install, the documented path is to enter the SafeLine directory, run docker compose down, and remove that directory. Community support is Discord, including the #FAQ channel, plus GitHub issues, as noted 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;p&gt;The decision is narrow. Use this WAF when a self-hosted web service must be reached from outside, when DNS can target the reverse proxy, and when the host matches the documented platform rules. Do not use it as a reason to publish services that should stay private, and do not describe it as an integration with a specific tunnel, panel, or orchestrator. The supported path is the one in the application guide: domain, port, upstream, and a domain that resolves to SafeLine.&lt;/p&gt;
&lt;h4 id=&quot;which-self-hosted-services-should-sit-behind-a-waf-&quot;&gt;Which self-hosted services should sit behind a WAF?&lt;/h4&gt;
&lt;p&gt;Only web apps you can publish as HTTP or HTTPS. SafeLine receives traffic for the original site, cleans malicious requests, and forwards the rest to the upstream, which is the model in &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;. Non-web listeners are outside that guide.&lt;/p&gt;
&lt;h4 id=&quot;is-a-small-homelab-host-enough-&quot;&gt;Is a small homelab host enough?&lt;/h4&gt;
&lt;p&gt;The documented minimum is 1 CPU core, 1 GB of memory, and 5 GB of disk, on Linux with Docker 20.10.14 or newer, Docker Compose 2.0.0 or newer, and a CPU with ssse3, per &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;. ARM also requires a Pro license. The Personal Edition is not supported on ARM.&lt;/p&gt;
&lt;h4 id=&quot;what-do-i-enter-for-one-public-site-&quot;&gt;What do I enter for one public site?&lt;/h4&gt;
&lt;p&gt;Add an application with the domain, hostname, or IP, the listen port, and the upstream address. Check SSL for HTTPS. Resolve that domain to the SafeLine server IP, as described 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;. Rate limiting, CAPTCHA, authentication challenge, and dynamic HTML or JS encryption are separate controls from &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;h4 id=&quot;how-can-i-verify-that-a-probe-was-blocked-&quot;&gt;How can I verify that a probe was blocked?&lt;/h4&gt;
&lt;p&gt;Send the documented SQL injection, XSS, path traversal, code injection, and XXE examples to your own domain. A blocking page means the defense fired. Open the attack list and click detail to confirm the record.&lt;/p&gt;
&lt;h4 id=&quot;does-this-replace-private-networking-or-app-login-&quot;&gt;Does this replace private networking or app login?&lt;/h4&gt;
&lt;p&gt;No. It filters traffic for web apps you choose to expose. It does not patch the upstream or justify publishing a service that should remain private. If you remove the install, use docker compose down and delete the install directory, following &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;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/32229/why-i-protect-only-some-homelab-services-with-a-waf</guid>
<pubDate>Sat, 24 Oct 2026 02:25:33 +0000</pubDate>
</item>
<item>
<title>How to Choose a WAF for a Homelab Before You Publish Anything</title>
<link>https://coderlegion.com/32228/how-to-choose-a-waf-for-a-homelab-before-you-publish-anything</link>
<description>&lt;p&gt;A homelab rarely fails in one dramatic way. It fails when a useful web app is reachable, a password form is guessable, and nobody has decided which requests are allowed to touch the origin. A WAF can help, but only if you treat it as a reverse proxy with a defined job, not as a label you place on every container.&lt;/p&gt;
&lt;p&gt;SafeLine is documented as a self-hosted WAF that protects web apps by filtering and monitoring HTTP traffic between a web application and the Internet. Deployed in front of an app, it is a reverse proxy: clients reach the WAF first, and the WAF forwards traffic it considers safe to the origin while blocking malicious HTTP and HTTPS requests and unauthorized data leaving the app. That model is the whole decision. If a self-hosted service is not an HTTP or HTTPS application you can place behind that proxy, this checklist should stop you from promising protection the product docs do not describe. 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;h3 id=&quot;sort-services-before-you-sort-controls&quot;&gt;Sort services before you sort controls&lt;/h3&gt;
&lt;p&gt;Write down every service you want to protect and mark only those that speak HTTP or HTTPS. A photo library, a notes site, a dashboard, or a small API can belong on the list when you can name a domain, hostname, or IP, a listen port, and an upstream address. A database port, a raw game server, or a protocol that never becomes an HTTP request does not become a WAF application just because it runs on the same host.&lt;/p&gt;
&lt;p&gt;The official application flow is concrete. In the Web Admin Console, open Applications and choose Add Application. Enter the original app domain, hostname, or IP. Enter the port SafeLine will listen on, such as 80 or 443, and check the SSL option for HTTPS apps. Enter the upstream, which is the real address used to forward traffic. After that, resolve the name you entered to the IP of the server where SafeLine runs, then reach the protected app through that name. If you cannot complete those four facts, the service is not ready for this path. 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;Keep the origin from being a shortcut. The value of the proxy is that clients pass through it before they reach the server. If the same app is still published on a second port, a second hostname, or a direct LAN address that bypasses the WAF, the checklist is unfinished even if the console shows a healthy application.&lt;/p&gt;
&lt;h3 id=&quot;match-documented-threats-to-homelab-exposure&quot;&gt;Match documented threats to homelab exposure&lt;/h3&gt;
&lt;p&gt;The product documentation names a wide set of web attacks, including 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. Core capabilities listed alongside that coverage are web-attack defense, proactive bot-abuse defense, HTML and JS code encryption, IP-based rate limiting, and a web access control list. 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;For a homelab, translate those names into exposure, not into a feature tour. A form or query string that reaches a database-backed app is a reason to care about injection and path traversal. A login page on a name that resolves from outside the house is a reason to care about brute force. A site that suddenly attracts scripted clients is a reason to care about bots and floods. An app you only use over a trusted VPN may still deserve the proxy if the origin would be dangerous when that VPN rule is wrong, but the checklist should say so explicitly.&lt;/p&gt;
&lt;p&gt;Do not invent a connector for a particular self-hosted brand. The supplied docs describe a generic reverse-proxy application. They do not document a special integration for any homelab suite. If an app needs a custom header, a long-lived connection, or an existing proxy in front of it, test that behavior yourself and treat anything beyond domain, port, upstream, and DNS as unverified.&lt;/p&gt;
&lt;h3 id=&quot;pick-controls-by-failure-mode&quot;&gt;Pick controls by failure mode&lt;/h3&gt;
&lt;p&gt;Blocking web attacks is the baseline. The feature list says SafeLine defends against web attacks such as SQL injection, XSS, code injection, OS command injection, CRLF injection, XXE, SSRF, and path traversal. Rate limiting is separate. The docs describe it as a way to throttle traffic that exceeds defined limits, aimed at DoS attacks, brute-force attempts, traffic surges, and other abuse. A CAPTCHA challenge is for bot attacks: human users are allowed through, while crawlers and bots are blocked. An authentication challenge is a password gate: when it is on, visitors must enter the password or they are blocked. Dynamic protection is different again: when it is on, HTML and JS from the web server are dynamically encrypted on each visit. 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;A practical homelab mapping looks like this. Use attack blocking for any app whose parameters, uploads, or paths are reachable. Add rate limiting where login, search, or API routes can be hammered. Consider CAPTCHA where anonymous bots, not forgotten passwords, are the problem. Use the authentication challenge only when a shared password gate is acceptable for every visitor of that application, because it will block people who do not have that password. Turn on dynamic protection when you specifically want HTML and JS encrypted per visit, and verify that your own pages still work. None of these toggles replaces patching the origin app.&lt;/p&gt;
&lt;p&gt;Published evaluation numbers are a tuning warning, not a score you should paste onto your hardware. On 33669 samples, the docs report SafeLine Balance at 71.65 percent detection, 0.07 percent false positives, and 99.45 percent accuracy, and SafeLine Strict at 76.17 percent detection, 0.22 percent false positives, and 99.38 percent accuracy. Strict raises detection and also raises the false-positive rate compared with Balance. For a homelab, that means you should watch the attack list after you change policy, especially if household tools start failing on ordinary requests. 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;h3 id=&quot;confirm-the-host-can-carry-the-proxy&quot;&gt;Confirm the host can carry the proxy&lt;/h3&gt;
&lt;p&gt;The deploy guide states minimums: Linux; x86_64 or arm64; Docker 20.10.14 or above; Docker Compose 2.0.0 or above; 1 CPU core, 1 GB memory, and 5 GB disk; and a CPU with SSSE3. Documented checks include uname -m, docker version, docker compose version, processor count, free -h, df -h, and lscpu | grep ssse3. A small lab box can meet the minimum and still feel tight once logs, database data, and several proxied apps share that 1 GB. Plan disk beyond the 5 GB floor if you expect to keep attack history.&lt;/p&gt;
&lt;p&gt;ARM needs an extra decision. The deploy guide says SafeLine installed on ARM requires a Pro license to work properly, and that the Personal Edition is not supported on ARM. An arm64 homelab board is therefore not the same choice as an x86_64 mini PC. If you are looking at the LTS channel, note that LTS is no longer maintained starting from 9.1.0-LTS (14 August 2025), and the docs strongly recommend upgrading to the latest version. 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;The console itself is part of the exposure review. After install, the web console is &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 admin account is retrieved with docker exec safeline-mgt resetadmin. Treat that management port as a privileged surface: it is how you add applications and read attack detail, so it should not be casually published beside the apps you are trying to protect.&lt;/p&gt;
&lt;h3 id=&quot;prove-the-path-with-the-documented-tests&quot;&gt;Prove the path with the documented tests&lt;/h3&gt;
&lt;p&gt;After DNS points at the SafeLine host, use the official test cases with your own domain in place of the example host. The docs give SQL injection as /?id=1+and+1=2+union+select+1, XSS as /?id=&amp;lt;img+src=x+onerror=alert()&amp;gt;, path traversal as /?id=../../../../etc/passwd, code injection as /?id=phpinfo();system('id'), and an XXE-style query. A blocking page means the attack was defended. Then open the console attack list and click detail so you can see what was recorded, not only what the browser showed. 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;Repeat one normal visit after each test. A homelab WAF that blocks the sample attacks and also blocks your own bookmark is not finished. The docs state that SafeLine is production-ready, but that statement does not mean every policy is correct for your apps. Your proof is the proxy path, the block page, the attack detail, and a clean legitimate request.&lt;/p&gt;
&lt;h4 id=&quot;does-a-homelab-waf-cover-every-self-hosted-service-&quot;&gt;Does a homelab WAF cover every self-hosted service?&lt;/h4&gt;
&lt;p&gt;No. The documented role is an HTTP and HTTPS reverse proxy in front of a web application. Services that you cannot describe with a domain, hostname, or IP, a listen port, and an upstream should stay outside this design until you have a real web path for them.&lt;/p&gt;
&lt;h4 id=&quot;which-homelab-host-facts-are-actually-required-&quot;&gt;Which homelab host facts are actually required?&lt;/h4&gt;
&lt;p&gt;The deploy guide requires Linux on x86_64 or arm64, Docker 20.10.14 or newer, Docker Compose 2.0.0 or newer, at least 1 core, 1 GB of memory, 5 GB of disk, and SSSE3. ARM installs need a Pro license; the Personal Edition is not supported on ARM.&lt;/p&gt;
&lt;h4 id=&quot;should-i-enable-every-challenge-on-day-one-&quot;&gt;Should I enable every challenge on day one?&lt;/h4&gt;
&lt;p&gt;Not by default. Rate limiting targets excess traffic, brute force, surges, and abuse. CAPTCHA targets bots. The authentication challenge blocks visitors who do not enter its password. Dynamic protection encrypts HTML and JS on each visit. Enable the control that matches the failure you are seeing, then retest a normal session.&lt;/p&gt;
&lt;h4 id=&quot;how-do-i-know-the-waf-not-another-hop-blocked-the-request-&quot;&gt;How do I know the WAF, not another hop, blocked the request?&lt;/h4&gt;
&lt;p&gt;Use the documented attack URLs against the name that resolves to the SafeLine server. A blocking page is the first sign. The console attack list and its detail view are the second. If the origin is still reachable on another address, fix that bypass before you trust the result.&lt;/p&gt;
&lt;h4 id=&quot;what-should-i-leave-off-this-checklist-&quot;&gt;What should I leave off this checklist?&lt;/h4&gt;
&lt;p&gt;Leave off claims the sources do not make: special integrations for named homelab apps, extra protocols, pricing, and any promise that a minimum lab host will behave like a large deployment. Also leave the management console unpublished to the same audience as the apps, and prefer a maintained release over the unmaintained LTS line if you are choosing a version now.&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/32228/how-to-choose-a-waf-for-a-homelab-before-you-publish-anything</guid>
<pubDate>Sat, 24 Oct 2026 02:25:01 +0000</pubDate>
</item>
<item>
<title>Open Source vs. Proprietary: Why We Built Parts of AnimeArray with Open-Source Tools</title>
<link>https://coderlegion.com/31541/open-source-vs-proprietary-why-we-built-parts-of-animearray-with-open-source-tools</link>
<description>&lt;p&gt;There's a question we get every time someone finds the site for the first time. It usually arrives about ten seconds after they realise AnimeArray is free:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;So who's paying for all this? What's the catch?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It's a fair question, and for a while I didn't have a good answer beyond &quot;advertising covers the hosting.&quot; That was true but it was the boring half of the story. The interesting half is why we built most of what runs the site ourselves, when we could have assembled the same product out of almost entirely commercial services and shipped it in a fraction of the time.&lt;/p&gt;
&lt;p&gt;I've been chewing on that question for long enough that I figured the answer was worth writing down properly — including the parts where we made the wrong call.&lt;/p&gt;
&lt;h3 id=&quot;what-owning-it-actually-got-us&quot;&gt;What &quot;owning it&quot; actually got us&lt;/h3&gt;
&lt;p&gt;The first thing you get is the ability to read the code. Not documentation &lt;em&gt;about&lt;/em&gt; it — the code.&lt;/p&gt;
&lt;p&gt;This sounds obvious once you say it, but I only appreciated it properly during an incident a few months in. Something in the request-handling layer started throwing intermittently. Not consistently enough to be obvious, not rarely enough to ignore. I lost a couple of hours reading the source of the component that was misbehaving, found the logic error, and fixed it myself.&lt;/p&gt;
&lt;p&gt;The alternative was a support ticket with a stack trace I didn't fully understand, waiting on a response from someone who would need my description of the problem to even start investigating. That's not a criticism of vendors — it's just a real difference in how long the problem takes to die. On a small project, an hour versus a week is the whole ballgame.&lt;/p&gt;
&lt;p&gt;The second thing is exit cost, and this is the one I underweighted for a long time.&lt;/p&gt;
&lt;p&gt;Every proprietary tool in a stack is a dependency you don't control. Pricing changes. Features get deprecated. APIs shift under you. The vendor pivots toward a different market. Individually these are survivable. Stacked across a dozen tools, they add up to something you can no longer actually move, even if every individual part is replaceable on paper.&lt;/p&gt;
&lt;p&gt;The reason we care is specific: the expensive, hard-won parts of what we built — the recommendation logic that understands what you actually watched, the systems that keep twelve characters sounding like twelve different people — those live in our code, not inside somebody else's product. If we changed direction tomorrow, we'd carry that work with us. That was deliberate, even if I didn't have this vocabulary for it at the time.&lt;/p&gt;
&lt;p&gt;The third is predictable cost, which sounds boring until you have to present a budget.&lt;/p&gt;
&lt;p&gt;Open source tooling isn't free. It's labour and hardware, both of which you can see coming and forecast. What it avoids is per-seat licences and metered APIs that scale unpredictably and tend to punish you precisely when you start succeeding — which is a genuinely unpleasant property to own.&lt;/p&gt;
&lt;p&gt;And the fourth is privacy, though I want to frame it carefully. It's not that open source is more private by some moral property. It's structural. When you run the software, the data stays where you put it. You don't need to publish a policy about what you &lt;em&gt;won't&lt;/em&gt; collect, because there's no third party standing in the path to collect it.&lt;/p&gt;
&lt;h3 id=&quot;the-part-nobody-wants-to-hear&quot;&gt;The part nobody wants to hear&lt;/h3&gt;
&lt;p&gt;Open source is not free, and &quot;we built it ourselves&quot; is not a synonym for &quot;we did nothing for it.&quot;&lt;/p&gt;
&lt;p&gt;Some of the most valuable software in our stack was donated by someone, and I'm grateful for it every day. But the hours we spent configuring, debugging, updating, monitoring and repairing it are absolutely real, and they come out of the same revenue that has to cover hosting and bandwidth. On a small team that's the largest cost we carry, and it's invisible if you only look at the licensing line and conclude we're saving money.&lt;/p&gt;
&lt;p&gt;We own the maintenance. Every dependency is something we chose to run, which means somebody is responsible for watching it, updating it, and dealing with the moment an upstream release breaks something we rely on. A company selling commercial software does that work as part of the price. We do it as part of the job. If you're building something small and reading this thinking it's a free shortcut, that's the misunderstanding I most want to correct.&lt;/p&gt;
&lt;p&gt;There's a version of this that only works at a certain ratio. If our traffic grew a hundredfold, we'd need to make completely different calls — probably more managed services, more outsourced operations, and a much smaller independent stack. We don't pretend the current approach scales forever. We think it's honest about what it costs and right for where we are today, and those are different questions.&lt;/p&gt;
&lt;h3 id=&quot;where-we-deliberately-chose-proprietary&quot;&gt;Where we deliberately chose proprietary&lt;/h3&gt;
&lt;p&gt;I'm not going to pretend open source wins every round, because it doesn't, and an article that only celebrates its own decisions is an advertisement.&lt;/p&gt;
&lt;p&gt;We use paid tools in a few categories, and I'd make the same call again:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Things where a support contract is worth more than the licence.&lt;/strong&gt; When a problem has a clear escalation path and a known owner, it gets solved faster than anything we could diagnose ourselves. That's not a bad thing to buy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Services with no credible open equivalent&lt;/strong&gt; at the quality level we need. Rebuilding a search index or a video pipeline in order to avoid a subscription isn't virtue, it's waste. Not everything important is a matter of principle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anything where our own time is the scarcest resource&lt;/strong&gt; and licensing it is genuinely cheaper than building it. This one is easy to get wrong because founders tend to over-value building. Sometimes building is the right call and it's satisfying. Sometimes it's ego with a maintenance bill attached.&lt;/p&gt;
&lt;p&gt;The other thing worth saying: we don't treat open source as a purity test. A permissive licence is legal permission, not a guarantee of quality, security, or maintenance. Popularity on a package registry tells you how many people use something. It does not tell you whether anybody is looking after it.&lt;/p&gt;
&lt;h3 id=&quot;the-four-questions-we-ask&quot;&gt;The four questions we ask&lt;/h3&gt;
&lt;p&gt;When a new tool comes up, we run it through a checklist. It's short on purpose, because a long checklist doesn't get used.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Can we read it?&lt;/strong&gt; If we can't inspect what we're running, we can't honestly reason about whether it belongs anywhere near a stack that handles user accounts. This is a threshold question — a tool that fails it usually doesn't get a second conversation, regardless of price.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What's the exit?&lt;/strong&gt; If this vanished tomorrow, how long would it take to replace it? High exit cost on something load-bearing is a decision we make deliberately, or not at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who pays when it breaks?&lt;/strong&gt; If the honest answer is &quot;we do&quot; and we're not in a position to staff that, we shouldn't choose it. No amount of being right about the long term compensates for a small team quietly becoming the on-call rotation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Does it compound?&lt;/strong&gt; Does owning this make the next thing easier to build, or does it create a brand new category of problem? Tools that make later work faster are worth more than tools that are marginally better today.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The real output of this isn't a score. It's that it forces us to be honest about which category a decision falls into, which is where most bad choices actually get made — in the gap between &quot;it's free&quot; and &quot;we can maintain it.&quot;&lt;/p&gt;
&lt;h3 id=&quot;what-this-actually-means-for-the-people-who-use-the-site&quot;&gt;What this actually means for the people who use the site&lt;/h3&gt;
&lt;p&gt;This isn't infrastructure trivia. It shows up in things people notice.&lt;/p&gt;
&lt;p&gt;Because we own the software, we can promise the things that matter and keep them. Everything stays free and usable without an account, because there's no per-user cost to pass on — you can try &lt;a rel=&quot;nofollow&quot; href=&quot;https://animearray.site/&quot;&gt;AnimeArray&lt;/a&gt; for as long as you like and never be asked for a card.&lt;/p&gt;
&lt;p&gt;It also means we can be straight about what the site is and isn't. It's an independent fan project. It hosts no video. It isn't affiliated with, endorsed by, or connected to any studio, publisher, or licensor. There's no commercial arrangement making any of that awkward to say, and I'd rather be boringly accurate than vaguely impressive.&lt;/p&gt;
&lt;p&gt;And it means we can fix things without asking anyone's permission. When something wasn't working well — and things have, repeatedly — we changed it. Nobody had to approve a roadmap.&lt;/p&gt;
&lt;p&gt;If you want to see how this reads in practice, the &lt;a rel=&quot;nofollow&quot; href=&quot;https://roleplay.animearray.site/&quot;&gt;character chats&lt;/a&gt; are the part I'm proudest of, mostly because keeping twelve distinct voices distinct is much harder than it sounds and much more satisfying than I expected. The &lt;a rel=&quot;nofollow&quot; href=&quot;https://otaku.animearray.site/&quot;&gt;Otaku AI assistant&lt;/a&gt; is the other one, and it exists because we kept wanting a thing that didn't exist.&lt;/p&gt;
&lt;h3 id=&quot;if-you-re-starting-something-similar&quot;&gt;If you're starting something similar&lt;/h3&gt;
&lt;p&gt;The question isn't open source versus proprietary. Anyone who frames it that way has already decided and is looking for permission.&lt;/p&gt;
&lt;p&gt;The question is: &lt;strong&gt;do you want to own your dependencies, and are you prepared to pay for that honestly?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If yes, the tooling is the easy part. You'll find the shape of your stack follows fairly quickly from there.&lt;/p&gt;
&lt;p&gt;If no — and that's a completely legitimate answer for many projects — you should lean toward managed services, accept the lock-in consciously, and spend the time you saved on the part of the product that only you can build.&lt;/p&gt;
&lt;p&gt;The mistake I'd avoid is picking one and then resenting it later. Either position is defensible. Being unable to afford the one you chose is not.&lt;/p&gt;
&lt;p&gt;AnimeArray is at &lt;a rel=&quot;nofollow&quot; href=&quot;https://animearray.site/&quot;&gt;animearray.site&lt;/a&gt; if you want to see what the outcome looks like. It's free, it needs no account, and every decision I described above is visible in the finished product — including the compromises.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31541/open-source-vs-proprietary-why-we-built-parts-of-animearray-with-open-source-tools</guid>
<pubDate>Sat, 17 Oct 2026 16:56:37 +0000</pubDate>
</item>
<item>
<title>Reverse Proxy or Transparent WAF? A Checklist for Web Teams</title>
<link>https://coderlegion.com/31302/reverse-proxy-or-transparent-waf-a-checklist-for-web-teams</link>
<description>&lt;h2 id=&quot;reverse-proxy-or-transparent-waf-a-checklist-for-web-teams&quot;&gt;Reverse Proxy or Transparent WAF? A Checklist for Web Teams&lt;/h2&gt;
&lt;p&gt;Ask five questions before deployment: Can the origin be restricted? Who terminates TLS? Where are logs collected? How will bypasses be detected? What is the rollback path?&lt;/p&gt;
&lt;p&gt;A reverse-proxy WAF makes these decisions explicit in the HTTP path. A transparent design may reduce topology changes but can require more network-level coordination. SafeLine’s documented deployment model is a self-hosted reverse proxy, so use the official guide to validate fit.&lt;/p&gt;
&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-safeline-support-both-rule-based-and-semantic-protection-&quot;&gt;Does SafeLine support both rule-based and semantic protection?&lt;/h4&gt;
&lt;p&gt;SafeLine documents layered application protection and dynamic protection features. Check the current product documentation for the exact behavior of each release.&lt;/p&gt;
&lt;h4 id=&quot;should-i-test-changes-before-production-&quot;&gt;Should I test changes before production?&lt;/h4&gt;
&lt;p&gt;Yes. Use a staged rollout, review logs, and verify legitimate requests before tightening policies.&lt;/p&gt;
&lt;h4 id=&quot;where-can-i-check-current-pro-pricing-&quot;&gt;Where can I check current Pro pricing?&lt;/h4&gt;
&lt;p&gt;Use the official &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;700K+ Installs Sale page&lt;/a&gt; for current campaign terms.&lt;/p&gt;
&lt;h4 id=&quot;is-the-sale-renewable-at-the-same-price-&quot;&gt;Is the sale renewable at the same price?&lt;/h4&gt;
&lt;p&gt;The campaign page says promotional pricing ends with the campaign; renewals return to regular pricing.&lt;/p&gt;
&lt;p&gt;What evidence would you use to compare protection modes in your own traffic?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Read the full guide on dev.to:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;📖 &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/&quot;&gt;Reverse Proxy or Transparent WAF? A Checklist for Web Teams&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;SafeLine Pro 700K+ Installs Sale&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31302/reverse-proxy-or-transparent-waf-a-checklist-for-web-teams</guid>
<pubDate>Fri, 16 Oct 2026 07:56:12 +0000</pubDate>
</item>
<item>
<title>Reverse Proxy or Transparent WAF? A Checklist for Web Teams</title>
<link>https://coderlegion.com/31287/reverse-proxy-or-transparent-waf-a-checklist-for-web-teams</link>
<description>&lt;h2 id=&quot;reverse-proxy-or-transparent-waf-a-checklist-for-web-teams-1&quot;&gt;Reverse Proxy or Transparent WAF? A Checklist for Web Teams&lt;/h2&gt;
&lt;p&gt;Ask five questions before deployment: Can the origin be restricted? Who terminates TLS? Where are logs collected? How will bypasses be detected? What is the rollback path?&lt;/p&gt;
&lt;p&gt;A reverse-proxy WAF makes these decisions explicit in the HTTP path. A transparent design may reduce topology changes but can require more network-level coordination. SafeLine’s documented deployment model is a self-hosted reverse proxy, so use the official guide to validate fit.&lt;/p&gt;
&lt;h3 id=&quot;faq-1&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-safeline-support-both-rule-based-and-semantic-protection--1&quot;&gt;Does SafeLine support both rule-based and semantic protection?&lt;/h4&gt;
&lt;p&gt;SafeLine documents layered application protection and dynamic protection features. Check the current product documentation for the exact behavior of each release.&lt;/p&gt;
&lt;h4 id=&quot;should-i-test-changes-before-production--1&quot;&gt;Should I test changes before production?&lt;/h4&gt;
&lt;p&gt;Yes. Use a staged rollout, review logs, and verify legitimate requests before tightening policies.&lt;/p&gt;
&lt;h4 id=&quot;where-can-i-check-current-pro-pricing--1&quot;&gt;Where can I check current Pro pricing?&lt;/h4&gt;
&lt;p&gt;Use the official &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;700K+ Installs Sale page&lt;/a&gt; for current campaign terms.&lt;/p&gt;
&lt;h4 id=&quot;is-the-sale-renewable-at-the-same-price--1&quot;&gt;Is the sale renewable at the same price?&lt;/h4&gt;
&lt;p&gt;The campaign page says promotional pricing ends with the campaign; renewals return to regular pricing.&lt;/p&gt;
&lt;p&gt;What evidence would you use to compare protection modes in your own traffic?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Read the full guide on dev.to:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;📖 &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/&quot;&gt;Reverse Proxy or Transparent WAF? A Checklist for Web Teams&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;SafeLine Pro 700K+ Installs Sale&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31287/reverse-proxy-or-transparent-waf-a-checklist-for-web-teams</guid>
<pubDate>Fri, 16 Oct 2026 06:23:12 +0000</pubDate>
</item>
<item>
<title>Reverse Proxy WAF vs Transparent Bridge: A Deployment Decision</title>
<link>https://coderlegion.com/31286/reverse-proxy-waf-vs-transparent-bridge-a-deployment-decision</link>
<description>&lt;h2 id=&quot;reverse-proxy-waf-vs-transparent-bridge-a-deployment-decision&quot;&gt;Reverse Proxy WAF vs Transparent Bridge: A Deployment Decision&lt;/h2&gt;
&lt;p&gt;The main difference is how clearly the WAF participates in the application traffic path. A reverse proxy is an explicit HTTP gateway. A transparent bridge is designed to minimize visible topology changes.&lt;/p&gt;
&lt;h3 id=&quot;reverse-proxy-trade-offs&quot;&gt;Reverse proxy trade-offs&lt;/h3&gt;
&lt;p&gt;The explicit hop can make routing and policy ownership easier to reason about. It also means the team must plan certificates, upstream connectivity, health checks, and origin restrictions.&lt;/p&gt;
&lt;h3 id=&quot;transparent-designs&quot;&gt;Transparent designs&lt;/h3&gt;
&lt;p&gt;A transparent design may fit networks where changing endpoints is difficult, but it can make troubleshooting and application context more dependent on the surrounding network.&lt;/p&gt;
&lt;p&gt;SafeLine documents the reverse-proxy model, application onboarding, and web attack protections. Compare that documented model with your existing topology before choosing a deployment.&lt;/p&gt;
&lt;h3 id=&quot;faq-2&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-safeline-support-both-rule-based-and-semantic-protection--2&quot;&gt;Does SafeLine support both rule-based and semantic protection?&lt;/h4&gt;
&lt;p&gt;SafeLine documents layered application protection and dynamic protection features. Check the current product documentation for the exact behavior of each release.&lt;/p&gt;
&lt;h4 id=&quot;should-i-test-changes-before-production--2&quot;&gt;Should I test changes before production?&lt;/h4&gt;
&lt;p&gt;Yes. Use a staged rollout, review logs, and verify legitimate requests before tightening policies.&lt;/p&gt;
&lt;h4 id=&quot;where-can-i-check-current-pro-pricing--2&quot;&gt;Where can I check current Pro pricing?&lt;/h4&gt;
&lt;p&gt;Use the official &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;700K+ Installs Sale page&lt;/a&gt; for current campaign terms.&lt;/p&gt;
&lt;h4 id=&quot;is-the-sale-renewable-at-the-same-price--2&quot;&gt;Is the sale renewable at the same price?&lt;/h4&gt;
&lt;p&gt;The campaign page says promotional pricing ends with the campaign; renewals return to regular pricing.&lt;/p&gt;
&lt;p&gt;What evidence would you use to compare protection modes in your own traffic?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Read the full guide on dev.to:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;📖 &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/&quot;&gt;Reverse Proxy WAF vs Transparent Bridge: A Deployment Decision&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/lto&quot;&gt;SafeLine Pro 700K+ Installs Sale&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31286/reverse-proxy-waf-vs-transparent-bridge-a-deployment-decision</guid>
<pubDate>Fri, 16 Oct 2026 06:22:39 +0000</pubDate>
</item>
<item>
<title>SafeLine’s 700K Install Sale Is Live: Save up to 35% on Pro</title>
<link>https://coderlegion.com/30798/safelines-700k-install-sale-is-live-save-up-to-35-on-pro</link>
<description>&lt;h2 id=&quot;safeline-s-700k-install-sale-is-live-save-up-to-35-on-pro&quot;&gt;SafeLine’s 700K Install Sale Is Live: Save up to 35% on Pro&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;SafeLine has passed 700,000 installs. To celebrate, SafeLine Pro is up to 35% off through November 30, 2026.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[Image suggestion: SafeLine 700K milestone campaign banner]&lt;/p&gt;
&lt;p&gt;SafeLine is a self-hosted web application firewall (WAF). It helps detect common attacks like SQL injection and cross-site scripting (XSS) before they reach your applications. It also includes CC protection and human verification, with one-click deployment and a graphical interface for day-to-day management.&lt;/p&gt;
&lt;p&gt;[Image suggestion: SafeLine product dashboard]&lt;/p&gt;
&lt;h3 id=&quot;what-pro-adds&quot;&gt;What Pro adds&lt;/h3&gt;
&lt;p&gt;As your website grows, you may need more visibility, flexible rules, or support for more applications. Pro includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Attack overview:&lt;/strong&gt; see traffic and attack activity in visual reports.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unlimited applications:&lt;/strong&gt; add more sites as you grow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced rules:&lt;/strong&gt; use layered protection and flexible Allow/Deny controls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance and high availability:&lt;/strong&gt; enable maximum-performance mode and sync configuration across master–slave nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[Image suggestion: Pro attack overview or feature comparison]&lt;/p&gt;
&lt;h3 id=&quot;sale-plans&quot;&gt;Sale plans&lt;/h3&gt;
&lt;p&gt;The sale runs &lt;strong&gt;October 12–November 30, 2026&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Plan &lt;/th&gt;&lt;th&gt;Regular price &lt;/th&gt;&lt;th&gt;Sale price &lt;/th&gt;&lt;th&gt;Discount&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1-Year Pro &lt;/td&gt;&lt;td&gt;$1,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$880&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;12% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2-Year Pro &lt;/td&gt;&lt;td&gt;$2,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$1,580&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;21% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3-Year Pro &lt;/td&gt;&lt;td&gt;$3,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$2,250&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;25% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5 × 1-Year Pro &lt;/td&gt;&lt;td&gt;$5,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$3,500&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;30% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10 × 1-Year Pro &lt;/td&gt;&lt;td&gt;$10,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$6,500&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;35% off&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;[Image suggestion: Pricing cards showing all five sale plans]&lt;/p&gt;
&lt;p&gt;The 2-Year plan works out to &lt;strong&gt;$790 per year&lt;/strong&gt;. The 3-Year plan works out to &lt;strong&gt;$750 per year&lt;/strong&gt;. These are one-time payments for the full license term, not annual installments.&lt;/p&gt;
&lt;p&gt;Multi-year plans extend one license. Multi-license packs include separate one-year licenses. All discounted licenses in a purchase must be placed in &lt;strong&gt;one order&lt;/strong&gt;. Discounts generally can’t be combined with other offers or codes.&lt;/p&gt;
&lt;h3 id=&quot;before-you-buy&quot;&gt;Before you buy&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Monthly Pro and Lite aren’t part of this sale.&lt;/li&gt;
&lt;li&gt;There’s no purchase limit on discounted packs.&lt;/li&gt;
&lt;li&gt;Renewals after the campaign return to regular pricing.&lt;/li&gt;
&lt;li&gt;Check the campaign page for full terms and license details.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[Image suggestion: Short purchase steps or checkout screenshot]&lt;/p&gt;
&lt;p&gt;Ready to choose a plan? Visit the &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/safeline&quot;&gt;SafeLine campaign page&lt;/a&gt;. You can also &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;try the online demo&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;view SafeLine on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The SafeLine Pro 700K install sale ends November 30. Save up to 35%.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Prices and terms are based on the English-language campaign page. Regional offers may differ.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30798/safelines-700k-install-sale-is-live-save-up-to-35-on-pro</guid>
<pubDate>Mon, 12 Oct 2026 10:48:13 +0000</pubDate>
</item>
<item>
<title>SafeLine’s 700K Install Sale Is Live: Save up to 35% on Pro</title>
<link>https://coderlegion.com/30796/safelines-700k-install-sale-is-live-save-up-to-35-on-pro</link>
<description>&lt;p&gt;&lt;strong&gt;SafeLine has passed 700,000 installs. To celebrate, SafeLine Pro is up to 35% off through November 30, 2026.&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=4231558487066993236&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;SafeLine is a self-hosted web application firewall (WAF). It helps detect common attacks like SQL injection and cross-site scripting (XSS) before they reach your applications. It also includes CC protection and human verification, with one-click deployment and a graphical interface for day-to-day management.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=2539455387620100710&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-pro-adds-1&quot;&gt;What Pro adds&lt;/h3&gt;
&lt;p&gt;As your website grows, you may need more visibility, flexible rules, or support for more applications. Pro includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Attack overview:&lt;/strong&gt; see traffic and attack activity in visual reports.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unlimited applications:&lt;/strong&gt; add more sites as you grow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced rules:&lt;/strong&gt; use layered protection and flexible Allow/Deny controls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance and high availability:&lt;/strong&gt; enable maximum-performance mode and sync configuration across master–slave nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[Image suggestion: Pro attack overview or feature comparison]&lt;/p&gt;
&lt;h3 id=&quot;sale-plans-1&quot;&gt;Sale plans&lt;/h3&gt;
&lt;p&gt;The sale runs &lt;strong&gt;October 12–November 30, 2026&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Plan &lt;/th&gt;&lt;th&gt;Regular price &lt;/th&gt;&lt;th&gt;Sale price &lt;/th&gt;&lt;th&gt;Discount&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1-Year Pro &lt;/td&gt;&lt;td&gt;$1,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$880&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;12% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2-Year Pro &lt;/td&gt;&lt;td&gt;$2,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$1,580&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;21% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3-Year Pro &lt;/td&gt;&lt;td&gt;$3,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$2,250&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;25% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5 × 1-Year Pro &lt;/td&gt;&lt;td&gt;$5,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$3,500&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;30% off&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10 × 1-Year Pro &lt;/td&gt;&lt;td&gt;$10,000 &lt;/td&gt;&lt;td&gt;&lt;strong&gt;$6,500&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;35% off&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;[Image suggestion: Pricing cards showing all five sale plans]&lt;/p&gt;
&lt;p&gt;The 2-Year plan works out to &lt;strong&gt;$790 per year&lt;/strong&gt;. The 3-Year plan works out to &lt;strong&gt;$750 per year&lt;/strong&gt;. These are one-time payments for the full license term, not annual installments.&lt;/p&gt;
&lt;p&gt;Multi-year plans extend one license. Multi-license packs include separate one-year licenses. All discounted licenses in a purchase must be placed in &lt;strong&gt;one order&lt;/strong&gt;. Discounts generally can’t be combined with other offers or codes.&lt;/p&gt;
&lt;h3 id=&quot;before-you-buy-1&quot;&gt;Before you buy&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Monthly Pro and Lite aren’t part of this sale.&lt;/li&gt;
&lt;li&gt;There’s no purchase limit on discounted packs.&lt;/li&gt;
&lt;li&gt;Renewals after the campaign return to regular pricing.&lt;/li&gt;
&lt;li&gt;Check the campaign page for full terms and license details.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[Image suggestion: Short purchase steps or checkout screenshot]&lt;/p&gt;
&lt;p&gt;Ready to choose a plan? Visit the &lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/safeline&quot;&gt;SafeLine campaign page&lt;/a&gt;. You can also &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;try the online demo&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;view SafeLine on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The SafeLine Pro 700K install sale ends November 30. Save up to 35%.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Prices and terms are based on the English-language campaign page. Regional offers may differ.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30796/safelines-700k-install-sale-is-live-save-up-to-35-on-pro</guid>
<pubDate>Mon, 12 Oct 2026 10:44:13 +0000</pubDate>
</item>
<item>
<title>Cloud WAF or Self-Hosted WAF? Four Questions for Teams</title>
<link>https://coderlegion.com/30774/cloud-waf-or-self-hosted-waf-four-questions-for-teams</link>
<description>&lt;h2 id=&quot;cloud-waf-or-self-hosted-waf-four-questions-for-teams&quot;&gt;Cloud WAF or Self-Hosted WAF? Four Questions for Teams&lt;/h2&gt;
&lt;p&gt;A short checklist can make the choice concrete. Where must traffic be processed? Who owns the WAF? How will you test policy changes? What is the recovery plan if the enforcement point fails?&lt;/p&gt;
&lt;h3 id=&quot;traffic-and-data-path&quot;&gt;Traffic and data path&lt;/h3&gt;
&lt;p&gt;Document whether requests may pass through an external edge and whether origin services can be reached only through the WAF. These answers often narrow the options quickly.&lt;/p&gt;
&lt;h3 id=&quot;ownership-and-rollout&quot;&gt;Ownership and rollout&lt;/h3&gt;
&lt;p&gt;Cloud services reduce some infrastructure ownership. Self-hosted services place more responsibility with your team but can provide direct control of deployment and policy. Either model needs staged rollout, logs, and a way to restore service.&lt;/p&gt;
&lt;p&gt;SafeLine operates as a reverse proxy in front of the web application and documents protections including web attack defense, rate limiting, CAPTCHA, authentication challenges, and dynamic protection.&lt;/p&gt;
&lt;h3 id=&quot;what-safeline-adds&quot;&gt;What SafeLine adds&lt;/h3&gt;
&lt;p&gt;SafeLine is documented as a self-hosted WAF that works as a reverse proxy in front of a web application. Its official documentation lists defenses for SQL injection, XSS, code injection, SSRF, path traversal, brute force, HTTP flood, and bot abuse. It also documents rate limiting, CAPTCHA challenges, authentication challenges, and dynamic protection.&lt;/p&gt;
&lt;p&gt;The right deployment still depends on your traffic path, application behavior, and operational capacity. Start with one application, confirm the proxy path, review logs, and tune policies before expanding coverage.&lt;/p&gt;
&lt;h3 id=&quot;faq-3&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-a-waf-replace-every-other-security-control-&quot;&gt;Does a WAF replace every other security control?&lt;/h4&gt;
&lt;p&gt;No. It focuses on web traffic and should complement network controls, secure code, identity controls, patching, and monitoring.&lt;/p&gt;
&lt;h4 id=&quot;is-reverse-proxy-placement-important-&quot;&gt;Is reverse proxy placement important?&lt;/h4&gt;
&lt;p&gt;Yes. Requests need to pass through the WAF before reaching the protected application.&lt;/p&gt;
&lt;h4 id=&quot;should-i-enable-every-protection-immediately-&quot;&gt;Should I enable every protection immediately?&lt;/h4&gt;
&lt;p&gt;Begin with a monitored rollout and validate legitimate requests before tightening policies.&lt;/p&gt;
&lt;h4 id=&quot;where-can-i-verify-the-product-details-&quot;&gt;Where can I verify the product details?&lt;/h4&gt;
&lt;p&gt;Use the &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;official SafeLine documentation&lt;/a&gt; and its deployment guides.&lt;/p&gt;
&lt;p&gt;What part of your current traffic path would you measure first before changing the security layer?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Read the full guide with screenshots on dev.to:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;📖 &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/&quot;&gt;Cloud WAF or Self-Hosted WAF? Four Questions for Teams&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30774/cloud-waf-or-self-hosted-waf-four-questions-for-teams</guid>
<pubDate>Mon, 12 Oct 2026 06:45:09 +0000</pubDate>
</item>
<item>
<title>Cloud WAF vs Self-Hosted WAF: A Deployment Decision Guide</title>
<link>https://coderlegion.com/30773/cloud-waf-vs-self-hosted-waf-a-deployment-decision-guide</link>
<description>&lt;h2 id=&quot;cloud-waf-vs-self-hosted-waf-a-deployment-decision-guide&quot;&gt;Cloud WAF vs Self-Hosted WAF: A Deployment Decision Guide&lt;/h2&gt;
&lt;p&gt;The cloud versus self-hosted decision is an operations decision as much as a feature comparison. Ask who owns the traffic path, who maintains the enforcement point, and who responds when protection affects legitimate users.&lt;/p&gt;
&lt;h3 id=&quot;cloud-advantages&quot;&gt;Cloud advantages&lt;/h3&gt;
&lt;p&gt;A managed service can reduce installation and maintenance work. It may be a good fit when your team wants a provider to handle much of the edge infrastructure and can route traffic through that service.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted-advantages&quot;&gt;Self-hosted advantages&lt;/h3&gt;
&lt;p&gt;A self-hosted WAF can fit environments where the team wants local control of routing and policy. It can also be easier to align with an existing reverse-proxy and private infrastructure design, provided the team operates it reliably.&lt;/p&gt;
&lt;p&gt;SafeLine documents installation, reverse-proxy behavior, application onboarding, rate limiting, and challenge features. Use those official guides to evaluate the work against your own topology.&lt;/p&gt;
&lt;h3 id=&quot;what-safeline-adds-1&quot;&gt;What SafeLine adds&lt;/h3&gt;
&lt;p&gt;SafeLine is documented as a self-hosted WAF that works as a reverse proxy in front of a web application. Its official documentation lists defenses for SQL injection, XSS, code injection, SSRF, path traversal, brute force, HTTP flood, and bot abuse. It also documents rate limiting, CAPTCHA challenges, authentication challenges, and dynamic protection.&lt;/p&gt;
&lt;p&gt;The right deployment still depends on your traffic path, application behavior, and operational capacity. Start with one application, confirm the proxy path, review logs, and tune policies before expanding coverage.&lt;/p&gt;
&lt;h3 id=&quot;faq-4&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-a-waf-replace-every-other-security-control--1&quot;&gt;Does a WAF replace every other security control?&lt;/h4&gt;
&lt;p&gt;No. It focuses on web traffic and should complement network controls, secure code, identity controls, patching, and monitoring.&lt;/p&gt;
&lt;h4 id=&quot;is-reverse-proxy-placement-important--1&quot;&gt;Is reverse proxy placement important?&lt;/h4&gt;
&lt;p&gt;Yes. Requests need to pass through the WAF before reaching the protected application.&lt;/p&gt;
&lt;h4 id=&quot;should-i-enable-every-protection-immediately--1&quot;&gt;Should I enable every protection immediately?&lt;/h4&gt;
&lt;p&gt;Begin with a monitored rollout and validate legitimate requests before tightening policies.&lt;/p&gt;
&lt;h4 id=&quot;where-can-i-verify-the-product-details--1&quot;&gt;Where can I verify the product details?&lt;/h4&gt;
&lt;p&gt;Use the &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;official SafeLine documentation&lt;/a&gt; and its deployment guides.&lt;/p&gt;
&lt;p&gt;What part of your current traffic path would you measure first before changing the security layer?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Read the full guide with screenshots on dev.to:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;📖 &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/&quot;&gt;Cloud WAF vs Self-Hosted WAF: A Deployment Decision Guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30773/cloud-waf-vs-self-hosted-waf-a-deployment-decision-guide</guid>
<pubDate>Mon, 12 Oct 2026 06:44:38 +0000</pubDate>
</item>
<item>
<title>SafeLine WAF vs Imperva: Self-Hosted WAF vs Enterprise Cloud Protection</title>
<link>https://coderlegion.com/30545/safeline-waf-vs-imperva-self-hosted-waf-vs-enterprise-cloud-protection</link>
<description>&lt;h2 id=&quot;safeline-waf-vs-imperva-self-hosted-waf-vs-enterprise-cloud-protection&quot;&gt;SafeLine WAF vs Imperva: Self-Hosted WAF vs Enterprise Cloud Protection&lt;/h2&gt;
&lt;p&gt;When people compare SafeLine to Imperva, they're usually comparing two very different things: a lightweight self-hosted WAF and a full enterprise cloud security stack. Here's how to think about which one fits your situation.&lt;/p&gt;
&lt;h3 id=&quot;what-each-one-is&quot;&gt;What each one is&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;SafeLine WAF&lt;/strong&gt; is a self-hosted web application firewall by Chaitin. Install it on your own server with one command, and it runs as a reverse proxy that inspects every HTTP request using a semantic engine — blocking SQL injection, XSS, and bots without signature upkeep. The Community Edition is free (10 apps, 800 QPS).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Imperva&lt;/strong&gt; is an enterprise cloud WAF and application-security platform. It sits in front of your apps at the network edge, bundling a WAF with a CDN, DDoS protection, and bot management. It's geared toward larger organizations with compliance and SLA requirements.&lt;/p&gt;
&lt;h3 id=&quot;the-difference-that-matters-the-model&quot;&gt;The difference that matters: the model&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SafeLine is self-hosted.&lt;/strong&gt; You run it, you own the data, you pay nothing on the free tier. Best for teams that want control and predictable cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Imperva is a managed cloud service.&lt;/strong&gt; You route traffic through Imperva's edge; they operate the infrastructure. Best for organizations that need an SLA, vendor support, and a broad security bundle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;side-by-side&quot;&gt;Side by side&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;SafeLine WAF &lt;/th&gt;&lt;th&gt;Imperva&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Deployment &lt;/td&gt;&lt;td&gt;Self-hosted reverse proxy &lt;/td&gt;&lt;td&gt;Cloud edge (WAF + CDN)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Detection &lt;/td&gt;&lt;td&gt;Semantic analysis, no signature upkeep &lt;/td&gt;&lt;td&gt;Signature, behavior, and reputation at scale&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Best for &lt;/td&gt;&lt;td&gt;Small teams, self-hosters, side projects &lt;/td&gt;&lt;td&gt;Enterprises with compliance and SLA needs&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Data residency &lt;/td&gt;&lt;td&gt;On your server &lt;/td&gt;&lt;td&gt;Through Imperva's cloud&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cost &lt;/td&gt;&lt;td&gt;Free Community Edition; paid tiers &lt;/td&gt;&lt;td&gt;Enterprise subscription&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;which-should-you-pick-&quot;&gt;Which should you pick?&lt;/h3&gt;
&lt;p&gt;If you run a handful of sites and want strong protection without a sales call or a monthly bill, start with a self-hosted WAF:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, point it at your app, and you're done.&lt;/p&gt;
&lt;p&gt;If you're at an organization with strict compliance, a required SLA, and a need for bundled CDN and bot management across many properties, a managed platform like Imperva is the more natural fit — at enterprise pricing.&lt;/p&gt;
&lt;h3 id=&quot;faq-5&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-safeline-enterprise-grade-&quot;&gt;Is SafeLine &quot;enterprise-grade&quot;?&lt;/h4&gt;
&lt;p&gt;SafeLine's detection is production-grade: semantic analysis with low false positives, running at scale for many users. The free tier is sized for around 10 apps; larger needs use paid tiers.&lt;/p&gt;
&lt;h4 id=&quot;does-imperva-require-its-cdn-&quot;&gt;Does Imperva require its CDN?&lt;/h4&gt;
&lt;p&gt;Imperva bundles a CDN, but you can use the WAF independently. A self-hosted WAF like SafeLine pairs with whatever CDN you already use.&lt;/p&gt;
&lt;h4 id=&quot;which-is-easier-to-start-&quot;&gt;Which is easier to start?&lt;/h4&gt;
&lt;p&gt;SafeLine: one install command, no account, no DNS change. Imperva: onboarding, routing setup, and a contract.&lt;/p&gt;
&lt;h4 id=&quot;can-i-self-host-and-still-meet-compliance-&quot;&gt;Can I self-host and still meet compliance?&lt;/h4&gt;
&lt;p&gt;Many teams run SafeLine in their own compliant environment and keep full control of logs and data residency — which is exactly why some organizations prefer self-hosted.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to give SafeLine a try?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30545/safeline-waf-vs-imperva-self-hosted-waf-vs-enterprise-cloud-protection</guid>
<pubDate>Sat, 10 Oct 2026 20:30:41 +0000</pubDate>
</item>
<item>
<title>What Is a WAF and How Does It Work? A Plain-English Guide</title>
<link>https://coderlegion.com/30547/what-is-a-waf-and-how-does-it-work-a-plain-english-guide</link>
<description>&lt;h2 id=&quot;what-is-a-waf-and-how-does-it-work-a-plain-english-guide&quot;&gt;What Is a WAF and How Does It Work? A Plain-English Guide&lt;/h2&gt;
&lt;p&gt;If you run a website, you've probably been told to &quot;put a WAF in front of it.&quot; Here's what that actually means — no jargon.&lt;/p&gt;
&lt;h3 id=&quot;what-waf-stands-for&quot;&gt;What &quot;WAF&quot; stands for&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;Web Application Firewall&lt;/strong&gt; protects your app at layer 7 (the application layer) — the part that speaks HTTP. Unlike a network firewall that only cares about IPs and ports, a WAF reads the &lt;em&gt;content&lt;/em&gt; of requests and decides whether they're safe.&lt;/p&gt;
&lt;h3 id=&quot;what-problem-it-solves&quot;&gt;What problem it solves&lt;/h3&gt;
&lt;p&gt;Most web attacks arrive as ordinary-looking HTTP requests that carry malicious payloads: a login field stuffed with SQL, a URL containing a script tag, a flood of requests from a botnet. A WAF inspects those requests before they reach your application code and blocks the bad ones.&lt;/p&gt;
&lt;h3 id=&quot;how-it-works&quot;&gt;How it works&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;It sits in front of your app&lt;/strong&gt; as a reverse proxy. Every request hits the WAF first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It inspects the request&lt;/strong&gt; — headers, URL, body, and cookies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It decides allow / block / challenge&lt;/strong&gt; based on its detection logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean traffic passes through&lt;/strong&gt; to your app; everything else is stopped.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;two-ways-wafs-detect-attacks&quot;&gt;Two ways WAFs detect attacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Signature-based:&lt;/strong&gt; matches known attack patterns (like an antivirus). Needs constant updating, and novel attacks slip through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic analysis:&lt;/strong&gt; understands what a request is &lt;em&gt;trying to do&lt;/em&gt; (for example, &quot;this is a SQL command&quot;), so it catches variants without a signature. SafeLine uses this approach, which keeps false positives low.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;where-it-sits&quot;&gt;Where it sits&lt;/h3&gt;
&lt;p&gt;A self-hosted WAF like SafeLine runs on your own server as a reverse proxy. You install it with one command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, point it at your app, and it filters traffic. No third party in the path, no DNS change.&lt;/p&gt;
&lt;h3 id=&quot;waf-vs-firewall-vs-ips&quot;&gt;WAF vs firewall vs IPS&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Network firewall:&lt;/strong&gt; controls who can connect (IPs and ports).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPS:&lt;/strong&gt; blocks known network intrusions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WAF:&lt;/strong&gt; understands HTTP and blocks application-layer attacks. They're complementary, not interchangeable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;faq-6&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;do-i-need-a-waf-if-i-use-a-cdn-&quot;&gt;Do I need a WAF if I use a CDN?&lt;/h4&gt;
&lt;p&gt;Many CDNs include a basic WAF, but a dedicated WAF gives finer control over application-layer rules. SafeLine focuses purely on that layer.&lt;/p&gt;
&lt;h4 id=&quot;will-a-waf-slow-my-site-down-&quot;&gt;Will a WAF slow my site down?&lt;/h4&gt;
&lt;p&gt;A well-tuned WAF adds minimal latency. SafeLine's free tier handles 800 QPS per instance.&lt;/p&gt;
&lt;h4 id=&quot;is-a-waf-enough-on-its-own-&quot;&gt;Is a WAF enough on its own?&lt;/h4&gt;
&lt;p&gt;It covers the application layer. Pair it with good patching, rate limiting, and (if needed) a CDN for fuller coverage.&lt;/p&gt;
&lt;h4 id=&quot;can-i-self-host-a-waf-for-free-&quot;&gt;Can I self-host a WAF for free?&lt;/h4&gt;
&lt;p&gt;Yes. SafeLine's Community Edition is free for up to 10 apps at 800 QPS and runs on a server you already have.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30547/what-is-a-waf-and-how-does-it-work-a-plain-english-guide</guid>
<pubDate>Sat, 10 Oct 2026 20:30:37 +0000</pubDate>
</item>
<item>
<title>SafeLine or CrowdSec? A Decision Guide for Your Stack</title>
<link>https://coderlegion.com/30417/safeline-or-crowdsec-a-decision-guide-for-your-stack</link>
<description>&lt;h2 id=&quot;safeline-or-crowdsec-a-decision-guide-for-your-stack&quot;&gt;SafeLine or CrowdSec? A Decision Guide for Your Stack&lt;/h2&gt;
&lt;p&gt;People often ask &quot;which one should I install?&quot; as if SafeLine and CrowdSec are interchangeable. They're not — they protect different layers, so the real question is &lt;em&gt;which layer is exposed first&lt;/em&gt;. Here's a quick way to decide what to deploy, and in what order.&lt;/p&gt;
&lt;h3 id=&quot;start-with-what-s-actually-exposed&quot;&gt;Start with what's actually exposed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You run a public web app.&lt;/strong&gt; Put SafeLine in front of it first. Its job is to inspect HTTP requests and block injection, XSS, and bots at the application layer — exactly the traffic your app receives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You run a bare server with SSH and other services.&lt;/strong&gt; Start with CrowdSec. It watches behavior across the host and bans malicious IPs (scanners, brute-forcers) at the firewall, before they reach anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Both describe you.&lt;/strong&gt; Run both. SafeLine filters the app; CrowdSec guards the host. Order doesn't matter much.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-simple-decision-tree&quot;&gt;A simple decision tree&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Is a web app reachable from the internet? → &lt;strong&gt;SafeLine&lt;/strong&gt; in front of it.&lt;/li&gt;
&lt;li&gt;Does the server expose SSH or other login services? → &lt;strong&gt;CrowdSec&lt;/strong&gt; to ban bad IPs.&lt;/li&gt;
&lt;li&gt;Both? → Deploy both; they don't conflict.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-each-one-needs-to-run&quot;&gt;What each one needs to run&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SafeLine&lt;/strong&gt; runs as a reverse proxy. One install command, point your app's traffic through the console, done. Free Community Edition covers up to 10 apps at 800 QPS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CrowdSec&lt;/strong&gt; runs as an agent plus a &quot;bouncer&quot; that enforces bans in your firewall (iptables/nftables). Add the collections for the services you actually run.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-mistake-picking-the-more-powerful-one&quot;&gt;The mistake: picking the &quot;more powerful&quot; one&lt;/h3&gt;
&lt;p&gt;A common trap is choosing based on feature count and skipping the other. But a WAF that filters requests can't ban an SSH brute-forcer, and an IP-banning engine can't read a SQL injection payload. Choosing one and skipping the other simply leaves a layer open. The decision isn't &lt;em&gt;SafeLine vs CrowdSec&lt;/em&gt; — it's &lt;em&gt;which layer first&lt;/em&gt;, and usually the answer is both.&lt;/p&gt;
&lt;h3 id=&quot;if-you-only-do-one-today&quot;&gt;If you only do one today&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Web app is your main risk → SafeLine.&lt;/li&gt;
&lt;li&gt;Host/SSH brute force is your main risk → CrowdSec.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then add the second when you have a moment. Incremental is fine; leaving a layer permanently open is not.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Don't ask which tool wins. Ask which layer is exposed — and cover it.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30417/safeline-or-crowdsec-a-decision-guide-for-your-stack</guid>
<pubDate>Fri, 09 Oct 2026 07:54:15 +0000</pubDate>
</item>
<item>
<title>From SSH Brute Force to SQL Injection: How SafeLine and Fail2ban Split the Work</title>
<link>https://coderlegion.com/30413/from-ssh-brute-force-to-sql-injection-how-safeline-and-fail2ban-split-the-work</link>
<description>&lt;h2 id=&quot;from-ssh-brute-force-to-sql-injection-how-safeline-and-fail2ban-split-the-work&quot;&gt;From SSH Brute Force to SQL Injection: How SafeLine and Fail2ban Split the Work&lt;/h2&gt;
&lt;p&gt;Most server compromises start with one of two things: someone guessing a password, or someone slipping a malicious payload into a web request. Those two attacks live on completely different layers — which is exactly why Fail2ban and SafeLine aren't competitors. Walk through both attack paths and it becomes obvious where each tool belongs.&lt;/p&gt;
&lt;h3 id=&quot;attack-path-1-ssh-brute-force&quot;&gt;Attack path 1: SSH brute force&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What happens:&lt;/strong&gt; a bot hammers your SSH port with thousands of password attempts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who stops it:&lt;/strong&gt; Fail2ban reads your authentication logs, counts the failures, and bans the offending IP by pushing a rule into your firewall (iptables, nftables, or firewalld).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why SafeLine isn't in the loop:&lt;/strong&gt; SafeLine sits in front of your &lt;em&gt;web app&lt;/em&gt;, inspecting HTTP traffic. SSH isn't HTTP, so it never sees the attempt. That's not a limitation — it's scope. Fail2ban owns the host; SafeLine owns the app.&lt;/p&gt;
&lt;h3 id=&quot;attack-path-2-sql-injection-in-a-login-form&quot;&gt;Attack path 2: SQL injection in a login form&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What happens:&lt;/strong&gt; a crafted POST hits &lt;code&gt;/login&lt;/code&gt; carrying a malicious payload designed to manipulate your database query.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who stops it:&lt;/strong&gt; SafeLine reads the request, and its semantic detection engine recognizes the injection attempt for what it is — regardless of the IP's reputation — and drops the request before it reaches your code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Fail2ban struggles here:&lt;/strong&gt; it sees an IP making a POST that returned a 200, which looks perfectly normal in a log. It has no visibility into the &lt;em&gt;payload&lt;/em&gt;, so it can't tell a legitimate login from a malicious one.&lt;/p&gt;
&lt;h3 id=&quot;the-split-stated-plainly&quot;&gt;The split, stated plainly&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Fail2ban &lt;/th&gt;&lt;th&gt;SafeLine&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Sees &lt;/td&gt;&lt;td&gt;IPs and log patterns &lt;/td&gt;&lt;td&gt;The actual HTTP request&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Stops &lt;/td&gt;&lt;td&gt;Brute force, scanners, repeat offenders &lt;/td&gt;&lt;td&gt;Injection, XSS, malicious bots&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Layer &lt;/td&gt;&lt;td&gt;Host / network (L3–L4) &lt;/td&gt;&lt;td&gt;Application (L7)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Acts by &lt;/td&gt;&lt;td&gt;Banning the IP at the firewall &lt;/td&gt;&lt;td&gt;Dropping the bad request&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Same server, two doors. Fail2ban locks the side door (SSH and service brute force); SafeLine locks the front door (your web app).&lt;/p&gt;
&lt;h3 id=&quot;a-sane-setup-order&quot;&gt;A sane setup order&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Expose only what you must.&lt;/strong&gt; Close unused ports; that alone shrinks your attack surface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fail2ban on the host.&lt;/strong&gt; Protect SSH and any other services with login attempts. Tune the filters to your logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SafeLine in front of the web app.&lt;/strong&gt; Install it as a reverse proxy and point your app's traffic through it:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your app keeps running exactly as before — it's just now shielded by a filter that understands what a request is trying to do.&lt;/p&gt;
&lt;h3 id=&quot;faq-7&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;can-one-tool-replace-the-other-&quot;&gt;Can one tool replace the other?&lt;/h4&gt;
&lt;p&gt;No. Fail2ban can't inspect request payloads; SafeLine doesn't ban IPs at the host level. They cover different layers.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-protect-ssh-&quot;&gt;Does SafeLine protect SSH?&lt;/h4&gt;
&lt;p&gt;No — and it's not meant to. SSH is handled by host-level tools like Fail2ban. SafeLine focuses on your web traffic.&lt;/p&gt;
&lt;h4 id=&quot;is-fail2ban-open-source-&quot;&gt;Is Fail2ban open source?&lt;/h4&gt;
&lt;p&gt;Yes, Fail2ban is open-source and widely used for host intrusion prevention. SafeLine is a self-hosted WAF with a free Community Edition (up to 10 apps at 800 QPS).&lt;/p&gt;
&lt;h4 id=&quot;if-i-only-pick-one-which-&quot;&gt;If I only pick one, which?&lt;/h4&gt;
&lt;p&gt;If your risk is a public web app, start with SafeLine — that's where application attacks land. If your risk is SSH or service brute force, start with Fail2ban. Most servers end up with both.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Different attacks, different layers, different tools — used together, they close both doors.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30413/from-ssh-brute-force-to-sql-injection-how-safeline-and-fail2ban-split-the-work</guid>
<pubDate>Fri, 09 Oct 2026 07:08:41 +0000</pubDate>
</item>
<item>
<title>SafeLine WAF vs Fail2ban: App-Layer vs Host-Level Defense</title>
<link>https://coderlegion.com/30411/safeline-waf-vs-fail2ban-app-layer-vs-host-level-defense</link>
<description>&lt;h2 id=&quot;safeline-waf-vs-fail2ban-app-layer-vs-host-level-defense&quot;&gt;SafeLine WAF vs Fail2ban: App-Layer vs Host-Level Defense&lt;/h2&gt;
&lt;p&gt;Fail2ban is one of the first tools people reach for when a server goes live — and for good reason. But it solves a different problem than a WAF. If you're wondering whether SafeLine replaces Fail2ban (or vice versa), the short answer is: they guard different layers, and you'll likely want both. Here's the breakdown.&lt;/p&gt;
&lt;h3 id=&quot;what-each-one-does&quot;&gt;What each one does&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Fail2ban&lt;/strong&gt; is an open-source intrusion-prevention tool. It watches your log files — SSH, web server, mail, whatever you point it at — and when an IP shows malicious behavior (repeated failed logins, bursts of 404s, obvious scans), it bans that IP by injecting a rule into your firewall (iptables, nftables, or firewalld). It's filter-and-ban, driven by regular expressions you configure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SafeLine&lt;/strong&gt; is a self-hosted WAF by Chaitin. It sits as a reverse proxy in front of your web app and inspects the &lt;em&gt;content&lt;/em&gt; of every HTTP request, blocking SQL injection, XSS, and malicious bots using a semantic detection engine — it understands what a request is trying to do, rather than matching attack signatures.&lt;/p&gt;
&lt;h3 id=&quot;the-key-difference-what-gets-inspected&quot;&gt;The key difference: what gets inspected&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fail2ban acts on IPs, based on log patterns.&lt;/strong&gt; It sees &quot;this IP failed SSH 10 times&quot; or &quot;this IP requested /wp-admin 50 times&quot; and blocks the IP. It never looks at the &lt;em&gt;body&lt;/em&gt; of a legitimate-looking HTTP request.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SafeLine acts on requests, at layer 7.&lt;/strong&gt; It reads the actual request your app receives and blocks the malicious ones — even from an IP that's never been seen before and has a clean reputation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's the crux: Fail2ban is great at stopping &lt;em&gt;who&lt;/em&gt; is attacking (bad IPs, brute force), while SafeLine is great at stopping &lt;em&gt;what&lt;/em&gt; the attack is (malicious payloads in the request).&lt;/p&gt;
&lt;h3 id=&quot;a-side-by-side-look&quot;&gt;A side-by-side look&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;SafeLine WAF &lt;/th&gt;&lt;th&gt;Fail2ban&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Primary job &lt;/td&gt;&lt;td&gt;Block web app attacks in HTTP requests &lt;/td&gt;&lt;td&gt;Ban IPs showing malicious log patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;What it sees &lt;/td&gt;&lt;td&gt;Request content (SQLi, XSS, bot traffic) &lt;/td&gt;&lt;td&gt;Log lines (failed logins, scans)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Enforcement &lt;/td&gt;&lt;td&gt;Reverse proxy, drops bad requests &lt;/td&gt;&lt;td&gt;Firewall rule banning the IP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Detection style &lt;/td&gt;&lt;td&gt;Semantic analysis (no signature upkeep) &lt;/td&gt;&lt;td&gt;Regex filters you define&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Covers &lt;/td&gt;&lt;td&gt;Application layer (L7) &lt;/td&gt;&lt;td&gt;Host / network layer (L3–L4)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Dashboard &lt;/td&gt;&lt;td&gt;Visual traffic &amp;amp; attack stats &lt;/td&gt;&lt;td&gt;Config files + CLI; no GUI&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;can-you-run-both-&quot;&gt;Can you run both?&lt;/h3&gt;
&lt;p&gt;Absolutely, and it's a common pairing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fail2ban protects the host.&lt;/strong&gt; It locks down SSH brute-force and bans IPs hammering your services — the stuff that shows up in logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SafeLine protects the app.&lt;/strong&gt; It filters the HTTP traffic that actually reaches your web service, catching injection and XSS that Fail2ban's log rules would never see.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Neither makes the other unnecessary. Fail2ban won't stop a SQL injection hidden in a valid-looking POST; SafeLine won't ban an IP brute-forcing your SSH port.&lt;/p&gt;
&lt;h3 id=&quot;which-should-you-start-with-&quot;&gt;Which should you start with?&lt;/h3&gt;
&lt;p&gt;If your concern is a &lt;strong&gt;public web app&lt;/strong&gt;, start with SafeLine — that's where application attacks land. Its free Community Edition covers up to 10 apps at 800 QPS and installs in one command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Point it at your app via the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt; and your requests are filtered. Then layer in Fail2ban for host-level brute-force protection if your server exposes SSH or other services.&lt;/p&gt;
&lt;h3 id=&quot;faq-8&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-safeline-replace-fail2ban-&quot;&gt;Does SafeLine replace Fail2ban?&lt;/h4&gt;
&lt;p&gt;Not entirely. SafeLine covers application-layer attacks; Fail2ban covers host-level IP banning (SSH brute force, etc.). They handle different layers.&lt;/p&gt;
&lt;h4 id=&quot;can-fail2ban-stop-sql-injection-&quot;&gt;Can Fail2ban stop SQL injection?&lt;/h4&gt;
&lt;p&gt;Only indirectly and poorly — it can ban an IP that triggers certain log patterns, but it can't inspect request payloads the way a WAF does. A WAF is the right tool for injection.&lt;/p&gt;
&lt;h4 id=&quot;is-fail2ban-hard-to-maintain-&quot;&gt;Is Fail2ban hard to maintain?&lt;/h4&gt;
&lt;p&gt;It's config-file driven: you write or tune filters (regex) for the services you watch. It's lightweight but less visual than a dashboard-based WAF.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-have-a-dashboard-&quot;&gt;Does SafeLine have a dashboard?&lt;/h4&gt;
&lt;p&gt;Yes. SafeLine's console shows traffic, blocked requests, and attack breakdowns without you parsing logs by hand.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Host-level banning and app-level filtering aren't competitors — together they close both doors.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30411/safeline-waf-vs-fail2ban-app-layer-vs-host-level-defense</guid>
<pubDate>Fri, 09 Oct 2026 06:34:40 +0000</pubDate>
</item>
<item>
<title>SafeLine WAF vs CrowdSec: WAF vs Behavior-Based Protection</title>
<link>https://coderlegion.com/30410/safeline-waf-vs-crowdsec-waf-vs-behavior-based-protection</link>
<description>&lt;h2 id=&quot;safeline-waf-vs-crowdsec-waf-vs-behavior-based-protection&quot;&gt;SafeLine WAF vs CrowdSec: WAF vs Behavior-Based Protection&lt;/h2&gt;
&lt;p&gt;If you're hardening a server, you'll run into both SafeLine and CrowdSec — and it's easy to assume they're rivals. They're not, really. They protect different layers, and most teams that take security seriously run both. Here's where each one fits so you can decide what you actually need.&lt;/p&gt;
&lt;h3 id=&quot;what-each-one-does-1&quot;&gt;What each one does&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;SafeLine&lt;/strong&gt; is a self-hosted web application firewall (WAF) by Chaitin. It sits in reverse-proxy mode in front of your web app and inspects every HTTP request — blocking SQL injection, cross-site scripting (XSS), and malicious bots before the traffic reaches your code. Its detection engine is &lt;strong&gt;semantic&lt;/strong&gt;: instead of matching attack signatures, it analyzes what a request is &lt;em&gt;trying to do&lt;/em&gt;, which keeps false positives low.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CrowdSec&lt;/strong&gt; is an open-source, community-powered security engine. Its agents observe behavior across your hosts and share signals of malicious IPs with a global threat-intelligence network. When an IP shows bad behavior — scanning, brute-forcing, weird traffic patterns — CrowdSec bans it, usually by pushing rules into your firewall (iptables, nftables) or a upstream filter.&lt;/p&gt;
&lt;h3 id=&quot;the-key-difference-layer&quot;&gt;The key difference: layer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SafeLine works at layer 7 (the application layer).&lt;/strong&gt; It reads the &lt;em&gt;content&lt;/em&gt; of HTTP requests. A request that looks harmless to a firewall but carries a SQLi payload gets caught by SafeLine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CrowdSec works at the network/host layer, based on behavior and IP reputation.&lt;/strong&gt; It decides whether an &lt;em&gt;IP&lt;/em&gt; is trustworthy and bans the ones that aren't. It doesn't deeply parse your application's request bodies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of it this way: CrowdSec asks &quot;is this IP a known bad actor?&quot; and SafeLine asks &quot;is this specific request malicious?&quot; Both questions matter.&lt;/p&gt;
&lt;h3 id=&quot;a-side-by-side-look-1&quot;&gt;A side-by-side look&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;SafeLine WAF &lt;/th&gt;&lt;th&gt;CrowdSec&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Primary job &lt;/td&gt;&lt;td&gt;Block web app attacks (SQLi, XSS, bots) &lt;/td&gt;&lt;td&gt;Ban malicious IPs by behavior + reputation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Where it sits &lt;/td&gt;&lt;td&gt;Reverse proxy, in front of your app &lt;/td&gt;&lt;td&gt;Host agent + firewall/remediation bouncer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;What it inspects &lt;/td&gt;&lt;td&gt;HTTP request content (L7) &lt;/td&gt;&lt;td&gt;IP behavior, log signals, community intel&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Detection style &lt;/td&gt;&lt;td&gt;Semantic analysis (no signature upkeep) &lt;/td&gt;&lt;td&gt;Behavior rules + crowd-sourced intelligence&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Dashboard &lt;/td&gt;&lt;td&gt;Visual traffic &amp;amp; attack stats &lt;/td&gt;&lt;td&gt;CLI + optional console; firewall rules&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cost &lt;/td&gt;&lt;td&gt;Free Community Edition (10 apps, 800 QPS) &lt;/td&gt;&lt;td&gt;Free / open-source&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;can-you-run-both--1&quot;&gt;Can you run both?&lt;/h3&gt;
&lt;p&gt;Yes — and they complement each other well:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CrowdSec pre-empts.&lt;/strong&gt; A known-bad IP trying to probe your site gets banned at the perimeter before it wastes your resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SafeLine catches what slips through.&lt;/strong&gt; The request that &lt;em&gt;does&lt;/em&gt; reach your app, carrying a clever payload, is stopped at the application layer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Many self-hosted setups put CrowdSec on the host (to protect SSH and ban scanners) and SafeLine in front of the web app (to filter application attacks). Neither makes the other redundant.&lt;/p&gt;
&lt;h3 id=&quot;which-should-you-start-with--1&quot;&gt;Which should you start with?&lt;/h3&gt;
&lt;p&gt;If you run a public web app, &lt;strong&gt;start with a WAF&lt;/strong&gt; — that's the layer attackers actually hit. SafeLine's free Community Edition covers up to 10 apps at 800 QPS and installs in one command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, point it at your app, and your traffic is filtered. Add CrowdSec afterward if you also want behavior-based IP banning across the host.&lt;/p&gt;
&lt;h3 id=&quot;faq-9&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-crowdsec-a-waf-&quot;&gt;Is CrowdSec a WAF?&lt;/h4&gt;
&lt;p&gt;No. It's an intrusion-prevention / IP-reputation engine. It bans bad IPs based on behavior and community intelligence but doesn't do deep HTTP payload inspection the way a WAF does.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-replace-my-firewall-&quot;&gt;Does SafeLine replace my firewall?&lt;/h4&gt;
&lt;p&gt;No. SafeLine filters application-layer traffic; your firewall still governs network access. They handle different layers.&lt;/p&gt;
&lt;h4 id=&quot;which-has-lower-false-positives-&quot;&gt;Which has lower false positives?&lt;/h4&gt;
&lt;p&gt;SafeLine's semantic engine is built to minimize false positives on legitimate traffic. CrowdSec's behavior rules can occasionally flag aggressive-but-legitimate crawlers, which you tune via its allowlists.&lt;/p&gt;
&lt;h4 id=&quot;can-safeline-run-on-the-same-server-as-crowdsec-&quot;&gt;Can SafeLine run on the same server as CrowdSec?&lt;/h4&gt;
&lt;p&gt;Yes. SafeLine runs as a containerized reverse proxy; CrowdSec runs as a host agent. They don't conflict.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Two layers, one goal: keep your app reachable to real users and invisible to attackers.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30410/safeline-waf-vs-crowdsec-waf-vs-behavior-based-protection</guid>
<pubDate>Fri, 09 Oct 2026 06:31:48 +0000</pubDate>
</item>
<item>
<title>SafeLine Reaches 700K Installs. A Pro Sale Is Coming.</title>
<link>https://coderlegion.com/30256/safeline-reaches-700k-installs-a-pro-sale-is-coming</link>
<description>&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=13321174692653627156&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;safeline-reaches-700k-installs-a-pro-sale-is-coming-&quot;&gt;SafeLine Reaches 700K Installs. A Pro Sale Is Coming.&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Thanks for being part of the SafeLine community. To celebrate 700,000+ installs, a limited-time SafeLine Pro sale starts October 12.&lt;/strong&gt;&lt;/p&gt;
&amp;lt;!-- Image suggestion: SafeLine 700K milestone teaser poster --&amp;gt;
&lt;p&gt;Running a website takes time. You ship updates, help customers, and keep services online. All the while, your site keeps getting requests—some welcome, some not.&lt;/p&gt;
&lt;p&gt;SafeLine helps protect websites from common attacks like SQL injection and cross-site scripting (XSS). It’s self-hosted and designed to be straightforward to deploy and manage.&lt;/p&gt;
&amp;lt;!-- Image suggestion: SafeLine dashboard or product screenshot --&amp;gt;
&lt;h3 id=&quot;when-is-pro-worth-a-look-&quot;&gt;When is Pro worth a look?&lt;/h3&gt;
&lt;p&gt;As your site grows, you may want more ways to understand traffic, tune protection, and manage more applications. SafeLine Pro adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An attack overview with visual traffic and attack data&lt;/li&gt;
&lt;li&gt;Unlimited applications&lt;/li&gt;
&lt;li&gt;Enhanced rules and more flexible Allow/Deny controls&lt;/li&gt;
&lt;li&gt;Maximum-performance mode and configuration sync for high availability&lt;/li&gt;
&lt;/ul&gt;
&amp;lt;!-- Image suggestion: Pro dashboard, attack overview, or feature comparison --&amp;gt;
&lt;h3 id=&quot;the-sale-starts-october-12&quot;&gt;The sale starts October 12&lt;/h3&gt;
&lt;p&gt;From &lt;strong&gt;October 12 to November 30, 2026&lt;/strong&gt;, save up to &lt;strong&gt;35%&lt;/strong&gt; on selected annual Pro plans and multi-license packs. We’ll share the full prices and purchase details when the sale opens.&lt;/p&gt;
&lt;p&gt;If you’re considering Pro, take a look at your current setup and think about what you’ll need next. Already using Pro? Check your license term and plan ahead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SafeLine Pro sale: October 12–November 30. Save up to 35%.&lt;/strong&gt;&lt;/p&gt;
&amp;lt;!-- Image suggestion: Campaign dates or sale countdown graphic --&amp;gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/safeline&quot;&gt;Learn more about SafeLine&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Try the online demo&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;View SafeLine on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Dates and terms follow the English-language campaign page. Regional offers may differ.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30256/safeline-reaches-700k-installs-a-pro-sale-is-coming</guid>
<pubDate>Thu, 08 Oct 2026 10:13:56 +0000</pubDate>
</item>
<item>
<title>SafeLine Reaches 700K Installs. A Pro Sale Is Coming.</title>
<link>https://coderlegion.com/30251/safeline-reaches-700k-installs-a-pro-sale-is-coming</link>
<description>&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=16454437680789420197&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;safeline-reaches-700k-installs-a-pro-sale-is-coming--1&quot;&gt;SafeLine Reaches 700K Installs. A Pro Sale Is Coming.&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Thanks for being part of the SafeLine community. To celebrate 700,000+ installs, a limited-time SafeLine Pro sale starts October 12.&lt;/strong&gt;&lt;/p&gt;
&amp;lt;!-- Image suggestion: SafeLine 700K milestone teaser poster --&amp;gt;
&lt;p&gt;Running a website takes time. You ship updates, help customers, and keep services online. All the while, your site keeps getting requests—some welcome, some not.&lt;/p&gt;
&lt;p&gt;SafeLine helps protect websites from common attacks like SQL injection and cross-site scripting (XSS). It’s self-hosted and designed to be straightforward to deploy and manage.&lt;/p&gt;
&amp;lt;!-- Image suggestion: SafeLine dashboard or product screenshot --&amp;gt;
&lt;h3 id=&quot;when-is-pro-worth-a-look--1&quot;&gt;When is Pro worth a look?&lt;/h3&gt;
&lt;p&gt;As your site grows, you may want more ways to understand traffic, tune protection, and manage more applications. SafeLine Pro adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An attack overview with visual traffic and attack data&lt;/li&gt;
&lt;li&gt;Unlimited applications&lt;/li&gt;
&lt;li&gt;Enhanced rules and more flexible Allow/Deny controls&lt;/li&gt;
&lt;li&gt;Maximum-performance mode and configuration sync for high availability&lt;/li&gt;
&lt;/ul&gt;
&amp;lt;!-- Image suggestion: Pro dashboard, attack overview, or feature comparison --&amp;gt;
&lt;h3 id=&quot;the-sale-starts-october-12-1&quot;&gt;The sale starts October 12&lt;/h3&gt;
&lt;p&gt;From &lt;strong&gt;October 12 to November 30, 2026&lt;/strong&gt;, save up to &lt;strong&gt;35%&lt;/strong&gt; on selected annual Pro plans and multi-license packs. We’ll share the full prices and purchase details when the sale opens.&lt;/p&gt;
&lt;p&gt;If you’re considering Pro, take a look at your current setup and think about what you’ll need next. Already using Pro? Check your license term and plan ahead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SafeLine Pro sale: October 12–November 30. Save up to 35%.&lt;/strong&gt;&lt;/p&gt;
&amp;lt;!-- Image suggestion: Campaign dates or sale countdown graphic --&amp;gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://cyberserval.tech/landing/safeline&quot;&gt;Learn more about SafeLine&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Try the online demo&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;View SafeLine on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Dates and terms follow the English-language campaign page. Regional offers may differ.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30251/safeline-reaches-700k-installs-a-pro-sale-is-coming</guid>
<pubDate>Thu, 08 Oct 2026 09:37:07 +0000</pubDate>
</item>
<item>
<title>How to Secure a Website Without Cloudflare</title>
<link>https://coderlegion.com/30201/how-to-secure-a-website-without-cloudflare</link>
<description>&lt;h2 id=&quot;how-to-secure-a-website-without-cloudflare&quot;&gt;How to Secure a Website Without Cloudflare&lt;/h2&gt;
&lt;p&gt;Cloudflare is the default answer to &quot;how do I secure my site,&quot; but it isn't the only one — and it isn't always the right fit. If you'd rather keep control of your infrastructure, avoid a third-party sitting between you and every visitor, or just want a free starting point, you can secure a website without Cloudflare using a self-hosted stack.&lt;/p&gt;
&lt;p&gt;Here's the layering that actually matters.&lt;/p&gt;
&lt;h3 id=&quot;the-security-layers-none-cloudflare-dependent-&quot;&gt;The security layers (none Cloudflare-dependent)&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TLS everywhere.&lt;/strong&gt; Terminate HTTPS with a free certificate (Let's Encrypt or your CA of choice). Encrypted transport is table stakes, not a feature you rent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A WAF in front of your app.&lt;/strong&gt; This is the layer Cloudflare's firewall usually provides. You can self-host it instead: a WAF like SafeLine runs as a reverse proxy in front of your service and filters injection, XSS, and bot traffic before it reaches your code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate limiting and bot management.&lt;/strong&gt; Throttle abusive clients and separate automated traffic from real users at the edge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hardened DNS and registrar.&lt;/strong&gt; Lock your domain (registrar lock), use a reputable DNS provider, and restrict zone edits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patching and backups.&lt;/strong&gt; Most breaches exploit known vulnerabilities in unpatched software. Keep dependencies current and back up regularly.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;where-safeline-fits-as-the-waf-layer&quot;&gt;Where SafeLine fits as the WAF layer&lt;/h3&gt;
&lt;p&gt;SafeLine is a self-hosted WAF by Chaitin. Its free &lt;strong&gt;Community Edition&lt;/strong&gt; runs on your own hardware and covers up to &lt;strong&gt;10 apps at 800 QPS&lt;/strong&gt;, which is enough for most sites. It sits in reverse-proxy mode in front of your app, so every request is inspected before it hits your code — the same job Cloudflare's firewall does, just on infrastructure you control.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After install, open the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, add your site, and point its upstream at your app. You now have a filtering layer in front of your traffic without handing your traffic to a third party.&lt;/p&gt;
&lt;h3 id=&quot;the-honest-trade-off&quot;&gt;The honest trade-off&lt;/h3&gt;
&lt;p&gt;Cloudflare also brings a global CDN and very large-scale DDoS scrubbing capacity. A self-hosted WAF handles the application layer (injection, XSS, bots, abuse) extremely well, but for nation-state-sized volumetric floods you'd still want upstream/network mitigation. For the overwhelming majority of sites — business apps, blogs, APIs, internal tools — a self-hosted WAF plus the hygiene above is a complete, Cloudflare-free security posture.&lt;/p&gt;
&lt;h3 id=&quot;faq-10&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-a-self-hosted-waf-harder-to-run-than-cloudflare-&quot;&gt;Is a self-hosted WAF harder to run than Cloudflare?&lt;/h4&gt;
&lt;p&gt;It's a different operational model: you own the box instead of a dashboard. The install is one command, and day-to-day it runs as a background service.&lt;/p&gt;
&lt;h4 id=&quot;do-i-lose-ddos-protection-without-cloudflare-&quot;&gt;Do I lose DDoS protection without Cloudflare?&lt;/h4&gt;
&lt;p&gt;You keep application-layer protection (the attacks that actually hit web apps). For massive volumetric attacks you'd add network-level mitigation, but most sites don't face those.&lt;/p&gt;
&lt;h4 id=&quot;can-i-still-use-a-cdn-&quot;&gt;Can I still use a CDN?&lt;/h4&gt;
&lt;p&gt;Yes — pair a CDN for static delivery with SafeLine in front of your dynamic origin. They're complementary, not exclusive.&lt;/p&gt;
&lt;h4 id=&quot;is-the-waf-free-&quot;&gt;Is the WAF free?&lt;/h4&gt;
&lt;p&gt;The Community Edition is free to run indefinitely and covers up to 10 apps at 800 QPS.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;That's it — a complete security stack you control, with no Cloudflare required.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30201/how-to-secure-a-website-without-cloudflare</guid>
<pubDate>Thu, 08 Oct 2026 02:39:32 +0000</pubDate>
</item>
<item>
<title>Self-Hosted WAF with a Low False Positive Rate: Why It Matters</title>
<link>https://coderlegion.com/29170/self-hosted-waf-with-a-low-false-positive-rate-why-it-matters</link>
<description>&lt;h2 id=&quot;self-hosted-waf-with-a-low-false-positive-rate-why-it-matters&quot;&gt;Self-Hosted WAF with a Low False Positive Rate: Why It Matters&lt;/h2&gt;
&lt;p&gt;When you shop for a WAF, the headline number everyone shows is detection rate — how much attack traffic it catches. That's important, but it's only half the story. The other half is the &lt;strong&gt;false positive rate (FPR)&lt;/strong&gt;: how often the WAF wrongly flags legitimate traffic as an attack. A WAF that blocks 100% of attacks but also blocks 20% of your real users is worse than no WAF at all.&lt;/p&gt;
&lt;p&gt;If you self-host, a low-FPR WAF protects your traffic without becoming a daily source of &quot;why is the site down?&quot; tickets. Here's what to look for.&lt;/p&gt;
&lt;h3 id=&quot;what-a-false-positive-actually-costs&quot;&gt;What a false positive actually costs&lt;/h3&gt;
&lt;p&gt;A false positive is a real, innocent request — a customer's login, a partner's API call, a search query with an odd character — that the WAF drops because it looked malicious. The consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lost conversions&lt;/strong&gt; — blocked customers don't retry, they leave.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Broken integrations&lt;/strong&gt; — a partner API call rejected mid-flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alert fatigue&lt;/strong&gt; — your team starts ignoring the WAF because it &quot;always complains.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;High FPR pushes teams to loosen rules until the WAF stops helping. Low FPR means you can keep protection tight without breaking the business.&lt;/p&gt;
&lt;h3 id=&quot;why-some-wafs-trip-on-false-positives&quot;&gt;Why some WAFs trip on false positives&lt;/h3&gt;
&lt;p&gt;Traditional signature-based WAFs match requests against a list of known attack patterns. That's brittle: an unusual-but-valid input — a SQL-looking string in a search box, an encoded parameter — can trip a rule that was meant for something else. The more rules you stack to catch attacks, the more innocent traffic you risk catching too.&lt;/p&gt;
&lt;h3 id=&quot;how-a-semantic-engine-lowers-the-rate&quot;&gt;How a semantic engine lowers the rate&lt;/h3&gt;
&lt;p&gt;A semantic-detection engine (the approach SafeLine uses) doesn't just pattern-match. It analyzes the &lt;em&gt;intent&lt;/em&gt; of a request — whether it's actually trying to exploit something — rather than whether it contains a suspicious-looking substring. Valid-but-odd requests pass; genuinely malicious ones are blocked. That distinction is what keeps the false positive rate low.&lt;/p&gt;
&lt;p&gt;In SafeLine's published benchmark (its BlazeHTTP test against tens of thousands of attack payloads), the Community Edition posted a &lt;strong&gt;0.07% false positive rate&lt;/strong&gt; while still detecting the large majority of attacks — markedly lower than the double-digit FPR seen in some signature-rule configurations of traditional WAFs in the same test. The point isn't the exact figure; it's that a semantic approach is designed to keep legitimate traffic flowing.&lt;/p&gt;
&lt;h3 id=&quot;what-to-check-before-you-commit&quot;&gt;What to check before you commit&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request intent, not just signatures&lt;/strong&gt; — ask whether the engine understands the request or just matches strings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tunable thresholds&lt;/strong&gt; — you should be able to tighten or loosen without rewriting rules by hand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transparent logs&lt;/strong&gt; — when something is blocked, you need to see why, fast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted fit&lt;/strong&gt; — run it where your traffic already flows, with no per-request billing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;deploying-it&quot;&gt;Deploying it&lt;/h3&gt;
&lt;p&gt;Bring up SafeLine as a reverse proxy in front of your app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, add your site, point its upstream at your app, and let the detection engine filter traffic. Review the logs for a day of real traffic, allowlist any legitimate patterns that surface, and you have tight protection with minimal noise.&lt;/p&gt;
&lt;h3 id=&quot;faq-11&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-a-low-false-positive-rate-the-same-as-high-detection-&quot;&gt;Is a low false positive rate the same as high detection?&lt;/h4&gt;
&lt;p&gt;No — they're independent. A WAF can be great at one and poor at the other. You want both: catch the attacks &lt;em&gt;and&lt;/em&gt; let real traffic through.&lt;/p&gt;
&lt;h4 id=&quot;should-i-trust-a-vendor-s-benchmark-number-&quot;&gt;Should I trust a vendor's benchmark number?&lt;/h4&gt;
&lt;p&gt;Treat published benchmarks as directional, not gospel — your traffic is the real test. Run the WAF in front of live traffic and watch the logs before drawing conclusions.&lt;/p&gt;
&lt;h4 id=&quot;will-a-semantic-engine-ever-false-positive-&quot;&gt;Will a semantic engine ever false-positive?&lt;/h4&gt;
&lt;p&gt;Any filter can, on sufficiently unusual input. The advantage is far fewer of them, and clear logs make the rare miss easy to spot and allowlist.&lt;/p&gt;
&lt;h4 id=&quot;is-this-free-to-self-host-&quot;&gt;Is this free to self-host?&lt;/h4&gt;
&lt;p&gt;The Community Edition is free to run indefinitely and covers up to 10 apps at 800 QPS, with the same detection engine as the paid tiers.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;That's it — you can run tight WAF protection without flooding your team with false alarms.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/29170/self-hosted-waf-with-a-low-false-positive-rate-why-it-matters</guid>
<pubDate>Wed, 30 Sep 2026 03:25:50 +0000</pubDate>
</item>
<item>
<title>How to Prevent Application-Layer DDoS Attacks on Your Web App</title>
<link>https://coderlegion.com/28851/how-to-prevent-application-layer-ddos-attacks-on-your-web-app</link>
<description>&lt;h2 id=&quot;how-to-prevent-application-layer-ddos-attacks-on-your-web-app&quot;&gt;How to Prevent Application-Layer DDoS Attacks on Your Web App&lt;/h2&gt;
&lt;p&gt;Most people picture DDoS as a firehose of garbage packets aimed at a network. But the attacks that actually take down modern web apps are usually quieter: &lt;strong&gt;application-layer (L7) DDoS&lt;/strong&gt;, where the flood looks like normal traffic. It's a wave of legitimate-looking HTTP requests designed to exhaust your app, database, or upstream.&lt;/p&gt;
&lt;p&gt;Because the requests aren't obviously malicious, a plain firewall can't tell them apart from real users. A WAF in front of your app is the right place to draw the line. Here's how.&lt;/p&gt;
&lt;h3 id=&quot;why-l7-ddos-is-tricky&quot;&gt;Why L7 DDoS is tricky&lt;/h3&gt;
&lt;p&gt;A network-layer DDoS is easy to spot — it's just volume. An application-layer attack blends in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requests hit real URLs with valid headers.&lt;/li&gt;
&lt;li&gt;They may come from many IPs (a botnet), so blocking by address alone doesn't scale.&lt;/li&gt;
&lt;li&gt;The damage comes from &lt;em&gt;cost&lt;/em&gt; — each request triggers expensive work: a database query, a render, an API call.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal isn't to crash your server with bandwidth; it's to make your app do so much real work that it falls over.&lt;/p&gt;
&lt;h3 id=&quot;the-defense-playbook&quot;&gt;The defense playbook&lt;/h3&gt;
&lt;p&gt;A few controls together blunt most L7 floods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Filter the obviously bad.&lt;/strong&gt; Drop malformed requests, known attack signatures, and malformed HTTP before they reach your app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate limit per IP and per path.&lt;/strong&gt; Cap how much any single client can ask of a given endpoint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manage bots.&lt;/strong&gt; Identify and throttle automated clients; let humans through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache aggressively.&lt;/strong&gt; Serve static and repeatable responses from cache so they never reach your app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scale the origin&lt;/strong&gt; behind the WAF so a spike doesn't instantly exhaust capacity.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;where-safeline-fits&quot;&gt;Where SafeLine fits&lt;/h3&gt;
&lt;p&gt;SafeLine is a self-hosted WAF that runs as a reverse proxy in front of your app, so every request is inspected before it reaches your code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;semantic detection engine&lt;/strong&gt; filters abnormal and malicious HTTP traffic, dropping the junk that would otherwise hit your app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate limiting&lt;/strong&gt; caps requests per client and per path, so a flood can't monopolize your origin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bot management&lt;/strong&gt; separates automated traffic from real users, letting you throttle or block the flood without hurting legitimate visitors.&lt;/li&gt;
&lt;li&gt;Because it runs at the edge of your stack, malicious requests are stopped early — before they trigger expensive backend work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SafeLine won't replace a full CDN-scale DDoS solution for nation-state-sized floods, but for the common L7 attacks that knock over small-to-mid web apps, it's a strong, self-hosted first line of defense.&lt;/p&gt;
&lt;h3 id=&quot;deploying-it-in-front-of-your-app&quot;&gt;Deploying it in front of your app&lt;/h3&gt;
&lt;p&gt;Bring up SafeLine as the proxy in front of your service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, add your site and point its upstream at your app. Enable bot mitigation and set sensible rate limits on your heaviest endpoints. Traffic is now filtered and throttled at the edge, so a flood has to get past the WAF before it can touch your app.&lt;/p&gt;
&lt;h3 id=&quot;faq-12&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;can-a-waf-stop-all-ddos-attacks-&quot;&gt;Can a WAF stop all DDoS attacks?&lt;/h4&gt;
&lt;p&gt;It handles the common application-layer floods that target web apps. Very large volumetric attacks also need upstream/network mitigation, but most real-world incidents are L7 — exactly what a WAF addresses.&lt;/p&gt;
&lt;h4 id=&quot;won-t-rate-limiting-hurt-real-users-during-a-spike-&quot;&gt;Won't rate limiting hurt real users during a spike?&lt;/h4&gt;
&lt;p&gt;Set limits above normal human patterns. Legitimate traffic sails through; only abusive automated volume gets throttled.&lt;/p&gt;
&lt;h4 id=&quot;does-this-replace-caching-and-scaling-&quot;&gt;Does this replace caching and scaling?&lt;/h4&gt;
&lt;p&gt;No — they're complementary. SafeLine filters and throttles; caching and scaling absorb the rest. Together they're far more resilient than any one control.&lt;/p&gt;
&lt;h4 id=&quot;is-this-hard-to-self-host-&quot;&gt;Is this hard to self-host?&lt;/h4&gt;
&lt;p&gt;The one-line installer brings up the whole stack as containers, and the console walks you through adding a site.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;That's it — your app now has a filtering and rate-limiting layer in front of it.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28851/how-to-prevent-application-layer-ddos-attacks-on-your-web-app</guid>
<pubDate>Mon, 28 Sep 2026 02:25:39 +0000</pubDate>
</item>
<item>
<title>Why I prefer systemd timers over cronjobs</title>
<link>https://coderlegion.com/28485/why-i-prefer-systemd-timers-over-cronjobs</link>
<description>&lt;p&gt;Most users would schedule their tasks using a cronjob, and that's perfectly reasonable&lt;/p&gt;
&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;I will &lt;em&gt;assume&lt;/em&gt; you are running on a linux machine with systemd (which you should be if you're running on a server), other init systems such as runit or openRC are not taken into consideration&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;The content is mainly targeted for servers, however you can apply these concepts to your personal machines &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;what-is-a-cronjob&quot;&gt;What is a cronjob&lt;/h4&gt;
&lt;p&gt;Cronjobs are essentially used for scheduling tasks at certain intervals or exact time(s)&lt;/p&gt;
&lt;p&gt;The task could be a shell script, a command, a call, anything you may need&lt;/p&gt;
&lt;h5 id=&quot;example-usage&quot;&gt;Example Usage&lt;/h5&gt;
&lt;p&gt;Creating a cronjob is very easy&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;crontab -e&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Paste this: &lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;*/1 * * * * echo &quot;$(date -Iminutes) Running&quot; &amp;gt;&amp;gt; /tmp/cronjob_running.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This would &lt;code&gt;echo&lt;/code&gt; the current datetime in ISO format to file &lt;code&gt;/tmp/cronjob_running.txt&lt;/code&gt; every minute&lt;/p&gt;
&lt;p&gt;Simple, easy and straightforward&lt;/p&gt;
&lt;h3 id=&quot;problem&quot;&gt;Problem&lt;/h3&gt;
&lt;p&gt;This works fine and well for personal, simple or non important tasks.&lt;/p&gt;
&lt;p&gt;But let's take this job:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;0 0 * * * /usr/local/sbin/postgresql_backup.sh &amp;gt;&amp;gt; /var/log/postgres/backups/backup.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This job would run the &lt;code&gt;postgresql_backup.sh&lt;/code&gt; script every day at &lt;code&gt;00:00&lt;/code&gt; and output the logs AND errors to &lt;code&gt;/var/log/postgres/backups/backup.log&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;What happens when the machine goes down at &lt;code&gt;00:00&lt;/code&gt;? or something even more probable, cron's systemd unit (like cronie) stops or does not start because someone forgot to (re)enable it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Answer: The job &lt;em&gt;never&lt;/em&gt; runs&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;systemd-timers&quot;&gt;Systemd timers&lt;/h3&gt;
&lt;h3 id=&quot;what-is-systemd&quot;&gt;What is systemd&lt;/h3&gt;
&lt;p&gt;It's the core init unit of your linux system, when your machine boots up, the kernel will load it with a &lt;code&gt;pid&lt;/code&gt; of 1&lt;/p&gt;
&lt;p&gt;A systemd timer is, as the name suggests, a timer that is managed by &lt;code&gt;systemd&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;So basically, the solution is already integrated into your Operating System, you're just not using it!&lt;/p&gt;
&lt;p&gt;What's more, they have more precision than cronjobs do and they support much finer scheduling granularity.&lt;/p&gt;
&lt;h3 id=&quot;how-to-create-these-timers&quot;&gt;How to create these timers&lt;/h3&gt;
&lt;p&gt;Now I'll be honest, creating them is a bit of a pain and not as quick as cronjobs, but we'll talk about the differences at the end!&lt;/p&gt;
&lt;p&gt;For the sake of simplicity I'll keep the example very straightforward, but note you can really get a bit more complex with these&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, you create a user systemd unit by running:&lt;/p&gt;
&lt;p&gt; &lt;code&gt;systemctl --user edit --force --full example-unit.service&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;&lt;p&gt;We're creating a &lt;code&gt;user&lt;/code&gt; scoped timer for this example, but for more serious work like a database backup, use sudo and omit user, like this: &lt;code&gt;sudo systemctl edit --force --full example-unit.service&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;The &lt;code&gt;--force --full&lt;/code&gt; flags are used to create the unit if it doesn't exist, I use the &lt;code&gt;systemctl edit&lt;/code&gt; command so that if we exit with an empty file, we won't have issues, plus it does create a &lt;em&gt;backup&lt;/em&gt; for us which is handy&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Then put this into the content&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-systemd&quot;&gt;[Unit]
Description=Our Example systemd Unit

[Service]
ExecStart=/usr/bin/echo &quot;Hello There!&quot;

[Install]
WantedBy=default.target
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Save and exit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reload your systemd daemon:&lt;/p&gt;
&lt;p&gt; &lt;code&gt;systemctl --user daemon-reload&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the unit&lt;/p&gt;
&lt;p&gt; &lt;code&gt;systemctl --user start example-unit.service&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nothing happens, why? where's my output?&lt;/p&gt;
&lt;p&gt;You inspect your service like any other systemd unit.. with &lt;code&gt;status&lt;/code&gt; subcommand&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run this&lt;/p&gt;
&lt;p&gt; &lt;code&gt;systemctl --user status example-unit.service&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; You get something similar to this:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://media.blog.nazih.top/systemd-timers/systemd-service-run.png&quot; alt=&quot;Result of our Example Unit output&quot;&gt;&lt;/p&gt;
&lt;p&gt;But where's the schedule here?&lt;br&gt;
Well, this is why I said&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;creating them is a bit of a pain and not as quick as cronjobs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;the-timer&quot;&gt;The Timer&lt;/h3&gt;
&lt;p&gt;Finally, it's time we create the actual timer unit&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run this command:&lt;/p&gt;
&lt;p&gt; &lt;code&gt;systemctl --user edit --force --full example-unit.timer&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;&lt;p&gt;The same goes here, omit the &lt;code&gt;--user&lt;/code&gt; flag and add &lt;code&gt;sudo&lt;/code&gt; if doing a system wide timer!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Add this&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-systemd&quot;&gt;[Unit]
Description=Running Our Example Unit regularly

[Timer]
OnCalendar=*:0/1
# This here is our magic flag
Persistent=true
Unit=example-unit.service

[Install]
WantedBy=timers.target
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Save and exit&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run this command&lt;/p&gt;
&lt;p&gt; &lt;code&gt;systemctl --user start example-unit.timer&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;NOTE: We're only starting the timer here, if we reboot the machine the timer will not persist&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;For the timer to remain enabled, you do &lt;code&gt;systemctl --user enable --now example-unit.timer&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Here's what you get:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://media.blog.nazih.top/systemd-timers/systemd-timer-run.png&quot; alt=&quot;timer-run&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://media.blog.nazih.top/systemd-timers/systemd-timer-unit.png&quot; alt=&quot;timer-unit&quot;&gt;&lt;/p&gt;
&lt;p&gt;This will &lt;code&gt;run&lt;/code&gt; our unit every minute, and with our magic &lt;code&gt;Persistent=true&lt;/code&gt; even if your machine goes down, or for whatever reason it gets missed due to some random bit flipping, your timer WILL run when it gets the chance&lt;/p&gt;
&lt;p&gt;It stores the last execution timestamp on disk. When the timer becomes active, systemd checks this file, and if the target trigger time passed while the system was powered off it immediately triggers the service.&lt;/p&gt;
&lt;h3 id=&quot;comparing-systemd-timers-to-other-solutions&quot;&gt;Comparing systemd timers to other solutions&lt;/h3&gt;
&lt;p&gt;Now for more informed readers, you may know of &lt;code&gt;anacron&lt;/code&gt; which is a perfectly reasonable solution however there are some differences you need to be aware of.&lt;/p&gt;
&lt;p&gt;Here's a comparison to systemd timers, cronjobs and anacron&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Solution &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Simple to create &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Flexible Scheduling &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Runs on missed tasks&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Systemd  &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;❌               &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✅                  &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Anacron  &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✅               &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;❌                  &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Cronjob  &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✅               &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✅                  &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;anacron doesn't have that much flexibility, they have daily basis checkup, which you may or may not want, so beware of that&lt;/p&gt;
&lt;h3 id=&quot;systemd-timers-scheduling&quot;&gt;Systemd timers Scheduling&lt;/h3&gt;
&lt;p&gt;You may have noticed that we used the &lt;code&gt;OnCalendar&lt;/code&gt; keyword in our timer, it's not the only one! there are more things you can configure&lt;/p&gt;
&lt;h4 id=&quot;monotonic-timers&quot;&gt;Monotonic Timers&lt;/h4&gt;
&lt;p&gt;These basically run relative to &lt;em&gt;something&lt;/em&gt;, it can be relative to system boot, it can be time since the unit was activated!&lt;/p&gt;
&lt;p&gt;Here's a small table of keywords and schedules you can have that I &lt;em&gt;borrowed&lt;/em&gt; from this great &lt;a rel=&quot;nofollow&quot; href=&quot;https://linuxconfig.org/how-to-schedule-tasks-with-systemd-timers-in-linux&quot;&gt;Article&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Keyword           &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Meaning&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;OnActiveSec       &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Schedule the task relative to the time when the timer unit itself is activated&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;OnBootSec         &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Schedule task relative to the system boot time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;OnStartupSec      &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Schedule the task relative to the time when systemd started&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;OnUnitActiveSec   &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Schedule the task relative to the last time the service unit was active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;OnUnitInactiveSec &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Schedule the task relative to the last time the service unit was inactive&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Seconds are used as the default unit of time. We can specify a different unit after the value (e.g. 15m for fifteen minutes)&lt;/p&gt;
&lt;h4 id=&quot;realtime-timers&quot;&gt;Realtime Timers&lt;/h4&gt;
&lt;p&gt;These are the ones that use the &lt;code&gt;OnCalendar&lt;/code&gt; keyword&lt;/p&gt;
&lt;p&gt;The basic syntax is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;OnCalendar=Mon *-*-* 12:30:00
           │   │ │ │ │  │  │
           │   │ │ │ │  │  └── SECOND
           │   │ │ │ │  └───── MINUTE
           │   │ │ │ └──────── HOUR
           │   │ │ └────────── DAY OF MONTH
           │   │ └──────────── MONTH
           │   └────────────── YEAR
           └────────────────── WEEKDAY
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Systemd Timers are great for scheduling important tasks or interacting with a daemon that you already installed.&lt;br&gt;
So are they the solution for everything? No, they're cumbersome to create and honestly I don't like the way it's handled.&lt;/p&gt;
&lt;p&gt;Use the right tool for the job, if it's a business critical backup that runs twice a day? a very important data collection task? Use systemd timers, if it's simply another task that would not harm if it was missed once, use cronjobs, they're much easier to create &lt;/p&gt;
&lt;p&gt;There are many things that I have not mentioned in this article, and things I didn't go into depth into but I hope this article helps future engineers with their journey in automating and scheduling&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28485/why-i-prefer-systemd-timers-over-cronjobs</guid>
<pubDate>Thu, 24 Sep 2026 13:39:29 +0000</pubDate>
</item>
<item>
<title>Free WAF for Self-Hosted Apps: Protect Your Stack Without the Bill</title>
<link>https://coderlegion.com/28401/free-waf-for-self-hosted-apps-protect-your-stack-without-the-bill</link>
<description>&lt;h2 id=&quot;free-waf-for-self-hosted-apps-protect-your-stack-without-the-bill&quot;&gt;Free WAF for Self-Hosted Apps: Protect Your Stack Without the Bill&lt;/h2&gt;
&lt;p&gt;If you self-host your apps, you've already committed to owning the infrastructure. That's good news for security: it means you can drop a free WAF in front of your stack without signing up for another monthly bill. For anyone running services on a VPS, a homelab, or a small cloud instance, a self-hosted WAF is some of the cheapest insurance you can buy.&lt;/p&gt;
&lt;p&gt;Here's how to protect self-hosted apps for free, and why SafeLine's Community Edition is a practical default.&lt;/p&gt;
&lt;h3 id=&quot;why-self-hosted-apps-need-a-waf&quot;&gt;Why self-hosted apps need a WAF&lt;/h3&gt;
&lt;p&gt;Any app you expose to the internet — a dashboard, an API, a CMS — is a target. Attackers scan for injection flaws, exposed admin panels, and known exploits automatically, around the clock. A WAF sits in front of your app and filters that traffic before it reaches your code.&lt;/p&gt;
&lt;p&gt;The catch with many WAFs is the price: cloud services bill per request or per protected app, which adds up fast across a self-hosted stack with several services. Running the WAF yourself removes that line item.&lt;/p&gt;
&lt;h3 id=&quot;what-free-should-still-give-you&quot;&gt;What &quot;free&quot; should still give you&lt;/h3&gt;
&lt;p&gt;Not all free WAFs are equal. A free option is only worth it if it does the job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blocks the common web attacks (SQL injection, XSS) by default.&lt;/li&gt;
&lt;li&gt;Mitigates automated bots and credential stuffing.&lt;/li&gt;
&lt;li&gt;Deploys in minutes, not days.&lt;/li&gt;
&lt;li&gt;Runs on hardware you already have.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If a &quot;free&quot; tool needs you to write a pile of rules before it blocks anything, it isn't really free in time.&lt;/p&gt;
&lt;h3 id=&quot;safeline-community-edition-a-free-self-hosted-pick&quot;&gt;SafeLine Community Edition: a free self-hosted pick&lt;/h3&gt;
&lt;p&gt;SafeLine is a self-hosted WAF by Chaitin, and its &lt;strong&gt;Community Edition&lt;/strong&gt; is free to run indefinitely. It covers &lt;strong&gt;up to 10 applications at 800 QPS&lt;/strong&gt;, which is plenty for a personal stack or a small set of self-hosted services.&lt;/p&gt;
&lt;p&gt;Under the hood it uses a semantic detection engine — it analyzes request intent rather than matching a static signature list — to catch injection and bot traffic. You get the protection without becoming a rule-tuning specialist.&lt;/p&gt;
&lt;h3 id=&quot;deploying-it-in-a-few-minutes&quot;&gt;Deploying it in a few minutes&lt;/h3&gt;
&lt;p&gt;The one-line installer brings up the full stack (management console, detection engine, database, and cache) as containers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add a site and set its upstream to your app (for example &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Point your DNS or reverse proxy at SafeLine's listener.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it — traffic now flows through the WAF before reaching your app. The minimum host is modest: about &lt;strong&gt;1 CPU, 1 GB RAM, and 5 GB disk&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;when-free-stops-being-enough&quot;&gt;When free stops being enough&lt;/h3&gt;
&lt;p&gt;The Community Edition's two caps are &lt;strong&gt;10 apps&lt;/strong&gt; and &lt;strong&gt;800 QPS&lt;/strong&gt;. If you run more services or push more traffic, the paid tiers lift those limits — Lite raises the app cap, and Pro removes it entirely — while keeping the same detection engine. You upgrade for headroom, not for better protection.&lt;/p&gt;
&lt;h3 id=&quot;faq-13&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-this-really-free-or-a-trial-&quot;&gt;Is this really free, or a trial?&lt;/h4&gt;
&lt;p&gt;The Community Edition is free to run with no time limit. The only constraints are the 10-app and 800-QPS ceilings.&lt;/p&gt;
&lt;h4 id=&quot;can-it-sit-in-front-of-multiple-apps-&quot;&gt;Can it sit in front of multiple apps?&lt;/h4&gt;
&lt;p&gt;Yes — up to 10 on the free tier. Each protected site or API counts as one app.&lt;/p&gt;
&lt;h4 id=&quot;do-i-need-to-write-detection-rules-&quot;&gt;Do I need to write detection rules?&lt;/h4&gt;
&lt;p&gt;No. The semantic engine blocks common attacks out of the box; you tune only if you want to.&lt;/p&gt;
&lt;h4 id=&quot;what-if-i-outgrow-the-free-tier-later-&quot;&gt;What if I outgrow the free tier later?&lt;/h4&gt;
&lt;p&gt;Upgrading is a licensing change that raises the caps; your configuration and protected sites carry over.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28401/free-waf-for-self-hosted-apps-protect-your-stack-without-the-bill</guid>
<pubDate>Thu, 24 Sep 2026 02:29:13 +0000</pubDate>
</item>
<item>
<title>Best Self-Hosted WAF for Small Business: What to Look For</title>
<link>https://coderlegion.com/28400/best-self-hosted-waf-for-small-business-what-to-look-for</link>
<description>&lt;h2 id=&quot;best-self-hosted-waf-for-small-business-what-to-look-for&quot;&gt;Best Self-Hosted WAF for Small Business: What to Look For&lt;/h2&gt;
&lt;p&gt;Small businesses get attacked at roughly the same rate as everyone else, but they rarely have a security team to absorb the hit. A web application firewall (WAF) is one of the highest-leverage defenses you can put in front of your site — and for a small business, a &lt;strong&gt;self-hosted&lt;/strong&gt; WAF is often the most sensible way to run one.&lt;/p&gt;
&lt;p&gt;This guide walks through what actually matters when you're picking a WAF for a small business, and why a self-hosted option like SafeLine's free Community Edition deserves a serious look.&lt;/p&gt;
&lt;h3 id=&quot;what-a-small-business-actually-needs-from-a-waf&quot;&gt;What a small business actually needs from a WAF&lt;/h3&gt;
&lt;p&gt;Enterprise WAF buying guides are full of features most small businesses will never touch. Strip it back to what you really need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Protection from the common stuff&lt;/strong&gt; — SQL injection, cross-site scripting, and automated bots are the daily background noise of the internet. A WAF should block these out of the box, without you hand-writing rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy to set up&lt;/strong&gt; — if deployment takes a senior engineer a week, it won't happen. The best WAF for a small business is the one you'll actually turn on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low or no cost&lt;/strong&gt; — small margins mean every recurring subscription is a decision. Free is a strong default when the protection is real.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal upkeep&lt;/strong&gt; — you don't have spare cycles to babysit it. It should run quietly once configured.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-self-hosted-fits-small-businesses&quot;&gt;Why self-hosted fits small businesses&lt;/h3&gt;
&lt;p&gt;A self-hosted WAF runs on infrastructure you already control — a spare VM, a small VPS, or a node in your existing stack. That changes the economics in your favor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No per-app or per-request billing.&lt;/strong&gt; Cloud WAFs often charge by traffic or by the number of protected services. Self-hosted shifts that to a flat server cost you're likely already paying.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data stays with you.&lt;/strong&gt; Traffic inspection happens on your own hardware, which matters if you have residency or compliance preferences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No lock-in.&lt;/strong&gt; You're not tied to one vendor's console, pricing changes, or feature gates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The trade-off is real but small: you own the box, so you handle the host. For most small businesses that's a fair exchange for removing a monthly bill.&lt;/p&gt;
&lt;h3 id=&quot;how-to-evaluate-options&quot;&gt;How to evaluate options&lt;/h3&gt;
&lt;p&gt;When you compare self-hosted WAFs, score them on four things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Detection quality&lt;/strong&gt; — does it actually catch injection and bot traffic, or just pattern-match a stale signature list?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install friction&lt;/strong&gt; — how many commands from zero to a protected site?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource footprint&lt;/strong&gt; — can it run on a modest box alongside other services?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Price ceiling&lt;/strong&gt; — what do you pay as you grow?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;where-safeline-fits-1&quot;&gt;Where SafeLine fits&lt;/h3&gt;
&lt;p&gt;SafeLine is a self-hosted WAF by Chaitin. Its free &lt;strong&gt;Community Edition&lt;/strong&gt; is a strong fit for small businesses because it covers the needs above without a subscription:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Free forever, self-hosted, and covers &lt;strong&gt;up to 10 applications at 800 QPS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ships with a semantic detection engine that blocks SQL injection, XSS, and bots without signature tuning.&lt;/li&gt;
&lt;li&gt;Installs with a single command and runs on a modest host — roughly &lt;strong&gt;1 CPU, 1 GB RAM, and 5 GB disk&lt;/strong&gt; at minimum.&lt;/li&gt;
&lt;li&gt;Management console on &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That combination — free, low-footprint, and genuinely protective — is exactly what most small businesses are looking for.&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot;&gt;Getting started&lt;/h3&gt;
&lt;p&gt;The fastest path is the one-line installer, which brings up the whole stack (console, detection engine, database, cache) as containers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open the console, add your first site, and point its upstream at your app. If you grow past 10 apps or 800 QPS, paid tiers (Lite and Pro) raise the ceiling without changing how the WAF behaves.&lt;/p&gt;
&lt;h3 id=&quot;faq-14&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;do-i-need-a-waf-if-i-already-use-https-&quot;&gt;Do I need a WAF if I already use HTTPS?&lt;/h4&gt;
&lt;p&gt;Yes. HTTPS encrypts traffic; it doesn't stop an attacker from sending a malicious request to your login form. A WAF inspects what's inside the request.&lt;/p&gt;
&lt;h4 id=&quot;is-the-free-tier-enough-for-a-small-business-&quot;&gt;Is the free tier enough for a small business?&lt;/h4&gt;
&lt;p&gt;Often, yes — 10 apps at 800 QPS covers a typical small-business footprint. Upgrade only when you outgrow those caps.&lt;/p&gt;
&lt;h4 id=&quot;will-running-it-myself-be-a-lot-of-work-&quot;&gt;Will running it myself be a lot of work?&lt;/h4&gt;
&lt;p&gt;Minimal. Once installed and pointed at your sites, it runs as a background service. You check the console occasionally, like any other server component.&lt;/p&gt;
&lt;h4 id=&quot;what-if-i-don-t-have-a-spare-server-&quot;&gt;What if I don't have a spare server?&lt;/h4&gt;
&lt;p&gt;A small VPS (the size that runs the console) is enough to start, and it can often share the host with other lightweight services.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28400/best-self-hosted-waf-for-small-business-what-to-look-for</guid>
<pubDate>Thu, 24 Sep 2026 02:27:39 +0000</pubDate>
</item>
<item>
<title>SafeLine WAF Community Edition Limitations: What You Get for Free</title>
<link>https://coderlegion.com/28241/safeline-waf-community-edition-limitations-what-you-get-for-free</link>
<description>&lt;h2 id=&quot;safeline-waf-community-edition-limitations-what-you-get-for-free&quot;&gt;SafeLine WAF Community Edition Limitations: What You Get for Free&lt;/h2&gt;
&lt;p&gt;SafeLine ships a free &lt;strong&gt;Community Edition&lt;/strong&gt; that you can run on your own server with no time limit and no feature trial. That makes it one of the few self-hosted WAFs you can actually put in front of production traffic without pulling out a credit card. But &quot;free&quot; does come with a ceiling, and it's worth knowing exactly where that ceiling sits before you commit.&lt;/p&gt;
&lt;p&gt;This article walks through what the Community Edition includes, the two hard limits you'll hit, and the point at which stepping up to a paid tier makes sense.&lt;/p&gt;
&lt;h3 id=&quot;what-the-community-edition-actually-gives-you&quot;&gt;What the Community Edition actually gives you&lt;/h3&gt;
&lt;p&gt;The free tier is not a stripped-down demo. It's the same detection engine that powers the paid plans, just with capacity caps. Concretely, the Community Edition covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Up to 10 applications&lt;/strong&gt; behind the WAF.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Up to 800 QPS&lt;/strong&gt; (queries per second) of protected traffic.&lt;/li&gt;
&lt;li&gt;The core semantic detection engine — the part that blocks SQL injection, XSS, bot traffic, and common web exploits without signature tuning.&lt;/li&gt;
&lt;li&gt;A management console, logs, and the reverse-proxy mode that sits in front of your upstream services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your setup fits inside those two numbers, you get the full protective value of SafeLine at zero cost. For a personal site, a small portfolio of internal tools, or a handful of low-traffic services, that's often the entire story.&lt;/p&gt;
&lt;h3 id=&quot;where-the-limits-actually-bite&quot;&gt;Where the limits actually bite&lt;/h3&gt;
&lt;p&gt;There are exactly two hard constraints on the Community Edition, and both are about scale rather than features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;10 applications.&lt;/strong&gt; Each protected site or API counts as one app. Once you pass ten, you can't add more on the free tier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;800 QPS.&lt;/strong&gt; This is the throughput ceiling for inspected traffic. Bursts above it won't be denied outright, but you've left the envelope the free tier is sized for.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice what &lt;em&gt;isn't&lt;/em&gt; limited: there's no expiry, no blocked attack category, and no &quot;contact sales after 14 days&quot; wall. The limits are capacity, not capability. That's a meaningful difference from vendors who gate the actual protection behind a paid plan.&lt;/p&gt;
&lt;h3 id=&quot;when-it-s-time-to-move-up&quot;&gt;When it's time to move up&lt;/h3&gt;
&lt;p&gt;If you're consistently near either cap — or you simply expect to grow past it — SafeLine offers two paid tiers that lift the ceilings rather than change how the WAF behaves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lite&lt;/strong&gt; — roughly &lt;strong&gt;$10/month&lt;/strong&gt;, raising the cap to &lt;strong&gt;20 applications&lt;/strong&gt;. A small step up for growing teams.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro&lt;/strong&gt; — roughly &lt;strong&gt;$100/month&lt;/strong&gt;, with &lt;strong&gt;unlimited applications&lt;/strong&gt; for larger estates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the detection engine is identical across tiers, upgrading is about headroom, not about suddenly getting better protection. You move up when your app count or traffic volume demands it, not because the free tier is &quot;missing&quot; a feature.&lt;/p&gt;
&lt;h3 id=&quot;getting-started-on-the-free-tier&quot;&gt;Getting started on the free tier&lt;/h3&gt;
&lt;p&gt;The fastest way to see the Community Edition in action is the one-line installer, which brings up the whole stack (console, detection engine, database, cache) as containers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once it finishes, open the console at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;, add your first site, and point its upstream at your app. You're now protecting up to 10 applications at 800 QPS for free.&lt;/p&gt;
&lt;h3 id=&quot;faq-15&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-the-community-edition-a-time-limited-trial-&quot;&gt;Is the Community Edition a time-limited trial?&lt;/h4&gt;
&lt;p&gt;No. It's free to run indefinitely. The only constraints are the 10-app and 800-QPS ceilings.&lt;/p&gt;
&lt;h4 id=&quot;what-happens-if-i-exceed-800-qps-&quot;&gt;What happens if I exceed 800 QPS?&lt;/h4&gt;
&lt;p&gt;The limit is a sizing ceiling, not a hard cutoff that starts dropping traffic. But if you're consistently above it, a paid tier gives you the headroom to run comfortably.&lt;/p&gt;
&lt;h4 id=&quot;do-i-lose-any-protection-features-on-the-free-tier-&quot;&gt;Do I lose any protection features on the free tier?&lt;/h4&gt;
&lt;p&gt;The detection capabilities are the same across tiers. Paid plans raise the app and throughput limits; they don't unlock a separate set of WAF features.&lt;/p&gt;
&lt;h4 id=&quot;can-i-switch-from-community-to-pro-later-&quot;&gt;Can I switch from Community to Pro later?&lt;/h4&gt;
&lt;p&gt;Yes. Since the engine is the same, moving up is a licensing change that lifts the caps — your configuration and protected sites carry over.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28241/safeline-waf-community-edition-limitations-what-you-get-for-free</guid>
<pubDate>Wed, 23 Sep 2026 02:24:36 +0000</pubDate>
</item>
<item>
<title>How we migrated an Italian logistics company from Windows to Linux: a real case study</title>
<link>https://coderlegion.com/28167/how-we-migrated-an-italian-logistics-company-from-windows-to-linux-a-real-case-study</link>
<description>&lt;p&gt;In early 2026 I migrated a logistics and transport company in Bergamo, Italy from a fully proprietary setup to Linux and open source. Five workstations, five employees, zero technical background on their side. Here is what we did, what happened, and what I learned.&lt;/p&gt;
&lt;h3 id=&quot;the-starting-point&quot;&gt;The starting point&lt;/h3&gt;
&lt;p&gt;The company was running Windows on every workstation, Microsoft Office for documents, a third-party antivirus renewed annually, and an external IT technician called in every time something broke. They had no internal IT knowledge and no interest in acquiring any. They just wanted things to work.&lt;/p&gt;
&lt;p&gt;Their main pain points were slow machines, frequent crashes after Windows updates, and a recurring bill that kept growing without any visible improvement.&lt;/p&gt;
&lt;h3 id=&quot;what-we-installed&quot;&gt;What we installed&lt;/h3&gt;
&lt;p&gt;I replaced everything with a fully open source stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubuntu as the operating system on all five workstations&lt;/li&gt;
&lt;li&gt;LibreOffice in place of Microsoft Office&lt;/li&gt;
&lt;li&gt;Thunderbird for email&lt;/li&gt;
&lt;li&gt;Nextcloud for file sharing and internal document management, self-hosted on a server in Italy&lt;/li&gt;
&lt;li&gt;Mattermost for internal team communication&lt;/li&gt;
&lt;li&gt;pfSense as the network firewall&lt;/li&gt;
&lt;li&gt;WireGuard for VPN access&lt;/li&gt;
&lt;li&gt;Automated encrypted backups running nightly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Total recurring licence cost after migration: zero.&lt;/p&gt;
&lt;h3 id=&quot;the-migration-process&quot;&gt;The migration process&lt;/h3&gt;
&lt;p&gt;The full migration took approximately one week. I configured everything on a test machine first, validated all workflows with the team, then rolled out workstation by workstation during off-hours to avoid interruptions.&lt;/p&gt;
&lt;p&gt;The biggest challenge was not technical. It was psychological. People are used to what they know. I spent as much time sitting with each employee and showing them that LibreOffice opens their Word files and Nextcloud works like Google Drive as I did on the actual technical setup.&lt;/p&gt;
&lt;p&gt;After three days they stopped asking about Windows.&lt;/p&gt;
&lt;h3 id=&quot;results-after-six-months&quot;&gt;Results after six months&lt;/h3&gt;
&lt;p&gt;Six months in, the company has not called me for a single ordinary technical issue. The machines are faster. Updates do not break anything. There have been zero security incidents.&lt;/p&gt;
&lt;p&gt;The most concrete result: each employee recovered roughly one hour per day that was previously lost to slowdowns, crashes and waiting for the external technician. On five people that is five hours a day returned to productive work.&lt;/p&gt;
&lt;p&gt;Licence costs are gone. The infrastructure belongs to them, not to a vendor.&lt;/p&gt;
&lt;h3 id=&quot;why-this-matters-beyond-one-company&quot;&gt;Why this matters beyond one company&lt;/h3&gt;
&lt;p&gt;Most Italian SMEs are in the same situation. They pay recurring fees for software they do not own, store data on foreign servers subject to the US Cloud Act, and depend on vendors who can change the rules at any time.&lt;/p&gt;
&lt;p&gt;Linux and open source infrastructure is not experimental. It is mature, stable, and ready for business use. The barrier is not technical. It is awareness.&lt;/p&gt;
&lt;p&gt;I wrote the Zerolock Manifesto (&lt;a rel=&quot;nofollow&quot; href=&quot;https://zerolock.org&quot;&gt;https://zerolock.org&lt;/a&gt;) on exactly this topic. If you are working on similar migrations or have questions about the stack, I am happy to discuss in the comments.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28167/how-we-migrated-an-italian-logistics-company-from-windows-to-linux-a-real-case-study</guid>
<pubDate>Tue, 22 Sep 2026 12:57:16 +0000</pubDate>
</item>
<item>
<title>How to Block Bad Bots with SafeLine WAF</title>
<link>https://coderlegion.com/27873/how-to-block-bad-bots-with-safeline-waf</link>
<description>&lt;h2 id=&quot;how-to-block-bad-bots-with-safeline-waf&quot;&gt;How to Block Bad Bots with SafeLine WAF&lt;/h2&gt;
&lt;p&gt;Bad bots are everywhere: content scrapers, credential stuffers, vulnerability scanners, and spam senders. The trick is blocking the harmful ones without hurting good crawlers like Google. SafeLine does this with bot detection and a human-verification challenge at the edge.&lt;/p&gt;
&lt;h3 id=&quot;the-problem-with-a-blunt-block&quot;&gt;The problem with a blunt block&lt;/h3&gt;
&lt;p&gt;Blocking by IP or user-agent alone breaks easily — bots rotate both. And a naive block can also catch search-engine crawlers you &lt;em&gt;want&lt;/em&gt; indexing your site. You need to tell automated abuse apart from real users and legitimate bots.&lt;/p&gt;
&lt;h3 id=&quot;step-1-install-safeline-in-front-of-your-site&quot;&gt;Step 1 — Install SafeLine in front of your site&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add your site as the upstream in the console at &lt;code&gt;https://&amp;lt;safeline-ip&amp;gt;:9443&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-2-turn-on-bot-protection&quot;&gt;Step 2 — Turn on bot protection&lt;/h3&gt;
&lt;p&gt;SafeLine detects automated behavior and can issue a &lt;strong&gt;bot challenge&lt;/strong&gt; (a human-verification step) to clients that look suspicious. A real browser solves it once and proceeds; a scripted bot fails or gets throttled. Legitimate, well-behaved crawlers pass through normally.&lt;/p&gt;
&lt;h3 id=&quot;step-3-keep-good-bots-working&quot;&gt;Step 3 — Keep good bots working&lt;/h3&gt;
&lt;p&gt;Add allowlist entries for crawlers you trust (for example, Googlebot) so SEO and indexing are unaffected. SafeLine's heuristics handle the rest of the automated traffic.&lt;/p&gt;
&lt;h3 id=&quot;step-4-add-rate-limiting-where-it-helps&quot;&gt;Step 4 — Add rate limiting where it helps&lt;/h3&gt;
&lt;p&gt;Bot blocking pairs well with rate limiting for specific paths — &lt;code&gt;/login&lt;/code&gt; against credential stuffing, or an API endpoint against scraping. Set a threshold and SafeLine slows or blocks clients that exceed it.&lt;/p&gt;
&lt;h3 id=&quot;what-you-see&quot;&gt;What you see&lt;/h3&gt;
&lt;p&gt;The dashboard breaks down bot vs. human traffic and shows which clients were challenged or blocked, so you can tune the allowlist with confidence.&lt;/p&gt;
&lt;h3 id=&quot;faq-16&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;will-this-hurt-my-seo-&quot;&gt;Will this hurt my SEO?&lt;/h4&gt;
&lt;p&gt;No — good crawlers are allowed through; only abusive automated traffic is challenged.&lt;/p&gt;
&lt;h4 id=&quot;can-i-allow-specific-bots-&quot;&gt;Can I allow specific bots?&lt;/h4&gt;
&lt;p&gt;Yes — allowlist by user-agent or other traits for crawlers you trust.&lt;/p&gt;
&lt;h4 id=&quot;does-it-stop-credential-stuffing-&quot;&gt;Does it stop credential stuffing?&lt;/h4&gt;
&lt;p&gt;Combined with rate limiting on login paths, yes.&lt;/p&gt;
&lt;h4 id=&quot;free-tier-&quot;&gt;Free tier?&lt;/h4&gt;
&lt;p&gt;The Community Edition covers 10 apps at 800 QPS for free.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;That's it — abusive bots get challenged at the edge while real users and search engines sail through.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deploy it in minutes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27873/how-to-block-bad-bots-with-safeline-waf</guid>
<pubDate>Mon, 21 Sep 2026 02:29:37 +0000</pubDate>
</item>
<item>
<title>How to Protect a Web Server with SafeLine WAF</title>
<link>https://coderlegion.com/27779/how-to-protect-a-web-server-with-safeline-waf</link>
<description>&lt;h2 id=&quot;how-to-protect-a-web-server-with-safeline-waf&quot;&gt;How to Protect a Web Server with SafeLine WAF&lt;/h2&gt;
&lt;p&gt;A web server — Nginx, Apache, Caddy, or an app server behind them — faces the same internet as everything else: injection attempts, scanners, and bots. SafeLine sits in front of that server as a self-hosted WAF reverse proxy, filtering traffic before it reaches your web server.&lt;/p&gt;
&lt;h3 id=&quot;the-setup&quot;&gt;The setup&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Client → SafeLine (inspects) → your web server (upstream) → app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your web server becomes the &lt;strong&gt;upstream&lt;/strong&gt;. SafeLine receives public traffic on :80 / :443, decides what is safe, and forwards clean requests to wherever your server actually listens.&lt;/p&gt;
&lt;h3 id=&quot;step-1-install-safeline&quot;&gt;Step 1 — Install SafeLine&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It runs as a container and is happy on a small host (1 CPU, 1 GB RAM, 5 GB disk minimum).&lt;/p&gt;
&lt;h3 id=&quot;step-2-point-safeline-at-your-web-server&quot;&gt;Step 2 — Point SafeLine at your web server&lt;/h3&gt;
&lt;p&gt;Open the console at &lt;code&gt;https://&amp;lt;safeline-ip&amp;gt;:9443&lt;/code&gt; and add a protected site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Upstream server&lt;/strong&gt; — your web server's address, e.g. &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; if it runs on the same host, or &lt;code&gt;http://10.0.0.5:80&lt;/code&gt; if it's elsewhere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain&lt;/strong&gt; — the hostname clients use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Port&lt;/strong&gt; — the public port SafeLine listens on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-3-send-traffic-through-safeline&quot;&gt;Step 3 — Send traffic through SafeLine&lt;/h3&gt;
&lt;p&gt;Either repoint DNS for the domain to the SafeLine host, or move your web server off the public port (to a localhost port) and let SafeLine take it. Traffic now flows Client → SafeLine → web server.&lt;/p&gt;
&lt;h3 id=&quot;what-it-blocks&quot;&gt;What it blocks&lt;/h3&gt;
&lt;p&gt;SafeLine's semantic-analysis engine inspects request intent, not just signatures. Out of the box it blocks SQL injection, XSS, code/command injection, path traversal, and automated abuse — for any web server behind it, regardless of language or framework.&lt;/p&gt;
&lt;h3 id=&quot;faq-17&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-it-matter-what-web-server-i-use-&quot;&gt;Does it matter what web server I use?&lt;/h4&gt;
&lt;p&gt;No — Nginx, Apache, Caddy, and app servers all work the same way, since SafeLine operates at the HTTP layer in front of them.&lt;/p&gt;
&lt;h4 id=&quot;will-legitimate-traffic-be-blocked-&quot;&gt;Will legitimate traffic be blocked?&lt;/h4&gt;
&lt;p&gt;Rarely. If a specific route trips a false positive, add a whitelist rule for that path instead of disabling protection.&lt;/p&gt;
&lt;h4 id=&quot;free-tier-limits-&quot;&gt;Free tier limits?&lt;/h4&gt;
&lt;p&gt;The Community Edition covers up to 10 apps at 800 QPS at no cost.&lt;/p&gt;
&lt;h4 id=&quot;can-one-safeline-protect-several-web-servers-&quot;&gt;Can one SafeLine protect several web servers?&lt;/h4&gt;
&lt;p&gt;Yes — each protected site maps its own domain to its own upstream.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;That's it — your web server now has a self-hosted WAF filtering traffic before it ever arrives.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deploy it in minutes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27779/how-to-protect-a-web-server-with-safeline-waf</guid>
<pubDate>Sun, 20 Sep 2026 01:42:16 +0000</pubDate>
</item>
<item>
<title>How to Configure SafeLine WAF as a Reverse Proxy</title>
<link>https://coderlegion.com/27602/how-to-configure-safeline-waf-as-a-reverse-proxy</link>
<description>&lt;h2 id=&quot;how-to-configure-safeline-waf-as-a-reverse-proxy&quot;&gt;How to Configure SafeLine WAF as a Reverse Proxy&lt;/h2&gt;
&lt;p&gt;SafeLine is a self-hosted WAF that works as a reverse proxy by design: it terminates your public traffic, inspects every request, and forwards only clean traffic to your real web server. This guide walks through configuring that proxy flow so your existing apps stay exactly where they are.&lt;/p&gt;
&lt;h3 id=&quot;how-the-traffic-flows&quot;&gt;How the traffic flows&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Client → SafeLine (listens :80 / :443) → upstream origin server (your app)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SafeLine sits in front. Your web server (Nginx, Apache, a Docker app, whatever) becomes the &lt;strong&gt;upstream&lt;/strong&gt; — the server SafeLine forwards to. The app never sees unfiltered traffic, and you don't have to change your app's code.&lt;/p&gt;
&lt;h3 id=&quot;step-1-install-safeline-1&quot;&gt;Step 1 — Install SafeLine&lt;/h3&gt;
&lt;p&gt;Run the one-line installer on a host that can reach your upstream server:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It pulls the container, starts the management console, and is happy on a small box (1 CPU, 1 GB RAM, 5 GB disk minimum).&lt;/p&gt;
&lt;h3 id=&quot;step-2-open-the-console-and-add-a-site&quot;&gt;Step 2 — Open the console and add a site&lt;/h3&gt;
&lt;p&gt;Open &lt;code&gt;https://&amp;lt;safeline-ip&amp;gt;:9443&lt;/code&gt; and go to the protected-sites section. Add a site with three pieces of information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Upstream server&lt;/strong&gt; — where your real app listens, e.g. &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; (if it runs on the same host) or &lt;code&gt;http://192.168.1.20:80&lt;/code&gt; (if it's on another machine).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain&lt;/strong&gt; — the hostname clients use, e.g. &lt;code&gt;app.example.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Port&lt;/strong&gt; — the port SafeLine should listen on publicly (usually 80 for HTTP, 443 if you attach a certificate).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SafeLine now knows: &quot;when traffic arrives for &lt;code&gt;app.example.com&lt;/code&gt; on port 80, inspect it and forward to &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt;.&quot;&lt;/p&gt;
&lt;h3 id=&quot;step-3-point-traffic-at-safeline&quot;&gt;Step 3 — Point traffic at SafeLine&lt;/h3&gt;
&lt;p&gt;Two common ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DNS&lt;/strong&gt;: point &lt;code&gt;app.example.com&lt;/code&gt; to the SafeLine host's IP instead of the origin's IP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Port / firewall&lt;/strong&gt;: if SafeLine is on the same host, stop your web server from binding the public port and let SafeLine take it, with the web server moved to a localhost port (the upstream above).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either way, new requests now pass through SafeLine first.&lt;/p&gt;
&lt;h3 id=&quot;step-4-verify-and-tune&quot;&gt;Step 4 — Verify and tune&lt;/h3&gt;
&lt;p&gt;The dashboard shows real-time request logs: allowed, blocked, and challenged. SafeLine's semantic-analysis engine blocks SQL injection, XSS, and automated abuse without signature tuning. If a specific path needs custom handling (a legacy API that trips a false positive), you can add a whitelist rule for that route.&lt;/p&gt;
&lt;h3 id=&quot;why-this-mode-is-convenient&quot;&gt;Why this mode is convenient&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Your app stays unchanged — SafeLine is purely in the network path.&lt;/li&gt;
&lt;li&gt;One SafeLine instance can proxy multiple upstreams (the free Community Edition covers 10 apps).&lt;/li&gt;
&lt;li&gt;You get a single inspection point and a single dashboard for everything behind it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;faq-18&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-safeline-replace-my-nginx-&quot;&gt;Does SafeLine replace my Nginx?&lt;/h4&gt;
&lt;p&gt;Not necessarily. Nginx can stay as the upstream; SafeLine just inspects traffic before it. Many run Nginx → SafeLine → app, or SafeLine → Nginx → app.&lt;/p&gt;
&lt;h4 id=&quot;what-about-https-&quot;&gt;What about HTTPS?&lt;/h4&gt;
&lt;p&gt;You can terminate TLS at SafeLine and forward plain HTTP to the upstream, or forward HTTPS through to the upstream untouched.&lt;/p&gt;
&lt;h4 id=&quot;is-there-a-request-limit-on-the-free-tier-&quot;&gt;Is there a request limit on the free tier?&lt;/h4&gt;
&lt;p&gt;The Community Edition handles up to 800 QPS across 10 protected apps at no cost.&lt;/p&gt;
&lt;h4 id=&quot;can-i-run-more-than-one-upstream-per-safeline-&quot;&gt;Can I run more than one upstream per SafeLine?&lt;/h4&gt;
&lt;p&gt;Yes — each protected site maps its own domain to its own upstream.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;That's it — your WAF is now running in front of your apps as a reverse proxy.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deploy it in minutes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27602/how-to-configure-safeline-waf-as-a-reverse-proxy</guid>
<pubDate>Fri, 18 Sep 2026 10:19:28 +0000</pubDate>
</item>
<item>
<title>How to Deploy a Self-Hosted WAF Alternative to Cloudflare</title>
<link>https://coderlegion.com/27329/how-to-deploy-a-self-hosted-waf-alternative-to-cloudflare</link>
<description>&lt;h2 id=&quot;how-to-deploy-a-self-hosted-waf-alternative-to-cloudflare&quot;&gt;How to Deploy a Self-Hosted WAF Alternative to Cloudflare&lt;/h2&gt;
&lt;p&gt;A self-hosted WAF means the inspection engine runs in your own environment, not a vendor's cloud. For teams that want control, privacy, or predictable cost, that is the whole point — and SafeLine is built exactly for this.&lt;/p&gt;
&lt;h3 id=&quot;what-self-hosted-buys-you&quot;&gt;What &quot;self-hosted&quot; buys you&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Traffic never leaves your network for inspection.&lt;/li&gt;
&lt;li&gt;No per-request billing.&lt;/li&gt;
&lt;li&gt;Your own dashboard, logs, and policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;safeline-specifically&quot;&gt;SafeLine specifically&lt;/h3&gt;
&lt;p&gt;SafeLine is deployed as a container that acts as a reverse proxy. Its semantic-analysis engine inspects each request for attack intent, blocking SQLi, XSS, and automated abuse before it reaches your app. The web console lives at &lt;code&gt;https://&amp;lt;ip&amp;gt;:9443&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;comparing-to-saas-wafs&quot;&gt;Comparing to SaaS WAFs&lt;/h3&gt;
&lt;p&gt;SaaS WAFs (Cloudflare, AWS WAF) win on zero-infra and global edges. Self-hosted wins on control and cost. SafeLine narrows the operational gap with a fast container install and a free Community Edition (10 apps / 800 QPS).&lt;/p&gt;
&lt;h3 id=&quot;faq-19&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;what-are-the-hardware-requirements-&quot;&gt;What are the hardware requirements?&lt;/h4&gt;
&lt;p&gt;1 CPU, 1 GB RAM, 5 GB disk — modest.&lt;/p&gt;
&lt;h4 id=&quot;can-it-sit-behind-my-existing-load-balancer-&quot;&gt;Can it sit behind my existing load balancer?&lt;/h4&gt;
&lt;p&gt;Yes; place it as the inspection tier before your upstreams.&lt;/p&gt;
&lt;h4 id=&quot;how-do-i-monitor-it-&quot;&gt;How do I monitor it?&lt;/h4&gt;
&lt;p&gt;The dashboard shows real-time logs and alerts; you can also export for your own SIEM.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deploy it in minutes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27329/how-to-deploy-a-self-hosted-waf-alternative-to-cloudflare</guid>
<pubDate>Wed, 16 Sep 2026 03:00:26 +0000</pubDate>
</item>
<item>
<title>SafeLine WAF: A Self-Hosted Alternative to Cloudflare You Can Run Yourself</title>
<link>https://coderlegion.com/27148/safeline-waf-a-self-hosted-alternative-to-cloudflare-you-can-run-yourself</link>
<description>&lt;p&gt;When people talk about protecting a website from bots, scrapers, and injection attacks, Cloudflare is usually the first name that comes up. It's a solid service — but it's not the only path, and for some teams it isn't even the best one. If you care about where your traffic flows, how much you pay as you grow, and keeping your logs on your own infrastructure, a &lt;strong&gt;self-hosted WAF&lt;/strong&gt; deserves a serious look. SafeLine WAF is one option in that category, and here we'll see where it fits as an alternative to a cloud WAF like Cloudflare.&lt;/p&gt;
&lt;h3 id=&quot;why-look-beyond-a-cloud-waf&quot;&gt;Why look beyond a cloud WAF&lt;/h3&gt;
&lt;p&gt;Cloud WAFs are convenient: sign up, point your DNS, done. But that convenience comes with trade-offs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Your traffic routes through someone else's network.&lt;/strong&gt; For teams with data-residency requirements or simply a preference for self-control, that's a real concern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost scales with usage.&lt;/strong&gt; Many cloud WAFs bill per request or per feature tier, so a traffic spike can mean a surprising invoice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You depend on their UI and rate limits&lt;/strong&gt; for day-to-day changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of that is a reason to avoid cloud WAFs outright — but it explains why a growing number of teams evaluate self-hosted options.&lt;/p&gt;
&lt;h3 id=&quot;what-safeline-waf-is&quot;&gt;What SafeLine WAF is&lt;/h3&gt;
&lt;p&gt;SafeLine WAF is a self-hosted Web Application &amp;amp; API Protection (WAAP) solution by Chaitin. Instead of running in a vendor's cloud, it runs on your own infrastructure — typically deployed with a single Docker Compose file. Key points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free to start.&lt;/strong&gt; The Community Edition covers up to &lt;strong&gt;10 applications and 800 QPS&lt;/strong&gt; at no cost, with no per-request billing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paid tiers for scale.&lt;/strong&gt; Lite (~$10/month, 20 apps) and Pro (~$100/month, unlimited apps) unlock more capacity and features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You keep your data.&lt;/strong&gt; Traffic inspection and logs stay on your servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible rules and an open API&lt;/strong&gt; let you script policy and site management instead of clicking through a UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;safeline-vs-cloudflare-the-practical-differences&quot;&gt;SafeLine vs Cloudflare: the practical differences&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Dimension &lt;/th&gt;&lt;th&gt;Self-hosted (SafeLine) &lt;/th&gt;&lt;th&gt;Cloud WAF (Cloudflare)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Where traffic is inspected &lt;/td&gt;&lt;td&gt;Your infrastructure &lt;/td&gt;&lt;td&gt;Cloudflare's network&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cost model &lt;/td&gt;&lt;td&gt;Predictable (your servers) &lt;/td&gt;&lt;td&gt;Per request / per tier&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Log location &lt;/td&gt;&lt;td&gt;On your servers &lt;/td&gt;&lt;td&gt;Vendor's platform&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rule changes &lt;/td&gt;&lt;td&gt;API or UI, your pace &lt;/td&gt;&lt;td&gt;Vendor's UI and limits&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Setup &lt;/td&gt;&lt;td&gt;Docker Compose &lt;/td&gt;&lt;td&gt;DNS change + account&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This isn't &quot;one is better&quot; — it's about fit. Cloudflare shines when you want a hands-off CDN + WAF combo. SafeLine shines when you want control, predictable cost, and data sovereignty.&lt;/p&gt;
&lt;h3 id=&quot;getting-started-1&quot;&gt;Getting started&lt;/h3&gt;
&lt;p&gt;Installation is a one-liner (English install):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash -c &quot;$(curl -fsSLk https://waf.chaitin.com/release/latest/manager.sh)&quot; -- --en
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After deployment, the management console is available at &lt;code&gt;https://&amp;lt;your-server-ip&amp;gt;:9443&lt;/code&gt;. You can explore the interface without installing anything via the &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;live demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;SafeLine sits in front of your sites as a reverse proxy, so it can filter and block malicious requests before they reach your application — the same job a cloud WAF does, just on infrastructure you own.&lt;/p&gt;
&lt;h3 id=&quot;who-should-consider-it&quot;&gt;Who should consider it&lt;/h3&gt;
&lt;p&gt;A self-hosted WAF is a great fit if you already run your own servers and have someone comfortable with Docker, Nginx, and basic monitoring. A single node protecting a handful of sites is close to plug-and-play; a multi-node cluster protecting many production domains benefits from investing in monitoring and runbooks.&lt;/p&gt;
&lt;h3 id=&quot;faq-20&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;is-safeline-actually-free-&quot;&gt;Is SafeLine actually free?&lt;/h4&gt;
&lt;p&gt;The Community Edition protects up to 10 applications at 800 QPS with no request-based fees. Paid tiers add capacity and features when you outgrow it.&lt;/p&gt;
&lt;h4 id=&quot;do-i-have-to-replace-my-existing-reverse-proxy-&quot;&gt;Do I have to replace my existing reverse proxy?&lt;/h4&gt;
&lt;p&gt;No. SafeLine works as a reverse proxy in front of your services, so you can keep Nginx or your current setup behind it.&lt;/p&gt;
&lt;h4 id=&quot;how-is-this-different-from-just-using-cloudflare-&quot;&gt;How is this different from just using Cloudflare?&lt;/h4&gt;
&lt;p&gt;The core difference is ownership: inspection and logs stay on your infrastructure, and cost is predictable rather than tied to request volume.&lt;/p&gt;
&lt;h4 id=&quot;can-it-handle-production-traffic-&quot;&gt;Can it handle production traffic?&lt;/h4&gt;
&lt;p&gt;Yes, with the right edition and sizing. Start on Community for lower volumes, then move to Lite or Pro as traffic grows.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Thinking about bringing your edge protection in-house?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27148/safeline-waf-a-self-hosted-alternative-to-cloudflare-you-can-run-yourself</guid>
<pubDate>Mon, 14 Sep 2026 11:05:54 +0000</pubDate>
</item>
<item>
<title>What Happens When Every AI Tool You Use Shares One Brain?</title>
<link>https://coderlegion.com/26357/what-happens-when-every-ai-tool-you-use-shares-one-brain</link>
<description>&lt;p&gt;I was working across a growing pile of AI tools, and each one built its own little fiefdom of knowledge. Claude had Projects, Perplexity had Spaces, and my coding agents knew whatever happened to be on the local filesystem. My notes and todo lists lived in Obsidian, my bright ideas in AI &quot;projects,&quot; and my coding ideas in chat history I could never find. Each tool knew exactly what I'd told it in that session and nothing more, so every new conversation started with me re-explaining the history of what I was doing.&lt;/p&gt;
&lt;p&gt;Then my colleague and friend Siva showed me his second brain. He'd built his on Notion, wired his AI tools into it, automated capturing information, and could ask questions against everything he'd collected. I had to have one.&lt;/p&gt;
&lt;p&gt;But not his... My constraints ruled his out (and I just had to be different, because). No new notetaking tool: I already lived in Obsidian and wasn't migrating (again). No cloud subscription to glue it together. And whatever I built had to run on my home server, because I run one anyway and self-hosting is half the fun (pain?).&lt;/p&gt;
&lt;p&gt;What I ended up with is a plain folder of Markdown files fronted by a Model Context Protocol (MCP) server that lets any AI agent read and search it, synced to my devices through Obsidian Sync. My personal AI tools now share one brain. What follows is how I built it, what I almost built instead, and what a month of living with it has been like.&lt;/p&gt;
&lt;h3 id=&quot;key-insights&quot;&gt;Key insights&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It works way better than I anticipated. Agents move around the vault comfortably, powered mostly by keyword (lexical) and semantic search covering for each other: one finds the exact phrase, the other lets me be vague and &quot;let the AI figure it out.&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plain Markdown turned out to be the universal language between AI and human. Every tool reads it, every tool writes it, and I can open any note myself without going through an agent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A month in, the vault powers all my side quests and personal knowledge work, and I can't work without it now.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-i-considered&quot;&gt;What I considered&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The AI-first memory platforms.&lt;/strong&gt; Tools like mem0, Supermemory, or LangMem pitch themselves as second brains, but they're built as memory for agents: the AI reads and writes, and human interaction isn't at the forefront. Those have real value, and I even piloted mem0, but I wanted a personal wiki I could browse and edit myself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Obsidian MCP servers.&lt;/strong&gt; Since my notes already lived in Obsidian, this looked like the shortest path. However, everything I found either required the Obsidian desktop app running (via the Local REST API plugin), spoke stdio only, or needed a proxy bridge glued on top. All I really needed was a Markdown MCP: something that treats a folder of Markdown files as the vault, with search and auth. Requiring a desktop app to keep a headless server alive sounded fragile (which is what Notion solves out of the box, FWIW).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud-native platforms.&lt;/strong&gt; Notion and friends are probably the fastest way to get going, but adopting one meant a new notetaking tool and a cloud subscription: the two constraints I started with. Everything I had lived in Obsidian, so &quot;quick to start&quot; would have come with a migration attached and a bill.&lt;/p&gt;
&lt;p&gt;Nothing really fit, so I assembled my own stack.&lt;/p&gt;
&lt;h3 id=&quot;the-build&quot;&gt;The build&lt;/h3&gt;
&lt;p&gt;The assembled stack is one Docker Compose file on my home server, three services:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  mcp:         # markdown-vault-mcp: serves the vault over MCP, with search
  sync:        # obsidian-headless CLI in a Node container: keeps my devices in sync
  cloudflared: # Cloudflare Tunnel connector: outbound-only exposure
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Trimmed for print. The real one has the usual volumes, env vars, and healthchecks.)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mcp&lt;/code&gt; service runs &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/pvliesdonk/markdown-vault-mcp&quot;&gt;markdown-vault-mcp&lt;/a&gt;, an open-source MCP server that treats a plain folder of Markdown files as the vault. It adds keyword search via FTS5, and pointing it at an embedding model adds semantic search; embedding the entire vault costs pennies. The &lt;code&gt;sync&lt;/code&gt; service runs the official &lt;a rel=&quot;nofollow&quot; href=&quot;https://obsidian.md/help/headless&quot;&gt;obsidian-headless CLI&lt;/a&gt; against the Obsidian Sync subscription I already had, so anything an agent writes lands on my phone and laptops like any other note. I did have to do an initial &quot;login and setup&quot; ritual inside the sync container, but it has run seamlessly since.&lt;/p&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/cloudflare/cloudflared&quot;&gt;&lt;code&gt;cloudflared&lt;/code&gt;&lt;/a&gt; service deserves some emphasis. A Cloudflare Tunnel is outbound-only: my server calls out to Cloudflare, so there are no inbound ports to open and no public IP to worry about. When the stack is down, nothing is exposed at all, which is way better than leaving a forwarded port hanging around &quot;temporarily&quot; for months.&lt;/p&gt;
&lt;p&gt;For auth, I didn't want to hand a pre-shared API key to every tool I connect, so I put OAuth in front of it through Google, using my GCP account. Connecting a new tool now means a Google login instead of a copy-pasted secret.&lt;/p&gt;
&lt;p&gt;Two key decisions I made. The MCP server mounts only a subfolder of the vault, so agents can't see (ruin) anything outside it, while the &lt;code&gt;sync&lt;/code&gt; service mounts the root. Consistency across tools lives in the vault itself: an &lt;code&gt;AGENTS.md&lt;/code&gt; at the root, plus instructions the server ships to every client when it connects. Consistent rules across agents for consistent results.&lt;/p&gt;
&lt;p&gt;One side confession: in the first days, performance was awful, so I spent way too much time blaming a non-existent Cloudflare outage instead of the actual culprit: the Rancher Desktop VM was undersized for the vault and everything else running on it. Scaled it up, and the flakiness vanished.&lt;/p&gt;
&lt;h3 id=&quot;connecting-the-agents&quot;&gt;Connecting the agents&lt;/h3&gt;
&lt;p&gt;With the stack running, connecting a tool is routine: add an MCP connector, auth with Google, start hoarding brilliant ideas and lists. I connected Perplexity right away and it's been my primary workhorse since. Grok, Antigravity, and GitHub Copilot quickly followed, so I could take one of those ideas to implementation. Gemini Spark is connected too, though it's only run simple tests so far.&lt;/p&gt;
&lt;p&gt;I did not connect Claude and Claude Code. Those are work tools, and I try my best to keep work and personal systems apart. All of my clients now have their own AI use policies, security requirements, NDAs and more, so having their IP leak into a side quest would be bad.&lt;/p&gt;
&lt;p&gt;Since the server ships the same instructions to every client at connect time, each tool plays by the same rules. When I change the rules, I change them once. This was one of the wise decisions from the OG designers of MCP.&lt;/p&gt;
&lt;h3 id=&quot;a-month-in&quot;&gt;A month in&lt;/h3&gt;
&lt;p&gt;The vault has settled in as the default starting point for my side quests. Every project gets its own notes, so picking a quest back up after weeks of neglect no longer means digging through extensive chat histories. My to-do list lives there, and so does the running list of &quot;brilliant ideas,&quot; which grows much faster than I'll ever build them.&lt;/p&gt;
&lt;p&gt;The surprise of the project has been the search. I expected the agents to churn and waste tokens mining data from the vault. The pairing of keyword and semantic search is the true power behind it. I can just describe what a note is about rather than what it says, and the agent finds it every time.&lt;/p&gt;
&lt;p&gt;A folder of Markdown files, a sync container, and a tunnel gave every AI tool I use a shared memory that I can read myself. Total spend: a few pennies of embeddings, since everything else runs on subscriptions and hardware I already had. If your AI tools each keep their own little fiefdom, stand up your own stack!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26357/what-happens-when-every-ai-tool-you-use-shares-one-brain</guid>
<pubDate>Mon, 07 Sep 2026 00:04:43 +0000</pubDate>
</item>
<item>
<title>OIDC Authentication with Keycloak (and Auth0, Okta, Azure AD)</title>
<link>https://coderlegion.com/24810/oidc-authentication-with-keycloak-and-auth0-okta-azure-ad</link>
<description>&lt;p&gt;If your team already runs an identity provider, the last thing you want is a second login system. You want your apps to trust the identity system you already have — whether that's Keycloak, Auth0, Okta, or Azure AD. OpenID Connect (OIDC) is the protocol that makes that possible, and a self-hosted WAF can speak it for you.&lt;/p&gt;
&lt;p&gt;SafeLine supports OIDC out of the box. Instead of adding an OIDC client library to each app, you configure the identity provider once in the WAF, and it handles the redirect and the login gate in front of your applications. Here's the setup, straight from the docs.&lt;/p&gt;
&lt;h3 id=&quot;what-oidc-actually-is&quot;&gt;What OIDC actually is&lt;/h3&gt;
&lt;p&gt;OpenID Connect is an identity layer built on top of OAuth 2.0. It lets a client application verify who a user is, based on the authentication result from an authorization server — and get back basic user information — without the client ever handling the user's credentials directly.&lt;/p&gt;
&lt;p&gt;For a WAF, that's a clean fit: the WAF fronts your app, redirects unauthenticated visitors to your identity provider, and only lets approved users through.&lt;/p&gt;
&lt;h3 id=&quot;step-1-prepare-your-oidc-provider&quot;&gt;Step 1: Prepare your OIDC provider&lt;/h3&gt;
&lt;p&gt;The docs walk through Keycloak as the reference example, since it's a common self-hosted choice. Here's how to get the parameters SafeLine needs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to the Keycloak admin console.&lt;/li&gt;
&lt;li&gt;Select or create a &lt;strong&gt;Realm&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the left menu, click &lt;strong&gt;Clients → Create&lt;/strong&gt; to create a new client.&lt;/li&gt;
&lt;li&gt;Fill in a &lt;strong&gt;Client ID&lt;/strong&gt; — a unique identifier for the client.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Settings&lt;/strong&gt; tab:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Valid Redirect URIs&lt;/strong&gt; — add the application's callback address, for example &lt;code&gt;https://example.com/.safeline/auth/api/callback/oidc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Origins&lt;/strong&gt; — add the application address, for example &lt;code&gt;https://example.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Save, then switch to the &lt;strong&gt;Credentials&lt;/strong&gt; tab and copy the &lt;strong&gt;Client Secret&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key things to record:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Parameter &lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OIDC Discovery URL&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;https://{keycloak-host}/realms/{realm-name}&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Client ID&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;The client ID you created&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Client Secret&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;The secret from the Credentials tab&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;The callback path is fixed: append &lt;code&gt;/.safeline/auth/api/callback/oidc&lt;/code&gt; to your application URL.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-2-configure-safeline&quot;&gt;Step 2: Configure SafeLine&lt;/h3&gt;
&lt;p&gt;In the SafeLine console, go to &lt;strong&gt;Auth → Settings → Login Configuration&lt;/strong&gt;, find &lt;strong&gt;Third-Party Login&lt;/strong&gt;, and select &lt;strong&gt;OIDC&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Fill in the form:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Field &lt;/th&gt;&lt;th&gt;What it's for&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OIDC Server URL&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Your provider's discovery URL. SafeLine appends &lt;code&gt;.well-known/openid-configuration&lt;/code&gt; automatically&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Client ID&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;From your OIDC provider&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Client Secret&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;From your OIDC provider&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Title Name&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Shown on the blocking page — defaults to &quot;Sign In - OIDC&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Use Proxy to Access&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Check if your requests go through a proxy&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Auto Merge Account&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Automatically match incoming logins to existing accounts by email or phone number&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Click &lt;strong&gt;Submit&lt;/strong&gt; to save the binding.&lt;/p&gt;
&lt;h3 id=&quot;step-3-enable-oidc-on-the-application&quot;&gt;Step 3: Enable OIDC on the application&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Applications&lt;/strong&gt; and pick the app you want to protect.&lt;/li&gt;
&lt;li&gt;In that app's &lt;strong&gt;AUTH → Login Methods&lt;/strong&gt; configuration, enable &lt;strong&gt;OIDC&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Save.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-the-login-flow-looks-like&quot;&gt;What the login flow looks like&lt;/h3&gt;
&lt;p&gt;Once OIDC is enabled for an application:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A visitor opens the app and sees the OIDC login option.&lt;/li&gt;
&lt;li&gt;Clicking it redirects them to your identity provider's login page.&lt;/li&gt;
&lt;li&gt;After authenticating there, they're redirected back to SafeLine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First-time users&lt;/strong&gt; need to be approved by a SafeLine administrator before they can access the app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Approved users&lt;/strong&gt; get authorized and don't need another review for later visits; &lt;strong&gt;unapproved users&lt;/strong&gt; are blocked.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;managing-users&quot;&gt;Managing users&lt;/h3&gt;
&lt;p&gt;On &lt;strong&gt;AUTH → User Management&lt;/strong&gt; you can view which users are linked, review new users, manage access permissions, and manually merge accounts.&lt;/p&gt;
&lt;h3 id=&quot;faq-21&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;can-t-redirect-to-the-oidc-provider-after-integration-&quot;&gt;Can't redirect to the OIDC provider after integration?&lt;/h4&gt;
&lt;p&gt;Check that the OIDC discovery URL is correct and that it's reachable from a browser and returns valid JSON.&lt;/p&gt;
&lt;h4 id=&quot;callback-fails-after-the-user-authenticates-with-the-provider-&quot;&gt;Callback fails after the user authenticates with the provider?&lt;/h4&gt;
&lt;p&gt;Confirm the callback address is configured correctly — protocol (&lt;code&gt;http&lt;/code&gt;/&lt;code&gt;https&lt;/code&gt;), domain, and path all need to match.&lt;/p&gt;
&lt;h4 id=&quot;what-scopes-does-safeline-request-by-default-&quot;&gt;What scopes does SafeLine request by default?&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;openid&lt;/code&gt;, &lt;code&gt;profile&lt;/code&gt;, and &lt;code&gt;email&lt;/code&gt; (optional, used to link accounts), plus &lt;code&gt;phone&lt;/code&gt; (optional, for account linking).&lt;/p&gt;
&lt;h4 id=&quot;do-i-need-to-write-oidc-code-in-my-app-&quot;&gt;Do I need to write OIDC code in my app?&lt;/h4&gt;
&lt;p&gt;Not for the login gate itself. The WAF handles the redirect flow. You'd only add app code if the application needs the authenticated user's identity — via the auth callback flow.&lt;/p&gt;
&lt;h4 id=&quot;which-providers-are-supported-&quot;&gt;Which providers are supported?&lt;/h4&gt;
&lt;p&gt;The docs name Keycloak, Auth0, Okta, and Azure AD, and note the list isn't limited to those — anything speaking standard OIDC should work.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;If you already run Keycloak, Auth0, Okta, or Azure AD — are your internal apps currently trusting it, or are you maintaining a second login system?&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24810/oidc-authentication-with-keycloak-and-auth0-okta-azure-ad</guid>
<pubDate>Tue, 18 Aug 2026 03:52:19 +0000</pubDate>
</item>
<item>
<title>How to Add GitHub Login to Your Web App with a WAF</title>
<link>https://coderlegion.com/24808/how-to-add-github-login-to-your-web-app-with-a-waf</link>
<description>&lt;p&gt;&quot;Sign in with GitHub&quot; is one of the first things developers reach for when an internal tool needs authentication. The usual route is a real engineering task: register a GitHub OAuth app, add an OAuth client library to your codebase, store the &lt;code&gt;ClientID&lt;/code&gt; and &lt;code&gt;ClientSecret&lt;/code&gt;, implement the callback handler, and manage sessions yourself.&lt;/p&gt;
&lt;p&gt;There's a shorter path. If you front your web app with a self-hosted WAF that runs as a reverse proxy, you can let the WAF handle the entire GitHub OAuth flow — before a single request reaches your application code. SafeLine does exactly this. Here's the full walkthrough, straight from the docs.&lt;/p&gt;
&lt;h3 id=&quot;why-do-github-login-at-the-waf-layer-&quot;&gt;Why do GitHub login at the WAF layer?&lt;/h3&gt;
&lt;p&gt;A WAF already sits in front of your app, so every request passes through it. That makes it a natural place to gate access. Letting the WAF handle GitHub authentication means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No OAuth code in your app.&lt;/strong&gt; You don't add a client library, a callback route, or token storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One place to manage identity.&lt;/strong&gt; Add or remove GitHub login across several apps from one console.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It works for anything.&lt;/strong&gt; An internal dashboard, a legacy tool, or a static site can all get GitHub login the same way.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1-create-the-github-oauth-app&quot;&gt;Step 1: Create the GitHub OAuth app&lt;/h3&gt;
&lt;p&gt;First you need a GitHub OAuth application to act as the identity source. This is done on GitHub's side, not SafeLine's.&lt;/p&gt;
&lt;p&gt;From the GitHub documentation flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to GitHub and click your profile picture, then open &lt;strong&gt;Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the left sidebar, click &lt;strong&gt;Developer Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OAuth Apps&lt;/strong&gt;, then &lt;strong&gt;New OAuth App&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fill in the application form:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application name&lt;/strong&gt; — what users see on the authentication page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Homepage URL&lt;/strong&gt; — your application's URL, for example &lt;code&gt;https://a.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorization callback URL&lt;/strong&gt; — your homepage URL with &lt;code&gt;/.safeline/auth/api/callback/github&lt;/code&gt; appended. For the example above: &lt;code&gt;https://a.com/.safeline/auth/api/callback/github&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once created, GitHub gives you the two values you'll need next: a &lt;strong&gt;ClientID&lt;/strong&gt; and a &lt;strong&gt;ClientSecret&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The callback URL is the one place people get stuck. It's not arbitrary — it's always your Homepage URL plus the fixed path &lt;code&gt;/.safeline/auth/api/callback/github&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;step-2-configure-safeline-1&quot;&gt;Step 2: Configure SafeLine&lt;/h3&gt;
&lt;p&gt;Now move to the SafeLine console. Go to &lt;strong&gt;Auth → Settings → Login Configuration&lt;/strong&gt;, find &lt;strong&gt;Third-Party Login&lt;/strong&gt;, and select &lt;strong&gt;GitHub&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Fill in the configuration form:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Field &lt;/th&gt;&lt;th&gt;What it's for&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ClientID&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Your GitHub application ID&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ClientSecret&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Your GitHub application secret&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Title Name&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;The name shown on the blocking page — defaults to &quot;Sign In - GitHub&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Use Proxy to Access&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Check this if your requests need to go through a proxy&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Auto Merge Account&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Automatically match incoming GitHub logins to existing accounts by email&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Click &lt;strong&gt;Submit&lt;/strong&gt; to save the binding.&lt;/p&gt;
&lt;h3 id=&quot;step-3-enable-github-on-the-application&quot;&gt;Step 3: Enable GitHub on the application&lt;/h3&gt;
&lt;p&gt;Configuring the GitHub source isn't enough — you also have to switch it on for the specific app:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Applications&lt;/strong&gt; page and select the application you want to protect.&lt;/li&gt;
&lt;li&gt;In that application's &lt;strong&gt;AUTH&lt;/strong&gt; page, open the &lt;strong&gt;Login Methods&lt;/strong&gt; settings.&lt;/li&gt;
&lt;li&gt;Enable the &lt;strong&gt;GitHub&lt;/strong&gt; option.&lt;/li&gt;
&lt;li&gt;Save.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it. The app is now gated behind GitHub authentication.&lt;/p&gt;
&lt;h3 id=&quot;what-happens-when-a-user-tries-to-log-in&quot;&gt;What happens when a user tries to log in&lt;/h3&gt;
&lt;p&gt;Once the AUTH feature is enabled and GitHub is selected as the login method, the flow looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When someone visits the app, they're prompted to authenticate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New users&lt;/strong&gt; authenticate, then need to be &lt;strong&gt;reviewed and approved by a SafeLine administrator&lt;/strong&gt; in the console before they can get in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Approved users&lt;/strong&gt; are authorized for the app and don't need another review — subsequent logins just work after authentication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unapproved users&lt;/strong&gt; are blocked when they try to access the app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That approval step is a useful default: it stops an open GitHub login from becoming a backdoor for anyone with a GitHub account.&lt;/p&gt;
&lt;h3 id=&quot;managing-users-after-login&quot;&gt;Managing users after login&lt;/h3&gt;
&lt;p&gt;On the &lt;strong&gt;AUTH → User Management&lt;/strong&gt; page you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;See whether users have linked their GitHub accounts.&lt;/li&gt;
&lt;li&gt;Review new users for approval.&lt;/li&gt;
&lt;li&gt;Manage access permissions per user.&lt;/li&gt;
&lt;li&gt;Manually merge user accounts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;merge&quot; option is handy when someone has been logging in one way and you want to fold their history into another account.&lt;/p&gt;
&lt;h3 id=&quot;optional-combine-it-with-sso&quot;&gt;Optional: combine it with SSO&lt;/h3&gt;
&lt;p&gt;If you want users to authenticate just once and then reach &lt;em&gt;several&lt;/em&gt; applications, GitHub login can feed into SSO:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;AUTH → Settings → SSO&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enable the unified authentication feature.&lt;/li&gt;
&lt;li&gt;Add applications to unified authentication.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After that, a user authenticates once — including through GitHub — and can access every application that's joined SSO.&lt;/p&gt;
&lt;h3 id=&quot;faq-22&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;do-i-have-to-write-any-application-code-for-github-login-&quot;&gt;Do I have to write any application code for GitHub login?&lt;/h4&gt;
&lt;p&gt;Not for the login itself. The WAF handles the OAuth redirect and gatekeeping. Your app only needs custom code if it has to &lt;em&gt;know who&lt;/em&gt; logged in — for that you'd use the auth callback flow.&lt;/p&gt;
&lt;h4 id=&quot;why-does-a-new-github-user-need-admin-approval-&quot;&gt;Why does a new GitHub user need admin approval?&lt;/h4&gt;
&lt;p&gt;It's the default safety behavior: first-time users trigger a review so an admin can confirm who gets access. After approval, the same user logs in without further review.&lt;/p&gt;
&lt;h4 id=&quot;can-i-use-github-login-on-more-than-one-app-&quot;&gt;Can I use GitHub login on more than one app?&lt;/h4&gt;
&lt;p&gt;Yes. You configure the GitHub source once, then enable it on each application individually from that app's AUTH → Login Methods settings.&lt;/p&gt;
&lt;h4 id=&quot;what-if-my-traffic-goes-through-a-proxy-&quot;&gt;What if my traffic goes through a proxy?&lt;/h4&gt;
&lt;p&gt;Check the &lt;strong&gt;Use Proxy to Access&lt;/strong&gt; option in the GitHub login configuration. That tells SafeLine to route its GitHub calls through a proxy.&lt;/p&gt;
&lt;h4 id=&quot;does-github-login-work-together-with-other-login-methods-&quot;&gt;Does GitHub login work together with other login methods?&lt;/h4&gt;
&lt;p&gt;Yes. SafeLine supports several login methods (account/password, OIDC, LDAP, and GitHub), and you can enable more than one for an application.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Have you wired up &quot;Sign in with GitHub&quot; the hard way before — and would you move that identity layer out of your code and into the WAF?&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24808/how-to-add-github-login-to-your-web-app-with-a-waf</guid>
<pubDate>Tue, 18 Aug 2026 03:48:38 +0000</pubDate>
</item>
<item>
<title>Add Authentication and SSO to Any Web App Without Changing Code</title>
<link>https://coderlegion.com/24793/add-authentication-and-sso-to-any-web-app-without-changing-code</link>
<description>&lt;p&gt;Most people treat authentication as an application problem. If an internal dashboard, an admin panel, or a legacy tool doesn't have a login screen, the reflex is to open the codebase and start wiring up an auth library — OAuth clients, session management, user tables, password resets, the whole thing.&lt;/p&gt;
&lt;p&gt;That's a lot of work to do &lt;em&gt;once&lt;/em&gt;, and it's even worse when you have ten different apps that all need it.&lt;/p&gt;
&lt;p&gt;There's a faster way: put the authentication layer in front of your apps instead of inside them. A self-hosted WAF that sits as a reverse proxy in front of your services can handle login for you — before a single request ever reaches your application code.&lt;/p&gt;
&lt;p&gt;Here's how SafeLine does it, and how you can add both password protection and full SSO to any web app without touching its source.&lt;/p&gt;
&lt;h3 id=&quot;why-do-auth-at-the-waf-layer-&quot;&gt;Why do auth at the WAF layer?&lt;/h3&gt;
&lt;p&gt;A WAF is a reverse proxy: clients connect to the WAF first, the WAF filters and forwards traffic to your origin server. Because every request already flows &lt;em&gt;through&lt;/em&gt; it, the WAF is a natural place to gate access.&lt;/p&gt;
&lt;p&gt;That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No code changes.&lt;/strong&gt; The app behind the WAF doesn't need an auth library, a user table, or any login UI of its own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One place to manage.&lt;/strong&gt; Instead of maintaining credentials in ten apps, you manage them in one console.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It works for anything.&lt;/strong&gt; Legacy apps, static sites, internal tools, APIs — anything the WAF fronts can be protected.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SafeLine provides two authentication modes to cover different situations: &lt;strong&gt;Simple Auth&lt;/strong&gt; and &lt;strong&gt;SSO&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;simple-auth-vs-sso-two-ways-to-gate-access&quot;&gt;Simple Auth vs SSO: two ways to gate access&lt;/h3&gt;
&lt;p&gt;SafeLine gives you two distinct modes, and the difference comes down to scope:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simple Auth&lt;/strong&gt; is application-specific. A user logs in to access &lt;em&gt;that one&lt;/em&gt; application. If they move to a different app, they authenticate again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSO (Single Sign-On)&lt;/strong&gt; is the opposite. A user logs in once and then accesses &lt;em&gt;multiple&lt;/em&gt; related applications without repeated logins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of Simple Auth as &quot;lock this one door,&quot; and SSO as &quot;issue one badge that opens every door you're allowed into.&quot;&lt;/p&gt;
&lt;h3 id=&quot;simple-auth-password-protect-a-single-app&quot;&gt;Simple Auth: password-protect a single app&lt;/h3&gt;
&lt;p&gt;With Simple Auth turned on for an application, visitors must enter valid credentials before they can reach the app. Anyone who doesn't hold the credentials is blocked.&lt;/p&gt;
&lt;p&gt;When you configure Simple Auth for an application, you pick a &lt;strong&gt;login method&lt;/strong&gt; and set an &lt;strong&gt;Auth Callback URL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The login method is how users prove who they are. SafeLine supports four:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Account + Password&lt;/strong&gt; — a basic username/password login.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt; — sign in with a GitHub account.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OIDC&lt;/strong&gt; — sign in through an OpenID Connect identity provider.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LDAP&lt;/strong&gt; — sign in with an existing enterprise directory account.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;Auth Callback URL&lt;/strong&gt; is what lets you pass the authenticated user's identity into your app, which I'll cover in detail below.&lt;/p&gt;
&lt;h3 id=&quot;sso-one-login-every-app&quot;&gt;SSO: one login, every app&lt;/h3&gt;
&lt;p&gt;SSO is where this gets genuinely useful for teams. Once unified authentication is enabled, your users get a single sign-in entry point — an SSO center — and from there they can reach every application that has joined.&lt;/p&gt;
&lt;p&gt;The docs describe three business scenarios where this fits naturally:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enterprise application portal.&lt;/strong&gt; Internal systems like OA, HR, and CRM each have their own auth today. With SSO, employees log in once and reach all of them, while IT centralizes access policy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modernizing legacy apps.&lt;/strong&gt; Older apps often have no built-in auth, or a dated mechanism. SSO adds a modern authentication layer on top &lt;em&gt;without modifying application code&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero trust.&lt;/strong&gt; SSO is a core piece of a zero-trust architecture, giving every application access a consistent identity-verification and authorization path.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;enabling-sso&quot;&gt;Enabling SSO&lt;/h4&gt;
&lt;p&gt;You enable SSO from the &lt;strong&gt;Auth-Settings&lt;/strong&gt; page under the SSO tab. The configuration is a handful of fields:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Field &lt;/th&gt;&lt;th&gt;What it's for&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Domain&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;The domain users visit to reach the unified authentication center (e.g. &lt;code&gt;home.in.example.cn&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Port&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;An available port for the center&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SSL&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Optional, for HTTPS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Login Methods&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;The identity methods available (multiple can be enabled)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Force Enable TOTP&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;When on, &lt;em&gt;every&lt;/em&gt; SSO user must use TOTP for two-factor authentication&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Once enabled, users in the user list can access the SSO center by default.&lt;/p&gt;
&lt;h4 id=&quot;adding-apps-to-sso&quot;&gt;Adding apps to SSO&lt;/h4&gt;
&lt;p&gt;To bring an application into SSO, go to &lt;strong&gt;Applications&lt;/strong&gt;, click the app's &lt;strong&gt;AUTH&lt;/strong&gt; button, and switch it over. Then you configure two fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application Redirect URL&lt;/strong&gt; — where the user is sent when they click the app in the SSO center.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Callback URL&lt;/strong&gt; — how authentication info is passed to the app server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, when a user visits an application for the first time, they authenticate once. From then on, that one authentication covers every authorized application that has joined SSO.&lt;/p&gt;
&lt;p&gt;A few details worth knowing from the SSO docs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is &lt;strong&gt;no limit&lt;/strong&gt; on how many applications can join SSO.&lt;/li&gt;
&lt;li&gt;You can edit an application's name and logo in the SSO center.&lt;/li&gt;
&lt;li&gt;Users can only access applications they have permission for — joining SSO doesn't grant access to everything by default.&lt;/li&gt;
&lt;li&gt;Logging out of the SSO center is &lt;strong&gt;not&lt;/strong&gt; SLO (single logout) — that's not currently supported.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-four-login-methods&quot;&gt;The four login methods&lt;/h3&gt;
&lt;p&gt;Whichever mode you use, the actual identity check is done by one of four methods.&lt;/p&gt;
&lt;h4 id=&quot;account-password&quot;&gt;Account + Password&lt;/h4&gt;
&lt;p&gt;The simplest option. You configure a username and password, and visitors enter it to get through. It's a good fit for a single admin or a small set of trusted users.&lt;/p&gt;
&lt;h4 id=&quot;github&quot;&gt;GitHub&lt;/h4&gt;
&lt;p&gt;SafeLine can let users sign in with their GitHub identity. You create a GitHub OAuth application to get a &lt;code&gt;ClientID&lt;/code&gt; and &lt;code&gt;ClientSecret&lt;/code&gt;, then fill those into SafeLine's third-party login configuration. The callback URL for GitHub follows the pattern:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://your-app.com/.safeline/auth/api/callback/github
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There's also an &quot;Auto Merge Account&quot; option to match incoming GitHub logins to existing accounts by email.&lt;/p&gt;
&lt;h4 id=&quot;oidc&quot;&gt;OIDC&lt;/h4&gt;
&lt;p&gt;For organizations that already run an identity provider, SafeLine speaks OpenID Connect. The docs call out Keycloak, Auth0, Okta, and Azure AD as supported providers.&lt;/p&gt;
&lt;p&gt;Configuring it means pointing SafeLine at your provider's discovery URL (for Keycloak, something like &lt;code&gt;https://{keycloak-host}/realms/{realm-name}&lt;/code&gt;) plus a Client ID and Client Secret. This is the method to reach for when you want your apps to trust the identity system you already have.&lt;/p&gt;
&lt;h4 id=&quot;ldap&quot;&gt;LDAP&lt;/h4&gt;
&lt;p&gt;For enterprise directories, SafeLine supports LDAP — including Microsoft Active Directory, OpenLDAP, and Apache Directory. Users log in with their existing enterprise accounts.&lt;/p&gt;
&lt;p&gt;Configuration is the standard set of LDAP fields: a server URL (&lt;code&gt;ldap://host:389&lt;/code&gt; or &lt;code&gt;ldaps://host:636&lt;/code&gt; for SSL), a Bind DN, a Bind password, a user base DN, and a query condition. The query condition uses &lt;code&gt;%s&lt;/code&gt; as a placeholder for the username, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&amp;amp;(objectClass=person)(uid=%s))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the one to use when you want a self-hosted gateway in front of an on-premise directory.&lt;/p&gt;
&lt;h3 id=&quot;passing-the-authenticated-user-into-your-app&quot;&gt;Passing the authenticated user into your app&lt;/h3&gt;
&lt;p&gt;Blocking unauthenticated traffic is only half the story. Often your app needs to &lt;em&gt;know who&lt;/em&gt; just logged in. SafeLine handles this with a callback flow.&lt;/p&gt;
&lt;p&gt;After a user authenticates, SafeLine redirects to your configured &lt;strong&gt;Auth Callback URL&lt;/strong&gt;, appending a short-lived &lt;code&gt;code&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://example.com/application?code=123456&amp;amp;redirect_uri=original_user_access_address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your application then exchanges that &lt;code&gt;code&lt;/code&gt; for the user's identity by calling SafeLine's user-info endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET http://safeline-console.com/.safeline/auth/api/user?code=123456
X-SLCE-API-TOKEN: safeline-api-token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response gives you the user's &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;username&lt;/code&gt;. Two things to note: the &lt;code&gt;code&lt;/code&gt; can only be used &lt;strong&gt;once&lt;/strong&gt;, and you'll find the API token in the console under &lt;strong&gt;Settings → Management&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After your app obtains the user info, it should cache the login state to decide whether the user is logged in for subsequent requests, then redirect to the &lt;code&gt;redirect_uri&lt;/code&gt;. If retrieving the user info fails, your app should delete cookies with the &lt;code&gt;sl_auth_session_&lt;/code&gt; prefix and prompt the user to authenticate again.&lt;/p&gt;
&lt;h3 id=&quot;approvals-and-conditional-auth&quot;&gt;Approvals and conditional auth&lt;/h3&gt;
&lt;p&gt;Two more knobs round out the picture, both under the app's AUTH advanced configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Approval configuration.&lt;/strong&gt; You can require that first-time users trigger an approval request after authenticating, which an admin must approve before the user gets in. Or you can let users access directly after authentication. The former is handy for sensitive internal tools where you want a human in the loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conditional authentication.&lt;/strong&gt; You can enable authentication (or skip it) only when specific conditions are met — for example, requiring auth for certain paths while letting other traffic pass.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;Authentication doesn't have to be a per-app engineering project. Because a self-hosted WAF already sits in front of your traffic, it's the natural place to gate access — and SafeLine turns that into a real feature set: per-app password protection, unified SSO across your apps, and four identity methods (password, GitHub, OIDC, LDAP) to choose from.&lt;/p&gt;
&lt;p&gt;The result is that an internal dashboard, a legacy tool, or a static site can all get a proper login screen — and SSO — without a single line of application code changing.&lt;/p&gt;
&lt;p&gt;If you want to try it yourself, the setup starts with a single command. The full authentication documentation is at &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;docs.waf.chaitin.com&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;faq-23&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-adding-auth-at-the-waf-layer-slow-down-my-app-&quot;&gt;Does adding auth at the WAF layer slow down my app?&lt;/h4&gt;
&lt;p&gt;The check happens at the reverse-proxy layer before traffic reaches your origin, so your application itself isn't doing any extra work. The main cost is the one-time configuration.&lt;/p&gt;
&lt;h4 id=&quot;can-i-use-sso-for-both-internal-and-public-apps-&quot;&gt;Can I use SSO for both internal and public apps?&lt;/h4&gt;
&lt;p&gt;Yes. The mode is per-application, so you can put internal tools behind SSO while using Simple Auth or no auth on public apps, all from the same console.&lt;/p&gt;
&lt;h4 id=&quot;which-identity-provider-should-i-pick-&quot;&gt;Which identity provider should I pick?&lt;/h4&gt;
&lt;p&gt;If you already run Keycloak, Auth0, Okta, or Azure AD, OIDC is the natural fit. If you have an enterprise directory, use LDAP. GitHub is convenient for developer-facing tools, and Account + Password is fine for a small number of trusted users.&lt;/p&gt;
&lt;h4 id=&quot;do-i-have-to-modify-my-app-to-know-who-logged-in-&quot;&gt;Do I have to modify my app to know who logged in?&lt;/h4&gt;
&lt;p&gt;Only if your app needs the user's identity. In that case you implement the callback flow (exchange the &lt;code&gt;code&lt;/code&gt; for user info). If you just need to gate access, no code changes are required at all.&lt;/p&gt;
&lt;h4 id=&quot;does-safeline-s-sso-support-single-logout-&quot;&gt;Does SafeLine's SSO support single logout?&lt;/h4&gt;
&lt;p&gt;Not currently. Logging out of the SSO center is not SLO.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Which of the four login methods — password, GitHub, OIDC, or LDAP — fits your current stack?&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Ready to protect your sites without paying for a cloud WAF?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;SafeLine WAF on GitHub&lt;/a&gt; — give it a star if you find it useful&lt;/li&gt;
&lt;li&gt;🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;Official Docs&lt;/a&gt; — installation guide, configuration, and API reference&lt;/li&gt;
&lt;li&gt;🧪 &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;Live Demo&lt;/a&gt; — see the dashboard in action (no login required)&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24793/add-authentication-and-sso-to-any-web-app-without-changing-code</guid>
<pubDate>Mon, 17 Aug 2026 16:03:48 +0000</pubDate>
</item>
<item>
<title>Gnat, self-hosted analytics as a single Go binary, with a built-in MCP server</title>
<link>https://coderlegion.com/24651/gnat-self-hosted-analytics-as-a-single-go-binary-with-a-built-in-mcp-server</link>
<description>&lt;hr&gt;
&lt;p&gt;title: Gnat, self-hosted analytics as a single Go binary, with a built-in MCP server&lt;/p&gt;
&lt;h3 id=&quot;tags-go-selfhosted-opensource-ai&quot;&gt;tags: go, selfhosted, opensource, ai&lt;/h3&gt;
&lt;p&gt;A few months back I was crawling the web for a side project and came across an analytics platform's data that had exposed users' raw IPs. It wasn't malicious, just careless. But it stuck with me: most people using these tools have no idea their visitors' data is sitting around like that.&lt;/p&gt;
&lt;p&gt;That's the moment that pushed me to build &lt;strong&gt;Gnat&lt;/strong&gt;, a self-hosted analytics tool that doesn't cut corners on privacy, but also doesn't force you into a painful setup to get it.&lt;/p&gt;
&lt;h3 id=&quot;no-third-party-no-phoning-home&quot;&gt;No third party, no phoning home&lt;/h3&gt;
&lt;p&gt;Gnat runs entirely on infrastructure you control. There's no third party in the loop, no API calling home anywhere, and no data leaving your server. It's also completely free and open source, the whole thing is on GitHub.&lt;/p&gt;
&lt;h3 id=&quot;one-binary-zero-bloat&quot;&gt;One binary, zero bloat&lt;/h3&gt;
&lt;p&gt;Most self-hosted analytics tools make you choose: either something lightweight with barely any real analysis, or something with real analytical depth that also means Docker, a multi-service stack, and its own ops burden just to keep running.&lt;/p&gt;
&lt;p&gt;Gnat is a single Go binary. No CGO, no Docker, no multi-service stack. The dashboard (HTML, CSS, JS) is compiled directly into the executable, so there's nothing else to install alongside it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;tar xzf gnat-vX.Y.Z-linux-amd64.tar.gz
cd gnat-vX.Y.Z-linux-amd64
./gnat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's the whole install.&lt;/p&gt;
&lt;h3 id=&quot;real-analytical-depth&quot;&gt;Real analytical depth&lt;/h3&gt;
&lt;p&gt;Despite being one binary, Gnat doesn't skimp on features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pageviews and custom events via a simple JSON POST (no per-language SDKs needed)&lt;/li&gt;
&lt;li&gt;Funnels, cohorts, retention curves&lt;/li&gt;
&lt;li&gt;Auto-discovered path analysis&lt;/li&gt;
&lt;li&gt;SQLite by default, or Postgres/MySQL if that's how you already run infrastructure&lt;/li&gt;
&lt;li&gt;CSV, JSON, jsonL, it's your data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;built-for-the-agent-era&quot;&gt;Built for the agent era&lt;/h3&gt;
&lt;p&gt;The part I had the most fun building: Gnat ships with a &lt;strong&gt;native MCP server&lt;/strong&gt;. Claude or any MCP-compatible agent can query your analytics directly, ask what changed, pull a report, whatever you need.&lt;/p&gt;
&lt;h3 id=&quot;where-it-s-at&quot;&gt;Where it's at&lt;/h3&gt;
&lt;p&gt;This is early, v0.1.0, and I'm actively building on it. Multi-site support, SSO/team access, and managed hosting are all on the roadmap but not built yet, the README is upfront about what's real today versus what's planned.&lt;/p&gt;
&lt;p&gt;Gnat is licensed under AGPLv3, free to self-host and modify for any purpose, including commercially, but if you run a modified version as a service for others, the source has to stay open under the same terms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/var-raphael/Gnat&quot;&gt;https://github.com/var-raphael/Gnat&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Feedback, issues, and contributions are very welcome. I'd love to hear what you think, especially if you've felt the same Docker-and-multi-service fatigue trying to self-host analytics.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24651/gnat-self-hosted-analytics-as-a-single-go-binary-with-a-built-in-mcp-server</guid>
<pubDate>Fri, 14 Aug 2026 19:21:56 +0000</pubDate>
</item>
<item>
<title>Building What Was Missing: My Summer Finalizing MelaFreelance</title>
<link>https://coderlegion.com/24102/building-what-was-missing-my-summer-finalizing-melafreelance</link>
<description>&lt;p&gt;I didn't set out to build the ultimate productivity platform, and I certainly didn't intend to disrupt the SaaS industry. I just wanted to stop paying monthly subscriptions for tools built for project managers instead of freelancers.&lt;/p&gt;
&lt;p&gt;For years, I found myself stacking apps on top of each other—Asana for tasks, Everhour for time tracking—navigating complex interfaces only to use about ten percent of what I was actually paying for. In August 2025, out of pure frustration, I decided to sketch out a self-hosted alternative.&lt;/p&gt;
&lt;p&gt;For a year, MelaFreelance was my silent partner, running in the background of my daily work. This August, during the quiet of the summer holidays, I finally added the missing pieces. The app is now complete—not because it has every feature in the world, but because it finally has exactly the ones I actually use.&lt;/p&gt;
&lt;h2 id=&quot;escaping-the-subscription-bloat&quot;&gt;Escaping the Subscription Bloat&lt;/h2&gt;
&lt;p&gt;When you work alone, you don't need team permissions, complex Gantt charts, or enterprise cloud syncing. You simply need to know what you are doing, how long it took, and whether you have been paid for it.&lt;/p&gt;
&lt;p&gt;MelaFreelance is a quiet departure from the multi-tool chaos. It is a single, self-hosted space where the friction between tracking work and getting paid is entirely removed. Because it runs on my own server, I own the data. There is no cloud, no telemetry, and best of all, no monthly fees.&lt;/p&gt;
&lt;h2 id=&quot;a-flow-built-for-solo-work&quot;&gt;A Flow Built for Solo Work&lt;/h2&gt;
&lt;p&gt;The app is built on a modern stack (Laravel 12, Inertia 2, Vue 3, TypeScript, and Tailwind 4), but its philosophy is stubbornly simple. The hierarchy matches the reality of freelance work: &lt;strong&gt;Clients → Projects → Tasks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Rather than forcing you to define rigid &quot;project types&quot; before you even start working, MelaFreelance adapts to your billing reality based solely on the data you enter:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Billing Mode&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;How It Handles Time &amp;amp; Money&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Fixed-Price&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Tracked time simply shows your effective hourly rate, but the flat fee dictates what you are owed.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Hourly&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Every tracked minute is automatically multiplied by your set rate to calculate project earnings.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Non-Billable&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;For personal or pro-bono work, the financial UI elegantly drops away, leaving only your tracked hours.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;the-little-details-that-matter&quot;&gt;The Little Details That Matter&lt;/h2&gt;
&lt;p&gt;The summer finalization wasn't about adding more features; it was about refining the daily experience and removing friction.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Always-On Timer:&lt;/strong&gt; A running timer sits in the app header on every page. I can navigate to my dashboard or reports without ever losing sight of the clock.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Contextual Memory:&lt;/strong&gt; If I start a new task, the previous one automatically stops and banks its time. If I pause, the timer remembers my place, offering a quick &quot;Resume&quot; button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Unified Task Canvas:&lt;/strong&gt; Clicking a task opens a single workspace where I can edit notes, adjust the tracked time, and securely drag-and-drop private attachments (like PDFs or Figma links) that never leave my server.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Realistic Payment Ledger:&lt;/strong&gt; Freelance payments are rarely a simple yes/no checkbox. MelaFreelance lets me record deposits and part-payments as they arrive, automatically calculating what is still outstanding until the project is fully paid and sealed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yours-if-you-need-it&quot;&gt;Yours If You Need It&lt;/h2&gt;
&lt;p&gt;I built MelaFreelance so I could finally cancel my SaaS subscriptions, stop looking at features I'll never use, and just get back to work.&lt;/p&gt;
&lt;p&gt;With built-in dark mode, config-driven language support (English and Italian out of the box), and a frictionless setup using Laravel Sail or a local SQLite file, it has become exactly the tool I was missing.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&quot;I tried every time tracker made for teams, so I built the missing one for freelancers.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It works beautifully for me. If you are tired of bloated software and want a tidy, private, and elegant space to track your hours and invoices, you are welcome to clone it and make it your own.&lt;/p&gt;
&lt;p&gt;Check it out on &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/melasistema/clients-melasistema&quot;&gt;Github&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24102/building-what-was-missing-my-summer-finalizing-melafreelance</guid>
<pubDate>Tue, 04 Aug 2026 16:42:59 +0000</pubDate>
</item>
<item>
<title>Mastering Self-Hosted Convex on Dokploy: A Complete Deployment Guide</title>
<link>https://coderlegion.com/24030/mastering-self-hosted-convex-on-dokploy-a-complete-deployment-guide</link>
<description>&lt;p&gt;So, you've decided to take control of your data and self-host &lt;strong&gt;Convex&lt;/strong&gt;. It's a great choice but if you've tried pushing your functions to a local or private server, you might have run into cryptic errors about &quot;Relative import paths&quot; or &quot;Missing modules.&quot;&lt;/p&gt;
&lt;p&gt;The secret? You don't need custom deployment scripts. In fact, you &lt;em&gt;shouldn't&lt;/em&gt; use them. The official Convex CLI is actually powerful enough to handle self-hosted deployments perfectly—if you know which buttons to press.&lt;/p&gt;
&lt;p&gt;In this guide, I’ll show you exactly how to configure your project and deploy your functions like a pro.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-before-you-start&quot;&gt;1. Before You Start&lt;/h3&gt;
&lt;p&gt;Before we dive into the code, make sure you have the following ready:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Your Convex Instance&lt;/strong&gt;: Whether you're using Dokploy, Docker, or a raw VPS, your backend should be up and running.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Admin Key&lt;/strong&gt;: You'll need the master key for your server. &lt;ul&gt;
&lt;li&gt;&lt;em&gt;Tip&lt;/em&gt;: If you're using Dokploy, you can usually generate this by running &lt;code&gt;./generate_admin_key.sh&lt;/code&gt; inside your backend container's terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The CLI&lt;/strong&gt;: Make sure you have the latest version of Convex installed locally:&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install convex
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-preparing-your-project&quot;&gt;2. Preparing Your Project&lt;/h3&gt;
&lt;p&gt;For a smooth deployment, your &lt;code&gt;convex/&lt;/code&gt; folder needs to be a bit more &quot;independent.&quot;&lt;/p&gt;
&lt;h4 id=&quot;step-1-give-convex-its-own-identity&quot;&gt;Step 1: Give Convex its own Identity&lt;/h4&gt;
&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; inside your &lt;code&gt;convex/&lt;/code&gt; directory. This ensures the CLI knows exactly which dependencies to bundle when it prepares your code for the server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;name&quot;: &quot;my-convex-backend&quot;,
  &quot;private&quot;: true,
  &quot;type&quot;: &quot;module&quot;,
  &quot;dependencies&quot;: {
    &quot;convex&quot;: &quot;^1.16.0&quot;,
    &quot;typescript&quot;: &quot;^5.0.0&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;step-2-fix-your-config&quot;&gt;Step 2: Fix your Config&lt;/h4&gt;
&lt;p&gt;Ensure your &lt;code&gt;convex/convex.config.ts&lt;/code&gt; is using the modern &lt;code&gt;defineApp&lt;/code&gt; export. The server expects this structure to understand your app's layout.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { defineApp } from &quot;convex/server&quot;;

export default defineApp();
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-the-magic-environment-variables&quot;&gt;3. The Magic Environment Variables&lt;/h3&gt;
&lt;p&gt;The Convex CLI is &quot;Cloud-first&quot; by default, but we can tell it to target our own server by setting two specific environment variables.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Variable &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;What it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;CONVEX_SELF_HOSTED_URL&lt;/code&gt; &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Points the CLI to your backend URL (e.g., &lt;code&gt;https://api.myapp.com&lt;/code&gt;).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;CONVEX_SELF_HOSTED_ADMIN_KEY&lt;/code&gt; &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Your secret key. &lt;strong&gt;Crucial&lt;/strong&gt;: It must include the &lt;code&gt;convex-self-hosted|&lt;/code&gt; prefix!&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-the-big-moment-deploying&quot;&gt;4. The Big Moment: Deploying&lt;/h3&gt;
&lt;p&gt;Now, let's push your code. We're going to use the official &lt;code&gt;deploy&lt;/code&gt; command. &lt;/p&gt;
&lt;p&gt;Run this from your &lt;strong&gt;root&lt;/strong&gt; or &lt;strong&gt;convex&lt;/strong&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;CONVEX_SELF_HOSTED_URL=&quot;https://your-api-url.com&quot; \
CONVEX_SELF_HOSTED_ADMIN_KEY=&quot;convex-self-hosted|your-key-here&quot; \
npx convex deploy --typecheck disable
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;why-this-works-where-other-scripts-fail-&quot;&gt;Why this works where other scripts fail:&lt;/h4&gt;
&lt;p&gt;When you use a custom &lt;code&gt;fetch&lt;/code&gt; script to send files, you're just sending raw text. The server has no idea where &lt;code&gt;convex/server&lt;/code&gt; is. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The CLI is smarter.&lt;/strong&gt; It uses &lt;code&gt;esbuild&lt;/code&gt; to &quot;bundle&quot; your code into a single, self-contained JavaScript package. It finds all your imports and bakes them right into the file so the server can run them instantly.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-pro-tip-automate-everything&quot;&gt;5. Pro Tip: Automate Everything&lt;/h3&gt;
&lt;p&gt;Don't type those long variables every time. Add a script to your &lt;code&gt;convex/package.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&quot;scripts&quot;: {
  &quot;deploy&quot;: &quot;CONVEX_SELF_HOSTED_URL=... CONVEX_SELF_HOSTED_ADMIN_KEY=... npx convex deploy --typecheck disable&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, all it takes is a simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm run deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;troubleshooting-common-gotchas-&quot;&gt;Troubleshooting common &quot;Gotchas&quot;&lt;/h3&gt;
&lt;h4 id=&quot;-relative-import-path-convex-server-not-found-&quot;&gt;&quot;Relative import path 'convex/server' not found&quot;&lt;/h4&gt;
&lt;p&gt;If you see this, you likely bypassed the CLI. Always use &lt;code&gt;npx convex deploy&lt;/code&gt; so the bundler can do its job!&lt;/p&gt;
&lt;h4 id=&quot;-badadminkey-&quot;&gt;&quot;BadAdminKey&quot;&lt;/h4&gt;
&lt;p&gt;Double-check your key. Most people forget the &lt;code&gt;convex-self-hosted|&lt;/code&gt; prefix. Without it, the server will reject your request every time.&lt;/p&gt;
&lt;h4 id=&quot;missing-generated-files-in-your-frontend&quot;&gt;Missing &lt;code&gt;_generated&lt;/code&gt; files in your frontend&lt;/h4&gt;
&lt;p&gt;Run &lt;code&gt;npx convex codegen&lt;/code&gt; while your &lt;code&gt;CONVEX_SELF_HOSTED_URL&lt;/code&gt; is set to update your local TypeScript types to match what you just deployed.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Happy hosting! Your Convex backend is now truly yours.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24030/mastering-self-hosted-convex-on-dokploy-a-complete-deployment-guide</guid>
<pubDate>Mon, 03 Aug 2026 07:41:58 +0000</pubDate>
</item>
<item>
<title>The Issues of Deploying Laravel on Dokploy: Database Connection Hell</title>
<link>https://coderlegion.com/24029/the-issues-of-deploying-laravel-on-dokploy-database-connection-hell</link>
<description>&lt;p&gt;If you’ve tried deploying a Laravel application on &lt;strong&gt;Dokploy&lt;/strong&gt; (the self-hosted Heroku alternative built on Docker) and immediately ran into a wall of &lt;code&gt;Database connection refused&lt;/code&gt; or &lt;code&gt;SQLSTATE[HY000] [2002]&lt;/code&gt; errors, you are not alone. &lt;/p&gt;
&lt;p&gt;It works perfectly on your local machine, but the moment it hits the server, it falls apart. Here is a real-world breakdown of the database connectivity issues we experienced, why they happened, and how to fix them.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-the-localhost-trap-the-127-0-0-1-connection-refused-&quot;&gt;1. The &quot;Localhost&quot; Trap (The &lt;code&gt;127.0.0.1&lt;/code&gt; Connection Refused)&lt;/h3&gt;
&lt;h4 id=&quot;the-issue&quot;&gt;The Issue&lt;/h4&gt;
&lt;p&gt;On your local computer, you probably set your &lt;code&gt;.env&lt;/code&gt; to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-env&quot;&gt;DB_HOST=127.0.0.1
DB_PORT=3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you deploy this to Dokploy, your Laravel application crashes on start because it cannot connect to the database.&lt;/p&gt;
&lt;h4 id=&quot;the-reason&quot;&gt;The Reason&lt;/h4&gt;
&lt;p&gt;Dokploy runs everything in isolated &lt;strong&gt;Docker Containers&lt;/strong&gt;. &lt;br&gt;
Inside a container, &lt;code&gt;127.0.0.1&lt;/code&gt; or &lt;code&gt;localhost&lt;/code&gt; refers to &lt;strong&gt;the Laravel container itself&lt;/strong&gt;, not the host machine or your database container. Since there is no database running &lt;em&gt;inside&lt;/em&gt; your Laravel code container, it refuses the connection.&lt;/p&gt;
&lt;h4 id=&quot;the-solution&quot;&gt;The Solution&lt;/h4&gt;
&lt;p&gt;You must use Docker's internal networking. &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If your database is created inside Dokploy, Dokploy assigns it a specific network service name (e.g. &lt;code&gt;dokploy-db-mysql&lt;/code&gt; or the service name you typed in the database creation wizard).&lt;/li&gt;
&lt;li&gt;Change your host in the Dokploy Environment Variables UI to match that service name:&lt;pre&gt;&lt;code class=&quot;language-env&quot;&gt;DB_HOST=dokploy-db-mysql  # Use Dokploy's internal container name
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-the-config-caching-nightmare-why-changing-env-variables-in-the-ui-did-nothing-&quot;&gt;2. The Config Caching Nightmare (Why changing Env Variables in the UI did nothing)&lt;/h3&gt;
&lt;h4 id=&quot;the-issue-1&quot;&gt;The Issue&lt;/h4&gt;
&lt;p&gt;You realized the host was wrong, went to the Dokploy dashboard, updated the &lt;code&gt;DB_HOST&lt;/code&gt; environment variable to the correct container hostname, saved, and redeployed. &lt;br&gt;
Yet, the app &lt;em&gt;still&lt;/em&gt; threw the old connection error looking for &lt;code&gt;127.0.0.1&lt;/code&gt;. You checked the container logs, confirmed the new environment variables were set, but Laravel simply ignored them.&lt;/p&gt;
&lt;h4 id=&quot;the-reason-1&quot;&gt;The Reason&lt;/h4&gt;
&lt;p&gt;This happens if you run configuration caching in your &lt;code&gt;Dockerfile&lt;/code&gt; during the build step:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;RUN php artisan config:cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When Laravel builds your container, it runs &lt;code&gt;config:cache&lt;/code&gt; and &lt;strong&gt;bakes&lt;/strong&gt; whatever &lt;code&gt;.env&lt;/code&gt; values exist at build-time directly into a static cache file (&lt;code&gt;bootstrap/cache/config.php&lt;/code&gt;). &lt;br&gt;
At runtime, Laravel completely ignores your Dokploy UI environment variables and loads the baked-in values instead.&lt;/p&gt;
&lt;h4 id=&quot;the-solution-1&quot;&gt;The Solution&lt;/h4&gt;
&lt;p&gt;Never cache your configuration during the Docker build stage if you plan to change environment variables dynamically.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Remove &lt;code&gt;RUN php artisan config:cache&lt;/code&gt; from your build steps.&lt;/li&gt;
&lt;li&gt;If you want caching for speed in production, clear it on boot by running &lt;code&gt;php artisan config:clear&lt;/code&gt; or &lt;code&gt;php artisan optimize:clear&lt;/code&gt; inside your container's startup command / entrypoint script.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-the-race-condition-migrations-crashing-the-build-&quot;&gt;3. The Race Condition (Migrations crashing the build)&lt;/h3&gt;
&lt;h4 id=&quot;the-issue-2&quot;&gt;The Issue&lt;/h4&gt;
&lt;p&gt;You configured your Docker container to automatically run migrations on deployment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;php artisan migrate --force
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But your deployment failed during this step because the database connection timed out or was refused, even though all credentials were 100% correct.&lt;/p&gt;
&lt;h4 id=&quot;the-reason-2&quot;&gt;The Reason&lt;/h4&gt;
&lt;p&gt;When Dokploy restarts or provisions your stack, it starts both the Laravel container and the MySQL/PostgreSQL container simultaneously.&lt;br&gt;
Laravel boots up in milliseconds and immediately tries to run migrations. However, MySQL is still executing its slow initial setup scripts, checking schemas, and opening sockets. The database container isn't ready to receive queries yet, so Laravel's migration command crashes, failing the entire Dokploy deployment.&lt;/p&gt;
&lt;h4 id=&quot;the-solution-2&quot;&gt;The Solution&lt;/h4&gt;
&lt;p&gt;You need to make Laravel &quot;wait&quot; for the database to boot. Add a small bash loop to your entrypoint script (&lt;code&gt;entrypoint.sh&lt;/code&gt;) that pings the database port before running migrations:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo &quot;Waiting for MySQL to boot...&quot;
until nc -z -v -w30 $DB_HOST $DB_PORT; do
  echo &quot;MySQL is not ready yet. Retrying in 2 seconds...&quot;
  sleep 2
done
echo &quot;MySQL is up! Running migrations...&quot;
php artisan migrate --force
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-port-mapping-confusion-internal-vs-external-ports-&quot;&gt;4. Port Mapping Confusion (Internal vs. External Ports)&lt;/h3&gt;
&lt;h4 id=&quot;the-issue-3&quot;&gt;The Issue&lt;/h4&gt;
&lt;p&gt;Mapping your Dokploy MySQL database port to &lt;code&gt;3306&lt;/code&gt; (or &lt;code&gt;3307&lt;/code&gt;) externally so you could connect via TablePlus/DBeaver from your laptop, but when configuring your Laravel &lt;code&gt;.env&lt;/code&gt; inside Dokploy, you weren't sure which port to use.&lt;/p&gt;
&lt;h4 id=&quot;the-reason-3&quot;&gt;The Reason&lt;/h4&gt;
&lt;p&gt;Docker has two layers of ports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Internal Port:&lt;/strong&gt; The port the service listens to inside the Docker private network (always &lt;code&gt;3306&lt;/code&gt; for MySQL).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;External/Exposed Port:&lt;/strong&gt; The port mapped to the public server IP so you can connect from the outside world (e.g., mapping host &lt;code&gt;3307&lt;/code&gt; to container &lt;code&gt;3306&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inside Dokploy, your Laravel app and your MySQL container share the same private network. Therefore, they communicate &lt;strong&gt;internally&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-solution-3&quot;&gt;The Solution&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;Laravel (.env on Dokploy)&lt;/strong&gt;: Always use the internal port (&lt;code&gt;DB_PORT=3306&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;TablePlus/DBeaver (External laptop)&lt;/strong&gt;: Use the exposed host port (&lt;code&gt;3307&lt;/code&gt;) and the public server IP.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;summary-checklist-for-dokploy-deployments&quot;&gt;Summary Checklist for Dokploy deployments&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;DB_HOST&lt;/code&gt; to the internal Docker container/service name, not &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;DB_PORT&lt;/code&gt; to the internal port (&lt;code&gt;3306&lt;/code&gt; for MySQL), not the exposed host port.&lt;/li&gt;
&lt;li&gt;Avoid running &lt;code&gt;php artisan config:cache&lt;/code&gt; during Docker build time.&lt;/li&gt;
&lt;li&gt;Implement a &lt;code&gt;wait-for-it&lt;/code&gt; check in your startup script so migrations don't run before MySQL is fully booted.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24029/the-issues-of-deploying-laravel-on-dokploy-database-connection-hell</guid>
<pubDate>Mon, 03 Aug 2026 07:41:12 +0000</pubDate>
</item>
<item>
<title>The Missing Freelance Time Tracker</title>
<link>https://coderlegion.com/23921/the-missing-freelance-time-tracker</link>
<description>&lt;h2 id=&quot;the-missing-freelance-time-tracker&quot;&gt;The Missing Freelance Time Tracker&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;It has a name now: MelaFreelance. Here's what it is, and why it's yours — not mine.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;In the &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/23572/i-tried-every-time-tracker-made-for-teams-so-i-built-one-for-freelancers&quot;&gt;last piece&lt;/a&gt; I explained the itch: every time tracker I tried was built for teams, and I'm one person with a client, a project, and a clock. So I stopped renting other people's tools and built the small one I actually needed.&lt;/p&gt;
&lt;p&gt;This is that tool. It's called &lt;strong&gt;MelaFreelance&lt;/strong&gt;, and this is what it turned out to be.&lt;/p&gt;
&lt;h3 id=&quot;built-one-summer-polished-the-next&quot;&gt;Built one summer, polished the next&lt;/h3&gt;
&lt;p&gt;The first commit landed in &lt;strong&gt;August 2025&lt;/strong&gt;, in the slow, warm gap where the client emails thin out and there's finally room to make the thing you keep meaning to make. It wasn't pretty. It had no options, no settings, no polish — just the raw mechanics I needed to answer &lt;em&gt;who owes me what.&lt;/em&gt; And then I did the most honest test there is: I used it. Every day, for a straight year, exactly as it was.&lt;/p&gt;
&lt;p&gt;A year of real use is a brutally good editor. It tells you which features you invented and never touch, and which rough edges you step over so often you stopped noticing. Nothing survives that a design doc would have kept, and nothing gets cut that you actually reach for.&lt;/p&gt;
&lt;p&gt;So here we are, &lt;strong&gt;another August&lt;/strong&gt;, the same quiet slice of the calendar — and this time the work isn't building it, it's &lt;em&gt;finishing&lt;/em&gt; it. The polish it earned by proving, over twelve months, that it deserved to exist.&lt;/p&gt;
&lt;p&gt;There's a second reason the timing is right. Lately I've been deep in a much heavier project — &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/melasistema/s-moe&quot;&gt;&lt;strong&gt;S-MoE&lt;/strong&gt;&lt;/a&gt;, a sparse mixture-of-experts build that lives in exactly the kind of complexity you can't hold in your head on a hot afternoon. After enough of that, coming back to MelaFreelance feels like stepping out of a machine room into the sun. Small surface, clear edges, an obvious right answer for every question. Simple work — but not &lt;em&gt;unimportant&lt;/em&gt; work. Sometimes the most useful thing you can build is the one you can finish.&lt;/p&gt;
&lt;h3 id=&quot;it-s-yours-not-mine&quot;&gt;It's yours, not mine&lt;/h3&gt;
&lt;p&gt;Here's the decision that shapes everything else: &lt;strong&gt;MelaFreelance isn't a service you sign up for. It's a thing you run.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There's no account on my server, no subscription, no &quot;free tier&quot; quietly counting your clients until it asks for a card. You clone it, you point it at your own database, and it's yours — data and all. If I vanish tomorrow, your tool keeps working, because it was never on a server I control.&lt;/p&gt;
&lt;p&gt;That's not an accident, it's the whole philosophy. The tools that broke me in the first place all had one thing in common: my data lived in &lt;em&gt;their&lt;/em&gt; product, on &lt;em&gt;their&lt;/em&gt; terms, one pricing-page change away from held hostage. A tracker for freelancers should be the one piece of software a freelancer never has to worry about losing.&lt;/p&gt;
&lt;p&gt;So it's &lt;strong&gt;single-user by default&lt;/strong&gt; — no seats, no invites, no &quot;workspace.&quot; One person clones it, runs one command to create their account, and starts working. Everything about it assumes you are the only human who will ever log in, because for me, that's the truth.&lt;/p&gt;
&lt;h3 id=&quot;the-timer-that-s-always-there&quot;&gt;The timer that's always there&lt;/h3&gt;
&lt;p&gt;The most-used thing in a time tracker is the start/stop button, so I refused to bury it.&lt;/p&gt;
&lt;p&gt;In MelaFreelance the running timer isn't a widget you navigate to — it lives in the app's chrome, on &lt;strong&gt;every&lt;/strong&gt; page. Wherever you are, you can see what's ticking and stop it. And there's exactly one rule the app enforces for you, quietly: &lt;strong&gt;you can only run one timer at a time.&lt;/strong&gt; Start a task while another is running and the old one banks its minutes and stops on its own. A freelancer works one thing at a time; the tool should never let two clocks claim the same minute.&lt;/p&gt;
&lt;p&gt;When you stop, the bar doesn't just disappear. It remembers the last thing you were on — &lt;em&gt;&quot;was I still on the Rossi homepage?&quot;&lt;/em&gt; — with a one-click &lt;strong&gt;Resume&lt;/strong&gt;, until you dismiss it. Small thing. I use it twenty times a day.&lt;/p&gt;
&lt;h3 id=&quot;the-number-that-matters&quot;&gt;The number that matters&lt;/h3&gt;
&lt;p&gt;Open the app and the first thing it tells you is the number I actually came for: &lt;strong&gt;what am I owed, and what's still outstanding?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not tracked hours dressed up as money. Not an invoice-count vanity stat. Just: across every project, how much has been paid, and how much is still out there. Because payments in MelaFreelance are a &lt;strong&gt;ledger&lt;/strong&gt;, not a checkbox — a deposit, a milestone, a final balance — &quot;paid&quot; and &quot;outstanding&quot; are simply the arithmetic on that ledger. And the arithmetic is done once, on the backend, in whole cents, so the number on your dashboard is the number, every time. No rounding drift, no two screens disagreeing.&lt;/p&gt;
&lt;p&gt;Money can be windowed — &lt;em&gt;received this month&lt;/em&gt; — because every payment carries a date. Hours are all-time, on purpose: a task holds one running total, not a pile of dated entries I'd have to maintain. That asymmetry is a feature. It's the difference between a tool that answers your question and a tool that invents new ones to justify itself.&lt;/p&gt;
&lt;h3 id=&quot;still-small-on-purpose&quot;&gt;Still small on purpose&lt;/h3&gt;
&lt;p&gt;I've added things since launch — a gentle nudge to mark a project done when its last task finishes, a proper time picker, non-billable projects for the client called &lt;em&gt;&quot;Myself.&quot;&lt;/em&gt; But the rule hasn't changed: &lt;strong&gt;nothing ships unless I hit the need for it in my own week.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That's the luxury of building for exactly one user. There's no roadmap to defend, no enterprise deal bending the design, no feature added to win a comparison chart. When something annoys me, I fix it. When something's missing, I add it. When it's fine, I leave it alone — which is most of the time, and exactly the point.&lt;/p&gt;
&lt;p&gt;MelaFreelance is free, it's open, and it's built to be cloned. If you're a freelancer who's tired of renting the basics, you don't have to wait for me to build your features. You can take it and make it the tool &lt;em&gt;you&lt;/em&gt; needed all along.&lt;/p&gt;
&lt;p&gt;That was always the missing one. Built in one summer, quietly proven through a year of real work, and finished in the next. If a tool can earn that, it's earned a place on your machine too.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/melasistema/clients-melasistema&quot;&gt;MelaFreelance&lt;/a&gt; — built by a freelancer, for freelancers. Clone it, own it, get back to the work.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23921/the-missing-freelance-time-tracker</guid>
<pubDate>Sat, 01 Aug 2026 10:02:43 +0000</pubDate>
</item>
</channel>
</rss>