<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged server</title>
<link>https://coderlegion.com/tag/server</link>
<description>Powered by Question2Answer</description>
<item>
<title>Go type yourself!</title>
<link>https://coderlegion.com/33126/go-type-yourself</link>
<description>&lt;p&gt;DHH said that typescript is pure &quot;type masterbation&quot;. And though I agree with his premise, It is a fixable problem. And I say we use the type system to do just that.&lt;/p&gt;
&lt;p&gt;There is a familiar complaint about TypeScript: too much of the code is types talking to other types. Generic wrappers, schemas restating the same shapes, &lt;code&gt;never&lt;/code&gt; tricks to force a &lt;code&gt;switch&lt;/code&gt; to be complete. Very little of it does anything at run time.&lt;/p&gt;
&lt;p&gt;The complaint is fair, but it usually lands on the wrong target. The TypeScript in a typical full-stack feature is not careless. It is what you have to write to get the guarantees, because TypeScript can't see the parts that matter: what crosses the network, which errors can happen, and whether you handled all of them.&lt;/p&gt;
&lt;p&gt;Here is a small, ordinary feature. A page loads a post's title and shows a different message for each way loading can fail.&lt;/p&gt;
&lt;h3 id=&quot;in-typescript&quot;&gt;In TypeScript&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// shared/types.ts — the wire contract, stated as types AND as a runtime schema
import { z } from &quot;zod&quot;;

export const PostRow = z.object({ title: z.string(), owner: z.string() });
export type PostRow = z.infer&amp;lt;typeof PostRow&amp;gt;;

export type LoadError =
  | { kind: &quot;NotFound&quot;; id: string }
  | { kind: &quot;Forbidden&quot; }
  | { kind: &quot;Unavailable&quot; };

export type Result&amp;lt;T, E&amp;gt; = { ok: true; value: T } | { ok: false; error: E };
export type ApiResponse = Result&amp;lt;string, LoadError&amp;gt;;

// the same contract again, so the client can check at runtime what TS only assumes
export const ApiResponseSchema = z.discriminatedUnion(&quot;ok&quot;, [
  z.object({ ok: z.literal(true), value: z.string() }),
  z.object({ ok: z.literal(false), error: z.discriminatedUnion(&quot;kind&quot;, [
    z.object({ kind: z.literal(&quot;NotFound&quot;), id: z.string() }),
    z.object({ kind: z.literal(&quot;Forbidden&quot;) }),
    z.object({ kind: z.literal(&quot;Unavailable&quot;) }),
  ]) }),
]);

export function assertNever(x: never): never {
  throw new Error(`Unhandled: ${JSON.stringify(x)}`);
}

// app/api/post/route.ts
export async function GET(req: Request): Promise&amp;lt;Response&amp;gt; {
  const id = new URL(req.url).searchParams.get(&quot;id&quot;) ?? &quot;&quot;;
  const viewer = await getViewer(req);
  let row: PostRow | undefined;
  try {
    row = PostRow.optional().parse(
      db.prepare(&quot;SELECT title, owner FROM posts WHERE id = ?&quot;).get(id));
  } catch {
    return Response.json({ ok: false, error: { kind: &quot;Unavailable&quot; } } satisfies ApiResponse);
  }
  if (!row) return Response.json({ ok: false, error: { kind: &quot;NotFound&quot;, id } } satisfies ApiResponse);
  if (row.owner !== viewer) return Response.json({ ok: false, error: { kind: &quot;Forbidden&quot; } } satisfies ApiResponse);
  return Response.json({ ok: true, value: row.title } satisfies ApiResponse);
}

// client
type ClientError = LoadError | { kind: &quot;Transport&quot; };

async function loadTitle(id: string): Promise&amp;lt;Result&amp;lt;string, ClientError&amp;gt;&amp;gt; {
  let res: Response;
  try { res = await fetch(`/api/post?id=${encodeURIComponent(id)}`); }
  catch { return { ok: false, error: { kind: &quot;Transport&quot; } }; }
  const parsed = ApiResponseSchema.safeParse(await res.json());
  return parsed.success ? parsed.data : { ok: false, error: { kind: &quot;Transport&quot; } };
}

function label(r: Awaited&amp;lt;ReturnType&amp;lt;typeof loadTitle&amp;gt;&amp;gt;): string {
  if (r.ok) return r.value;
  switch (r.error.kind) {
    case &quot;NotFound&quot;:    return `No post ${r.error.id}`;
    case &quot;Forbidden&quot;:   return &quot;Not yours&quot;;
    case &quot;Unavailable&quot;: return &quot;Try again later&quot;;
    case &quot;Transport&quot;:   return &quot;Network trouble&quot;;
    default:            return assertNever(r.error);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;in-scrml&quot;&gt;In scrml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-scrml&quot;&gt;&amp;lt;program db=&quot;./app.db&quot;&amp;gt;

type LoadError:enum = { NotFound(id: string), Forbidden, Unavailable }

function loadTitle(id: string, viewer: string) ! LoadError {
    let row = ?{`SELECT title, owner FROM posts WHERE id = ${id}`}.get() !{
        _ :&amp;gt; { fail .Unavailable }
    }
    if (row is not) { fail .NotFound(id) }
    if (row.owner != viewer) { fail .Forbidden }
    return row.title
}

&amp;lt;msg&amp;gt; = &quot;&quot;

function show(id: string) {
    @msg = loadTitle(id, &quot;me&quot;) !{
        .NotFound(mid) :&amp;gt; &quot;No post &quot; + mid
        .Forbidden     :&amp;gt; &quot;Not yours&quot;
        .Unavailable   :&amp;gt; &quot;Try again later&quot;
        .Transport(_)  :&amp;gt; &quot;Network trouble&quot;
    }
}

&amp;lt;button onclick=show(&quot;1&quot;)&amp;gt;Load&amp;lt;/&amp;gt;
&amp;lt;p&amp;gt;${@msg}&amp;lt;/p&amp;gt;

&amp;lt;/program&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now is'nt that just so much nicer to read?&lt;/p&gt;
&lt;h3 id=&quot;where-the-typescript-went&quot;&gt;Where the TypeScript went&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;TypeScript &lt;/th&gt;&lt;th&gt;scrml&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;LoadError&lt;/code&gt; as a union of objects tagged with &lt;code&gt;kind&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;type LoadError:enum&lt;/code&gt;: variants with payloads are part of the language&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt;, and &lt;code&gt;ok: true/false&lt;/code&gt; wrapping at every return &lt;/td&gt;&lt;td&gt;&lt;code&gt;! LoadError&lt;/code&gt; on the signature, &lt;code&gt;fail .X&lt;/code&gt; in the body. A function that can fail is a language feature, not a library type&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;A Zod schema restating the wire type so the client can check it at run time &lt;/td&gt;&lt;td&gt;Nothing. &lt;code&gt;loadTitle&lt;/code&gt; runs on the server because it touches the database, and the compiler writes the encoding for its result and its errors&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;An API route, a URL, &lt;code&gt;fetch&lt;/code&gt;, a &lt;code&gt;try&lt;/code&gt; around &lt;code&gt;fetch&lt;/code&gt;, and a hand-made &lt;code&gt;&quot;Transport&quot;&lt;/code&gt; error &lt;/td&gt;&lt;td&gt;&lt;code&gt;loadTitle(id, &quot;me&quot;)&lt;/code&gt; is an ordinary call. A network failure arrives as the built-in &lt;code&gt;.Transport&lt;/code&gt; variant&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assertNever&lt;/code&gt; and a &lt;code&gt;default:&lt;/code&gt; branch to make the &lt;code&gt;switch&lt;/code&gt; complete &lt;/td&gt;&lt;td&gt;The compiler refuses an incomplete handler. Delete the &lt;code&gt;.Forbidden&lt;/code&gt; line and the build fails: &lt;code&gt;E-TYPE-080: Non-exhaustive error handler for LoadError. Missing variant(s): Forbidden&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;satisfies ApiResponse&lt;/code&gt; on every &lt;code&gt;Response.json&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Nothing to satisfy, because no response is written by hand&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Awaited&amp;lt;ReturnType&amp;lt;typeof loadTitle&amp;gt;&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Nothing to derive, because no type is threaded through generics&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;the-point&quot;&gt;The point&lt;/h3&gt;
&lt;p&gt;None of the TypeScript above is bad. Every line restates something TypeScript cannot see on its own:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the shape of what crosses the wire;&lt;/li&gt;
&lt;li&gt;the set of errors a call can produce;&lt;/li&gt;
&lt;li&gt;whether every one of them was handled.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You write those types because the compiler is blind to the server, the network and the client as one program.&lt;/p&gt;
&lt;p&gt;scrml's compiler is not blind to them. It compiles the server function, the encoding between server and browser, and the client in one pass. So it already knows the error set, already writes the encoding, and can check exhaustiveness itself. You don't need fewer guarantees. You just don't have to restate them by hand.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/33126/go-type-yourself</guid>
<pubDate>Fri, 30 Oct 2026 17:47:29 +0000</pubDate>
</item>
<item>
<title>My Servers Get Scanned Every 40 Seconds. Here's How I Stopped Caring — And Fixed It Anyway</title>
<link>https://coderlegion.com/26873/my-servers-get-scanned-every-40-seconds-heres-how-i-stopped-caring-and-fixed-it-anyway</link>
<description>&lt;p&gt;I'm exhausted. Genuinely, professionally exhausted. Every server I stand up, no matter how boring, no matter how &quot;it's just a staging box, nobody even knows the IP&quot; — gets scanned before the SSL cert finishes provisioning. I used to take it personally. I used to open &lt;code&gt;/var/log/auth.log&lt;/code&gt;, see four hundred failed logins from some IP block in a country I've never shipped a package to, and think: &lt;em&gt;why me specifically?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It's not you specifically. That's actually the first thing you need to internalize before any of the technical advice below will make sense to you emotionally instead of just intellectually. Internet-wide scanning is background radiation now. GreyNoise's Global Observation Grid clocked roughly &lt;strong&gt;212 exploitation attempts per second&lt;/strong&gt; across the back half of 2025, from nearly &lt;strong&gt;3 billion malicious sessions&lt;/strong&gt; and &lt;strong&gt;3.8 million unique source IPs&lt;/strong&gt; hitting internet-facing infrastructure. You are not being hunted. You are being &lt;em&gt;sampled&lt;/em&gt;, by the same dumb scripts that are sampling literally everyone else with a public IP, including your neighbor's smart fridge.&lt;/p&gt;
&lt;p&gt;Once that sinks in, the panic turns into engineering, which is a much more useful emotional state. So let's do the engineering.&lt;/p&gt;
&lt;h3 id=&quot;myth-1-changing-the-ssh-port-is-security-&quot;&gt;Myth #1: Changing the SSH Port Is &quot;Security&quot;&lt;/h3&gt;
&lt;p&gt;No. It isn't. I need you to hear this from someone who has changed the SSH port on every server they've ever owned: it is not security, it is noise reduction. A full port scan finds your &quot;hidden&quot; SSH port in about four seconds, and any attacker who is actually targeting &lt;em&gt;you specifically&lt;/em&gt; — as opposed to sweeping the entire IPv4 space with a botnet — will find it just as fast.&lt;/p&gt;
&lt;p&gt;What it &lt;em&gt;does&lt;/em&gt; do, and this is legitimately worth doing, is cut out the overwhelming majority of low-effort automated scanners that only ever probe port 22 because probing every port on every IP is expensive even for a botnet. Cleaner logs. Less fail2ban noise. Fewer 3 AM &quot;wait, is this real&quot; moments. Do it, but do it with your eyes open: you're sweeping the porch, not installing a deadbolt.&lt;/p&gt;
&lt;h3 id=&quot;the-actual-deadbolt-ssh-hardening-that-isn-t-theater&quot;&gt;The Actual Deadbolt: SSH Hardening That Isn't Theater&lt;/h3&gt;
&lt;p&gt;Here's the sshd config that actually matters, and I want you to notice something about it: none of it is exotic. It's the boring stuff nobody does because it involves editing a file instead of installing a shiny dashboard.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /etc/ssh/sshd_config.d/99-hardening.conf

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitEmptyPasswords no
MaxAuthTries 3
MaxSessions 4
LoginGraceTime 20

AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no

AllowUsers your_actual_username

ClientAliveInterval 300
ClientAliveCountMax 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate an Ed25519 key if you're still rocking RSA-4096 out of nostalgia — it's smaller, it's faster, and the public key is about 68 characters instead of 800-plus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519 -C &quot;you@host&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test your new config in a &lt;em&gt;second terminal&lt;/em&gt; before you reload sshd. I'm not going to explain why. If you've never locked yourself out of a box at 2 AM over a typo in &lt;code&gt;sshd_config&lt;/code&gt;, you will, and that day will teach you faster than I ever could. Just do the test-in-a-second-terminal thing now and skip the lesson.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo sshd -t &amp;amp;&amp;amp; sudo systemctl reload sshd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Password authentication being off is the single highest-leverage change on this entire list. GreyNoise's edge report noted a credential-spraying botnet targeting exposed RDP that grew from &lt;strong&gt;2,000 to 300,000 participating IPs in 72 days&lt;/strong&gt; — a 150x jump in about two and a half months, with the majority of it riding on compromised residential connections. That's the fate of anything on the internet still accepting &lt;code&gt;admin&lt;/code&gt; / &lt;code&gt;Password123!&lt;/code&gt; in 2026. Don't be the box that's still allowing it out of laziness.&lt;/p&gt;
&lt;h3 id=&quot;default-deny-firewall-because-allow-everything-block-what-i-notice-isn-t-a-strategy&quot;&gt;Default-Deny Firewall, Because &quot;Allow Everything, Block What I Notice&quot; Isn't a Strategy&lt;/h3&gt;
&lt;p&gt;Whatever you use — nftables, ufw, firewalld — the policy should be &lt;strong&gt;deny by default, allow the minimum set of ports you actually serve.&lt;/strong&gt; Not &quot;allow everything and block IPs after they annoy me.&quot; Deny-by-default means the scanners hitting the other 65,530 ports just get silently dropped, which also, pleasantly, makes your box slightly harder to fingerprint.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;limit&lt;/code&gt; instead of &lt;code&gt;allow&lt;/code&gt; on SSH isn't a typo — ufw's rate-limiting will auto-block an IP that hits the port more than six times in thirty seconds. It's a free, built-in speed bump before fail2ban even wakes up.&lt;/p&gt;
&lt;h3 id=&quot;fail2ban-vs-crowdsec-pick-a-fighter&quot;&gt;Fail2ban vs CrowdSec: Pick a Fighter&lt;/h3&gt;
&lt;p&gt;This is where I watch people either overthink it or underthink it, so let's settle it cleanly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fail2ban&lt;/strong&gt; watches your logs, notices repeated failures, and bans the offending IP at the firewall. It's been quietly doing this job for over a decade, it has zero external dependencies, it phones home to nobody, and on a 512MB box it barely registers. If you're running one server with SSH and maybe a web app, fail2ban is completely sufficient and there's a real argument for not overengineering past it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 3
bantime = 1h
findtime = 10m
ignoreip = your.own.ip.address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last line matters more than any other line in this entire article. Add your own IP to &lt;code&gt;ignoreip&lt;/code&gt; before you enable anything. Locking yourself out of your own server over your own typo is a rite of passage nobody actually enjoys.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CrowdSec&lt;/strong&gt; does the same local detection but adds a crowdsourced reputation layer: your agent optionally shares anonymized attack signals and receives a community blocklist in return, so an IP that hammered someone else's Ghost blog in Estonia last week gets pre-emptively blocked on your box before it ever sends you a single packet. It splits detection from enforcement — an engine that decides, and separate &quot;bouncers&quot; that actually carry out the ban at the firewall, at your reverse proxy, or in front of multiple servers from one shared decision list.&lt;/p&gt;
&lt;p&gt;If you're running a single personal box, fail2ban is fine — go ahead, sleep well. If you're running anything public-facing at scale, multiple servers, or you're just tired of every server relearning the same lessons independently, CrowdSec's shared blocklist and centralized decision-making genuinely earns its extra moving parts.&lt;/p&gt;
&lt;h3 id=&quot;patch-the-old-stuff-no-really-the-old-stuff&quot;&gt;Patch the Old Stuff. No, Really, the &lt;em&gt;Old&lt;/em&gt; Stuff&lt;/h3&gt;
&lt;p&gt;Here's the part that should offend your sense of narrative logic: GreyNoise's 2026 State of the Edge report found that &lt;strong&gt;pre-2015 CVEs generated roughly four times more exploitation traffic than CVEs disclosed in 2023–2024.&lt;/strong&gt; Shellshock. Old PHP-CGI bugs. Ancient WebLogic flaws. Vulnerabilities old enough to vote are still out there generating millions of exploitation attempts, because there are still millions of boxes nobody ever patched, and scanning for a decade-old known-good exploit is cheaper and more reliable for an attacker than gambling on something novel.&lt;/p&gt;
&lt;p&gt;Your bot army isn't targeting you with next-generation zero-days. It's targeting you with the software equivalent of trying every car door in the parking lot, because somewhere, someone genuinely still left it unlocked. Run &lt;code&gt;unattended-upgrades&lt;/code&gt;, set a reboot window, and stop assuming &quot;it's old, nobody cares about it anymore&quot; is a security posture. It is, statistically, the opposite of one.&lt;/p&gt;
&lt;h3 id=&quot;the-ip-reputation-illusion-is-over&quot;&gt;The IP-Reputation Illusion Is Over&lt;/h3&gt;
&lt;p&gt;If your entire defense strategy is &quot;block IPs that look sketchy,&quot; I have bad news. GreyNoise's residential-proxy research, based on 4 billion malicious sessions over 90 days, found that &lt;strong&gt;nearly 4 in 10 attacking IPs are residential&lt;/strong&gt; — ordinary home broadband, mobile data, small-business routers, quietly compromised and rented out as attack infrastructure. One residential proxy network Google's Threat Intelligence Group took down in January 2026 was running &lt;strong&gt;9 to 11 million daily active proxies&lt;/strong&gt; used by over 550 distinct threat groups, including state-sponsored ones. Your grandmother's router might, statistically, be more dangerous than she is.&lt;/p&gt;
&lt;p&gt;The takeaway isn't &quot;give up on IP blocking.&quot; It's &quot;don't let IP blocking be your &lt;em&gt;only&lt;/em&gt; layer,&quot; because the entire premise that you can infer intent from an IP address is, as GreyNoise's own CEO put it, broken at scale. Behavior-based detection (what CrowdSec's scenario engine does, what a WAF does) matters more now than reputation lists alone.&lt;/p&gt;
&lt;h3 id=&quot;troll-them-back-tarpits-are-underrated-and-extremely-funny&quot;&gt;Troll Them Back: Tarpits Are Underrated and Extremely Funny&lt;/h3&gt;
&lt;p&gt;This is my favorite category, because most security advice is defensive and boring, and tarpits let you be defensive &lt;em&gt;and&lt;/em&gt; petty, which is a combination I fully endorse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Endlessh&lt;/strong&gt; is an SSH tarpit: point it at port 22 (move your real sshd elsewhere), and it exploits a genuinely funny loophole in the SSH RFC — the server is allowed to send junk banner lines before the real version string, with no upper limit on how long it can stall. Endlessh sends an infinite trickle of random banner bytes, a few bytes every few seconds, and just… holds the connection open. Forever. Automated SSH brute-forcers, which are almost always single-threaded per target and not built to handle a server that never actually says hello, just sit there, burning a thread, going nowhere, for as long as you let them.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -p 22:2222 -p 127.0.0.1:2222:2222 --name endlessh figiel/endlessh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Nepenthes and its cousin Iocaine&lt;/strong&gt; do the same thing for web crawlers instead of SSH bots: an infinite maze of auto-generated fake pages, all linking back into themselves, all stuffed with Markov-chain gibberish that's just structured enough to look like content. Point a misbehaving scraper at it and it doesn't get an error, it doesn't get a block page — it gets an infinite hallway with no exit, and it keeps walking because nothing in its logic tells it to stop. It's less &quot;you shall not pass&quot; and more &quot;you shall pass, forever, into nothing.&quot; Deploy it behind a &lt;code&gt;Disallow&lt;/code&gt; in &lt;code&gt;robots.txt&lt;/code&gt; and let anything that ignores that directive enjoy the consequences.&lt;/p&gt;
&lt;p&gt;Neither of these replaces real hardening. Think of them as the security equivalent of leaving out a bowl of pennies for door-to-door scammers — it wastes nobody's time who matters, and it wastes a genuinely satisfying amount of time for everyone else.&lt;/p&gt;
&lt;h3 id=&quot;least-exposure-turn-off-what-you-re-not-using&quot;&gt;Least Exposure: Turn Off What You're Not Using&lt;/h3&gt;
&lt;p&gt;Every listening service is an entry point you now have to defend, patch, and think about at 3 AM. Run &lt;code&gt;ss -tulpn&lt;/code&gt;, look at every single line, and ask yourself honestly whether you meant to expose it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ss -tulpn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uninstall what you don't need. Remove build tools and compilers from production hosts — if an attacker does get a foothold, you'd rather they didn't have &lt;code&gt;gcc&lt;/code&gt; sitting there ready to compile their next stage for them. This is unglamorous work and it will not show up in a conference talk, but it closes more real doors than any single clever tool on this list.&lt;/p&gt;
&lt;h3 id=&quot;the-layered-reality-check&quot;&gt;The Layered Reality Check&lt;/h3&gt;
&lt;p&gt;None of the above is a silver bullet, and if anyone tries to sell you one tool as &quot;solves scanning forever,&quot; check their LinkedIn for how many &quot;growth hacker&quot; job titles they've had. Scanners aren't going away. GreyNoise isn't reporting billions of sessions because attackers are winning some grand campaign against you personally — they're reporting it because sweeping the entire internet costs them almost nothing and occasionally, somewhere, it works. Your job isn't to make yourself unscannable. It's to make yourself boring: patched, key-only, minimally exposed, quietly logged, and — if you're feeling generous — wasting a few bot-hours a day in a tarpit out of pure spite.&lt;/p&gt;
&lt;p&gt;Stack the boring layers. Skip the panic. Let the bots enjoy the maze.&lt;/p&gt;
</description>
<category>Discussions</category>
<guid isPermaLink="true">https://coderlegion.com/26873/my-servers-get-scanned-every-40-seconds-heres-how-i-stopped-caring-and-fixed-it-anyway</guid>
<pubDate>Fri, 11 Sep 2026 17:01:14 +0000</pubDate>
</item>
<item>
<title>How to Configure Nginx as an HTTPS Proxy Server?</title>
<link>https://coderlegion.com/18996/how-to-configure-nginx-as-an-https-proxy-server</link>
<description>
&lt;p&gt;Hello, I'm Ganesh. I'm building &lt;em&gt;git-lrc&lt;/em&gt;, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/p&gt;

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

&lt;p&gt;Now let's setup https for our nginx server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Before we start setting up https we should do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Buy a domain name from any registrar.&lt;/li&gt;
&lt;li&gt;Set up dns records to point to our server ip.&lt;/li&gt;
&lt;li&gt;Setup Certificate for our domain name.&lt;/li&gt;
&lt;li&gt;Install nginx on our server.&lt;/li&gt;
&lt;li&gt;Set up nginx server to serve our website.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Buying Domain Name
&lt;/h2&gt;

&lt;p&gt;We can buy domain name from any registrar like Namecheap, GoDaddy, etc. &lt;/p&gt;

&lt;p&gt;It depends on which name it is and the charges will be around &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up DNS Records
&lt;/h2&gt;

&lt;p&gt;Once buy setup the dns records to point to our server ip.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
For your server the ip address is [IP_ADDRESS]. &lt;br&gt;
And your domain name is [EMAIL_ADDRESS]&lt;/p&gt;

&lt;p&gt;So, you need to set up a dns record to point to your server ip.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Certificate
&lt;/h2&gt;

&lt;p&gt;Now let's setup certificate for our domain name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;example.com&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;so, we setup&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certbot &lt;span class=&quot;nt&quot;&gt;--nginx&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;example.com&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;EMAIL_ADDRESS] &lt;span class=&quot;nt&quot;&gt;--agree-tos&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-eff-email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is simple workflow on how certificate is fetched and how &lt;/p&gt;

&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftruvgc7r97ocn2ggu19.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftruvgc7r97ocn2ggu19.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key generation&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The Certbot generates a private key and a CSR (Certificate Signing Request) entirely on your machine. &lt;/p&gt;

&lt;p&gt;The private key is the core security guarantee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP-01 Challenge&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Let's Encrypt needs to verify you actually control &lt;code&gt;example.com&lt;/code&gt;. It sends Certbot a random token. &lt;/p&gt;

&lt;p&gt;Certbot places it at:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;/var/www/html/.well-known/acme-challenge/&amp;lt;random-token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nginx (already running on port 80) serves this file publicly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's Encrypt fetches the token&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;LE makes a plain HTTP request to &lt;code&gt;&lt;a href=&quot;http://example.com/.well-known/acme-challenge/&quot; rel=&quot;nofollow&quot;&gt;http://example.com/.well-known/acme-challenge/&lt;/a&gt;&amp;lt;token&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If it gets the right response back, it's satisfied that you own the domain. &lt;/p&gt;

&lt;p&gt;This is why DNS must be pointing to your server before you run Certbot &amp;mdash; if the domain pointed elsewhere, LE would fetch the token from the wrong machine and the challenge would fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Certificate issued &amp;amp; saved&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;LE signs and returns your certificate. &lt;/p&gt;

&lt;p&gt;Certbot saves four files to &lt;code&gt;/etc/letsencrypt/live/example.com/&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fullchain.pem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your cert + intermediate CA chain (this is what Nginx uses)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;privkey.pem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your private key (Nginx uses this too)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cert.pem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Just your cert alone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chain.pem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Just the CA chain alone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Nginx config is rewritten&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Certbot patches your &lt;code&gt;server&lt;/code&gt; block to add the &lt;code&gt;listen 443 ssl&lt;/code&gt; lines and the cert paths, and adds a new &lt;code&gt;server { listen 80; }&lt;/code&gt; block that redirects all HTTP traffic to HTTPS. &lt;/p&gt;

&lt;p&gt;Then it reloads Nginx for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up with nginx
&lt;/h2&gt;

&lt;p&gt;Assuming your application running in local host 8090. and you are setting up https for your domain name example.com.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight conf&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; {
    &lt;span class=&quot;n&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ssl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http2&lt;/span&gt;;
    &lt;span class=&quot;n&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;;

    &lt;span class=&quot;n&quot;&gt;ssl_certificate&lt;/span&gt;     /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;letsencrypt&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;live&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;fullchain&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;pem&lt;/span&gt;;
    &lt;span class=&quot;n&quot;&gt;ssl_certificate_key&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;letsencrypt&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;live&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;privkey&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;pem&lt;/span&gt;;

    &lt;span class=&quot;c&quot;&gt;# All requests &amp;mdash; public, no auth
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; / {
        &lt;span class=&quot;n&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;://&lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;8090&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Host&lt;/span&gt; $&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;Real&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;IP&lt;/span&gt; $&lt;span class=&quot;n&quot;&gt;remote_addr&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;Forwarded&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;For&lt;/span&gt; $&lt;span class=&quot;n&quot;&gt;proxy_add_x_forwarded_for&lt;/span&gt;;
        &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;Forwarded&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;Proto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add to symlink to sites enabled&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restarting nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;nginx &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;We could get https for our domain name example.com.&lt;/p&gt;

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

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


</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/18996/how-to-configure-nginx-as-an-https-proxy-server</guid>
<pubDate>Tue, 02 Jun 2026 16:03:57 +0000</pubDate>
</item>
<item>
<title>Public key retrieval is not allowed / Needs improvement</title>
<link>https://coderlegion.com/18848/public-key-retrieval-is-not-allowed-needs-improvement</link>
<description>&lt;p&gt;&lt;strong&gt;Today, in this article we will discuss the error message &quot;Public key retrieval is not allowed&quot;. This error &lt;span style=&quot;color: rgb(255, 4, 252);&quot;&gt;message is indicating that the system is configured to disallow the retrieval of a public key&lt;/span&gt;. This is likely a security measure &lt;span style=&quot;color: rgb(255, 4, 252);&quot;&gt;to prevent unauthorized access&lt;/span&gt; to sensitive information. It is &lt;span style=&quot;color: rgb(255, 4, 252);&quot;&gt;recommended to check with the administrator&lt;/span&gt; or technical support for further assistance.&lt;/strong&gt;&lt;/p&gt;
&lt;div id=&quot;toc-div&quot;&gt;
&lt;h4&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt;Table of Contents: &lt;a id=&quot;toc-toogle&quot; class=&quot;open&quot;&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div id=&quot;toc-list&quot;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#what&quot; rel=&quot;nofollow&quot;&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;span data-sheets-value=&quot;{&quot; data-sheets-userformat=&quot;{&quot;&gt;What does Error &quot;Public key retrieval is not allowed&quot; mean?&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#why&quot; rel=&quot;nofollow&quot;&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;Why is the Error Generated?&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sol&quot; rel=&quot;nofollow&quot;&gt;How to Solve the Error?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#con&quot; rel=&quot;nofollow&quot;&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;The Conclusion&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;a href=&quot;#con&quot; rel=&quot;nofollow&quot;&gt;The References&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;section&gt;&lt;/section&gt;
&lt;section&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt;What does error &quot;Public key retrieval is not allowed&quot; mean?&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt; &lt;a id=&quot;TypeError-str-object&quot; style=&quot;color: blue;&quot; href=&quot;#what&quot; rel=&quot;nofollow&quot;&gt;#&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The error message &quot;Public key retrieval is not allowed&quot; usually &lt;strong&gt;occurs when an application or service is trying to access a public key&lt;/strong&gt; from the server it is trying to connect to, but the operation is &lt;strong&gt;not allowed due to security or access control measures&lt;/strong&gt; that prevent the retrieval of the public key.&lt;/p&gt;
&lt;p&gt;In cryptography, public keys are used for encryption and digital signatures, while private keys are used for decryption and signing. When &lt;strong&gt;you attempt to connect to a server&lt;/strong&gt;, the system must first retrieve the server's public key &lt;strong&gt;to establish a secure connection&lt;/strong&gt;. If the &lt;strong&gt;server's public key cannot be retrieved&lt;/strong&gt;, the system may &lt;strong&gt;not be able to establish a secure connection&lt;/strong&gt;, and the error message &lt;strong&gt;&quot;Public key retrieval is not allowed&quot; will be displayed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The cause of this error can vary. This &lt;strong&gt;may happen be due to a firewall, network restriction&lt;/strong&gt;, or a policy set by the system administrator. To resolve this issue, you may &lt;strong&gt;need to contact your system administrator&lt;/strong&gt; or network administrator to request access to the public key &lt;strong&gt;or check the firewall&lt;/strong&gt; or network configurations.&lt;/p&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt;Why is the Error Generated? &lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;a id=&quot;reasons-that-will-cause&quot; style=&quot;color: blue;&quot; href=&quot;#why&quot; rel=&quot;nofollow&quot;&gt;#&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The &quot;Public key retrieval is not allowed&quot; error message can occur due to various causes. Some of the most common causes are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Firewall restriction:&lt;/strong&gt; Your system may not be able to retrieve the server's public key if the connection is being blocked by a firewall. The firewall may be configured to block connections to the server or to block the retrieval of the public key.&lt;br&gt;For example; you are trying to connect to a server over a secure connection using SSL/TLS, but the firewall is blocking the connection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Network restriction:&lt;/strong&gt; The system may not be able to retrieve the server's public key if there are restrictions in place on the network that prevent the retrieval. This could be due to a policy set by the network administrator or due to a misconfiguration of the network.&lt;br&gt;Say, you try to retrieve the public key of a server that is located in a different country, but the connection is blocked by the network administrator due to security policies. Then you will receives the error message &quot;Public key retrieval is not allowed.&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access control measures:&lt;/strong&gt; The server may have security measures in place that prevent unauthorized access to the public key. This could be due to a policy set by the system administrator or due to security software installed on the server e.g. you are trying to connect to a server that has security measures in place to prevent unauthorized access to the public key.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class MySQLConnectionExample {

  public static void main(String[] args) {
    try {
      // Load the MySQL Connector/J driver
      Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);

      // Establish a connection to the MySQL server
      Connection conn = DriverManager.getConnection(
        &quot;jdbc:mysql://localhost:3306/test_db?useSSL=true&quot;,
        &quot;username&quot;,
        &quot;password&quot;
      );

      System.out.println(&quot;Connected to the MySQL server successfully!&quot;);

      // Close the connection
      conn.close();
    } catch (SQLException | ClassNotFoundException e) {
      System.out.println(&quot;An error occurred while connecting to the MySQL server: &quot; + e.getMessage());
    }
  }
}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we first load the MySQL Connector/J driver using the &lt;code&gt;Class.forName&lt;/code&gt; method. Then, we use the &lt;code&gt;DriverManager.getConnection&lt;/code&gt; method to establish a connection to the MySQL server. The connection URL includes the &lt;code&gt;useSSL=true&lt;/code&gt; parameter, which indicates that we want to use SSL/TLS to secure the connection. We also specify the username and password to use when connecting to the server.&lt;br&gt;Here when the client is unable to retrieve the public key an error occurs, an exception will be thrown and an error message will be displayed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IP/domain restrictions:&lt;/strong&gt; The server may be configured to only allow public key retrieval from specific IP addresses or domains. If you are not on the approved list, it may not be able to retrieve the public key.&lt;br&gt;An example is that you are trying to connect to a server that is configured to only allow public key retrieval from specific IP addresses or domains and your system is not on the approved list, so the will receive the error.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Incorrect server configuration:&lt;/strong&gt; The server may be misconfigured, which could prevent the retrieval of the public key. This could be due to an error in the server's settings or due to an incorrect configuration of the server's software. For example, you try to connect to a server that is misconfigured, which prevents the retrieval of the public key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Certificate issues:&lt;/strong&gt; The server may have an expired or revoked certificate, which could prevent the retrieval of the public key. In this case, the system may not be able to establish a secure connection with the server. For example, you will try to connect to a server that has an expired or revoked certificate, which prevents the retrieval of the public key.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class=&quot;div-purple&quot;&gt;&lt;span class=&quot;alert-header&quot;&gt;Note&lt;/span&gt; &lt;span class=&quot;alert-body&quot;&gt;It is important to understand the cause of the &quot;Public key retrieval is not allowed&quot; error in order to resolve it effectively. Depending on the cause, you may need to make apply the appropiate solution.&lt;/span&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section&gt;&lt;a id=&quot;sol&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;&lt;/section&gt;
&lt;section&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt;How to Solve the Error? &lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;a id=&quot;the-solution&quot; style=&quot;color: blue;&quot; href=&quot;#sol&quot; rel=&quot;nofollow&quot;&gt;#&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The possible solutions for the causes of the &quot;Public key retrieval is not allowed&quot; error message are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Firewall restriction:&lt;/strong&gt; To resolve this issue, you can check the firewall configuration and ensure that the connection to the server is not being blocked. You may also need to open specific ports or add an exception to the firewall to allow the connection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Network restriction:&lt;/strong&gt; To resolve this issue, you may need to contact the network administrator and request that the restriction be lifted or that the necessary changes be made to the network configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access control measures:&lt;/strong&gt; To resolve this issue, you may need to request access to the public key from the system administrator or the security software provider. The system administrator may need to change the security measures in place to allow you to retrieve the public key. Like, the error in previous coding example occurs due to &lt;code&gt;useSSL=true&lt;/code&gt; parameter. Therefore, we change it to &lt;code&gt;useSSL=false&lt;/code&gt; as done below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class MySQLConnectionExample {

  public static void main(String[] args) {
    try {
      // Load the MySQL Connector/J driver
      Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);

      // Establish a connection to the MySQL server
      Connection conn = DriverManager.getConnection(
        &quot;jdbc:mysql://localhost:3306/test_db?useSSL=false&quot;,
        &quot;username&quot;,
        &quot;password&quot;
      );

      System.out.println(&quot;Connected to the MySQL server successfully!&quot;);

      // Close the connection
      conn.close();
    } catch (SQLException | ClassNotFoundException e) {
      System.out.println(&quot;An error occurred while connecting to the MySQL server: &quot; + e.getMessage());
    }
  }
}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you change the value of &lt;code&gt;useSSL&lt;/code&gt; in the connection string from &lt;code&gt;true&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;, then the connection will no longer attempt to use SSL encryption. This change can resolve the &quot;Public key retrieval is not allowed&quot; error if the issue was caused by a problem with the server's SSL certificate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IP/domain restrictions:&lt;/strong&gt; To resolve this issue, one may need to check the server configuration and ensure that your IP address or domain is on the approved list. If the IP address or domain is not on the approved list, you may need to request that it be added.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Incorrect server configuration:&lt;/strong&gt; To resolve this issue, you may need to check the server configuration and make any necessary changes to ensure that the server is configured correctly. You may also need to check the server software and ensure that it is installed and configured correctly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Certificate issues:&lt;/strong&gt; To resolve this issue, you may need to check the server certificate and ensure that it is valid and up-to-date. If the certificate is expired or revoked, you may need to request a new certificate from a trusted certificate authority.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section&gt;&lt;/section&gt;
&lt;section&gt;&lt;a id=&quot;con&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt;The Conclusion&lt;/strong&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, the &quot;Public key retrieval is not allowed&quot; &lt;strong&gt;error message indicates that the your are unable to retrieve the server's public key&lt;/strong&gt;, which is &lt;strong&gt;required to establish a secure connection&lt;/strong&gt; using SSL/TLS. This error can be &lt;strong&gt;caused by various factors&lt;/strong&gt;, including firewall restrictions, network restrictions, access control measures, IP/domain restrictions, incorrect server configuration, and certificate issues. To resolve the issue you may need to &lt;strong&gt;check for the cause&lt;/strong&gt; of the error in your specific situation and &lt;strong&gt;apply the suitable solution&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section&gt;&lt;a id=&quot;ref&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt;The References&lt;/strong&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Some resources for reference or further information are given below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;MySQL Connector/J documentation:&lt;br&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-using-ssl.html&quot; target=&quot;_new&quot;&gt;https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-using-ssl.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java API documentation:&lt;br&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.oracle.com/en/java/javase/14/docs/api/java.sql/java/sql/Driver.html&quot; target=&quot;_new&quot;&gt;https://docs.oracle.com/en/java/javase/14/docs/api/java.sql/java/sql/Driver.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MySQL official forums:&lt;br&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://forums.mysql.com/&quot; target=&quot;_new&quot;&gt;https://forums.mysql.com/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18848/public-key-retrieval-is-not-allowed-needs-improvement</guid>
<pubDate>Mon, 25 May 2026 04:13:39 +0000</pubDate>
</item>
<item>
<title>How to Configure Nginx as a Proxy Server?</title>
<link>https://coderlegion.com/16116/how-to-configure-nginx-as-a-proxy-server</link>
<description>
&lt;p&gt;Hello, I'm Ganesh. I'm building &lt;em&gt;git-lrc&lt;/em&gt;, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/p&gt;

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

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


</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/16116/how-to-configure-nginx-as-a-proxy-server</guid>
<pubDate>Fri, 01 May 2026 11:10:59 +0000</pubDate>
</item>
<item>
<title>Why CI/CD Changed Software Development Forever</title>
<link>https://coderlegion.com/15722/why-ci-cd-changed-software-development-forever</link>
<description>&lt;p&gt;There was a time when deploying software was scary.&lt;/p&gt;
&lt;p&gt;Really scary.&lt;/p&gt;
&lt;p&gt;Developers would write code for weeks…&lt;/p&gt;
&lt;p&gt;Then manually deploy everything at once and pray:&lt;/p&gt;
&lt;p&gt; “Hope nothing breaks in production.”&lt;/p&gt;
&lt;p&gt;Sometimes it worked.&lt;/p&gt;
&lt;p&gt;Sometimes…&lt;/p&gt;
&lt;p&gt;Production exploded &lt;/p&gt;
&lt;p&gt;That’s exactly the problem &lt;strong&gt;CI/CD&lt;/strong&gt; helped solve.&lt;/p&gt;
&lt;p&gt;Let’s break it down simply &lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;before-ci-cd-releases-were-painful&quot;&gt;Before CI/CD: Releases Were Painful&lt;/h3&gt;
&lt;p&gt;Earlier, shipping software often looked like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developers wrote code for weeks&lt;/li&gt;
&lt;li&gt;Changes piled up&lt;/li&gt;
&lt;li&gt;Big release day arrived&lt;/li&gt;
&lt;li&gt;Team manually deployed everything&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unexpected bugs&lt;/li&gt;
&lt;li&gt;Broken builds&lt;/li&gt;
&lt;li&gt;Failed deployments&lt;/li&gt;
&lt;li&gt;Long downtime&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Releasing software felt risky.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-common-problems-before-ci-cd&quot;&gt;⚠️ Common Problems Before CI/CD&lt;/h3&gt;
&lt;p&gt;Without automation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Testing was often manual&lt;/li&gt;
&lt;li&gt;Bugs were caught late&lt;/li&gt;
&lt;li&gt;Deployments were error-prone&lt;/li&gt;
&lt;li&gt;Rollbacks were messy&lt;/li&gt;
&lt;li&gt;“Works on my machine” became a lifestyle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sound familiar? &lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-is-ci-cd-&quot;&gt;What is CI/CD?&lt;/h2&gt;
&lt;p&gt;CI/CD stands for:&lt;/p&gt;
&lt;h4 id=&quot;-continuous-integration-ci-&quot;&gt;✅ Continuous Integration (CI)&lt;/h4&gt;
&lt;p&gt;Developers push code frequently.&lt;/p&gt;
&lt;p&gt;Every change automatically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Builds the project&lt;/li&gt;
&lt;li&gt;Runs tests&lt;/li&gt;
&lt;li&gt;Checks if anything broke&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Problems are caught early.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;continuous-delivery-deployment-cd-&quot;&gt;Continuous Delivery / Deployment (CD)&lt;/h4&gt;
&lt;p&gt;After code passes checks:&lt;/p&gt;
&lt;p&gt;It can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prepared for release automatically&lt;/li&gt;
&lt;li&gt;Or deployed automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Shipping becomes faster and safer.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-happens-in-a-ci-cd-pipeline-&quot;&gt;What Happens in a CI/CD Pipeline?&lt;/h3&gt;
&lt;p&gt;Typical flow:&lt;/p&gt;
&lt;p&gt;Code Push → Build → Test → Security Checks → Deploy&lt;/p&gt;
&lt;p&gt;Simple idea.&lt;/p&gt;
&lt;p&gt;Powerful impact.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-this-changed-everything&quot;&gt;Why This Changed Everything&lt;/h3&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;p&gt;❌ Big risky releases&lt;/p&gt;
&lt;p&gt;Now:&lt;/p&gt;
&lt;p&gt;✅ Small frequent safe releases&lt;/p&gt;
&lt;p&gt;That changes software development completely.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-real-benefits-of-ci-cd&quot;&gt;⚡ Real Benefits of CI/CD&lt;/h3&gt;
&lt;h4 id=&quot;faster-development&quot;&gt;Faster Development&lt;/h4&gt;
&lt;p&gt;Developers ship features quicker.&lt;/p&gt;
&lt;p&gt;No waiting for huge release cycles.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;better-code-quality&quot;&gt;Better Code Quality&lt;/h4&gt;
&lt;p&gt;Automated tests catch issues early.&lt;/p&gt;
&lt;p&gt; Less broken code reaching users.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;safer-deployments&quot;&gt;Safer Deployments&lt;/h4&gt;
&lt;p&gt;Every deployment follows a repeatable process.&lt;/p&gt;
&lt;p&gt;No random manual mistakes.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;faster-bug-fixes&quot;&gt;Faster Bug Fixes&lt;/h4&gt;
&lt;p&gt;Critical issue?&lt;/p&gt;
&lt;p&gt;Push fix.&lt;/p&gt;
&lt;p&gt;Pipeline runs.&lt;/p&gt;
&lt;p&gt;Deploy.&lt;/p&gt;
&lt;p&gt;Done.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;real-world-example&quot;&gt;Real-World Example&lt;/h3&gt;
&lt;p&gt;Imagine updating a payment feature.&lt;/p&gt;
&lt;p&gt;Without CI/CD:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manual tests&lt;/li&gt;
&lt;li&gt;Manual deploy&lt;/li&gt;
&lt;li&gt;High risk&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With CI/CD:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Push code&lt;/li&gt;
&lt;li&gt;Tests run automatically&lt;/li&gt;
&lt;li&gt;Deploy safely&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Huge difference.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;tools-you-ve-probably-heard-of&quot;&gt;Tools You’ve Probably Heard Of&lt;/h3&gt;
&lt;p&gt;Popular CI/CD tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;GitLab CI/CD&lt;/li&gt;
&lt;li&gt;Jenkins&lt;/li&gt;
&lt;li&gt;CircleCI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Different tools.&lt;/p&gt;
&lt;p&gt;Same mission:&lt;/p&gt;
&lt;p&gt; Automate software delivery.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-modern-teams-can-t-ignore-it&quot;&gt;Why Modern Teams Can’t Ignore It&lt;/h3&gt;
&lt;p&gt;Today apps update constantly.&lt;/p&gt;
&lt;p&gt;Think about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Netflix&lt;/li&gt;
&lt;li&gt;Amazon&lt;/li&gt;
&lt;li&gt;Spotify&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They can’t do manual deployments all day.&lt;/p&gt;
&lt;p&gt;CI/CD makes modern scale possible.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-is-ci-cd-just-for-big-companies-&quot;&gt;⚠️ Is CI/CD Just for Big Companies?&lt;/h3&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;p&gt;Even small projects benefit.&lt;/p&gt;
&lt;p&gt;Because automation early saves pain later.&lt;/p&gt;
&lt;p&gt;Huge lesson.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-big-shift&quot;&gt;The Big Shift&lt;/h3&gt;
&lt;p&gt;CI/CD changed development from:&lt;/p&gt;
&lt;p&gt;❌ “Deploy carefully and hope”&lt;/p&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;p&gt;✅ “Deploy confidently and often”&lt;/p&gt;
&lt;p&gt;That’s a mindset shift.&lt;/p&gt;
&lt;p&gt;Not just a tool shift.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thought&quot;&gt;Final Thought&lt;/h3&gt;
&lt;p&gt;CI/CD didn’t just make deployments faster.&lt;/p&gt;
&lt;p&gt; It changed how software gets built.&lt;/p&gt;
&lt;p&gt;Less fear.&lt;br&gt;
More automation.&lt;br&gt;
Faster delivery.&lt;/p&gt;
&lt;p&gt;And honestly…&lt;/p&gt;
&lt;p&gt;Modern software would look very different without it &lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15722/why-ci-cd-changed-software-development-forever</guid>
<pubDate>Fri, 24 Apr 2026 11:13:00 +0000</pubDate>
</item>
<item>
<title>Cool SQL Server Features You Can Use in Real World.</title>
<link>https://coderlegion.com/12233/cool-sql-server-features-you-can-use-in-real-world</link>
<description>&lt;p&gt;If you ever had to “fix a batch” of invoices, reset workflow statuses, or reprocess failed documents, you know the pain, one mistake and you either update too much, or you update the right rows but lose the evidence of what changed.&lt;/p&gt;
&lt;p&gt;SQL Server has a few features that make these scripts safer, easier to review, and much easier to debug later. Below is a clean demo that you can paste in SSMS and use in your daily work.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET NOCOUNT ON;
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRAN;

    /* 1) Demo table (drop + create) */
    IF OBJECT_ID('dbo.DocumentRepositoryDemo', 'U') IS NOT NULL
        DROP TABLE dbo.DocumentRepositoryDemo;

    CREATE TABLE dbo.DocumentRepositoryDemo
    (
        DocumentRepositoryID bigint IDENTITY(1,1) NOT NULL CONSTRAINT PK_DocumentRepositoryDemo PRIMARY KEY,
        OriginalInvoiceID    varchar(50) NOT NULL,
        WorkflowStatus       int NOT NULL,
        HasResponse          bit NOT NULL,
        IsForwardedTP        bit NOT NULL,
        ModifiedAtUtc        datetime2(3) NULL,
        ModifiedBy           sysname NULL
    );

    /* 2) Seed some fake data */
    INSERT dbo.DocumentRepositoryDemo
        (OriginalInvoiceID, WorkflowStatus, HasResponse, IsForwardedTP, ModifiedAtUtc, ModifiedBy)
    VALUES
        ('7601002721400-318242', 2, 1, 1, SYSUTCDATETIME(), SUSER_SNAME()),
        ('7601002721400-318161', 3, 1, 0, SYSUTCDATETIME(), SUSER_SNAME()),
        ('7601001392038-318127', 4, 0, 1, SYSUTCDATETIME(), SUSER_SNAME()),
        ('7601000777447-967851', 9, 0, 0, SYSUTCDATETIME(), SUSER_SNAME()),
        ('7601000777447-968159', 1, 1, 1, SYSUTCDATETIME(), SUSER_SNAME());

    /* 3) Target list (table variable) */
    DECLARE @InvoiceIds TABLE
    (
        OriginalInvoiceID varchar(50) NOT NULL PRIMARY KEY
    );

    INSERT INTO @InvoiceIds (OriginalInvoiceID)
    VALUES
        ('7601002721400-318242'),
        ('7601002721400-318161'),
        ('7601000777447-968159');

    /* 4) Change tracking (audit table variable) */
    DECLARE @Changed TABLE
    (
        DocumentRepositoryID bigint,
        OriginalInvoiceID    varchar(50),
        OldWorkflowStatus    int,
        NewWorkflowStatus    int,
        OldHasResponse       bit,
        NewHasResponse       bit,
        OldIsForwardedTP     bit,
        NewIsForwardedTP     bit,
        ChangedAtUtc         datetime2(3),
        ChangedBy            sysname
    );

    /* 5) Update + capture before/after with OUTPUT */
    UPDATE dr
        SET dr.WorkflowStatus = 5,
            dr.HasResponse = 0,
            dr.IsForwardedTP = 0,
            dr.ModifiedAtUtc = SYSUTCDATETIME(),
            dr.ModifiedBy = SUSER_SNAME()
    OUTPUT
        deleted.DocumentRepositoryID,
        deleted.OriginalInvoiceID,
        deleted.WorkflowStatus, inserted.WorkflowStatus,
        deleted.HasResponse, inserted.HasResponse,
        deleted.IsForwardedTP, inserted.IsForwardedTP,
        inserted.ModifiedAtUtc,
        inserted.ModifiedBy
    INTO @Changed
    (
        DocumentRepositoryID,
        OriginalInvoiceID,
        OldWorkflowStatus, NewWorkflowStatus,
        OldHasResponse, NewHasResponse,
        OldIsForwardedTP, NewIsForwardedTP,
        ChangedAtUtc,
        ChangedBy
    )
    FROM dbo.DocumentRepositoryDemo dr
    INNER JOIN @InvoiceIds i
        ON i.OriginalInvoiceID = dr.OriginalInvoiceID
    WHERE dr.WorkflowStatus &amp;lt;&amp;gt; 5
       OR dr.HasResponse &amp;lt;&amp;gt; 0
       OR dr.IsForwardedTP &amp;lt;&amp;gt; 0;

    /* 6) Results */
    SELECT *
    FROM @Changed
    ORDER BY OriginalInvoiceID, DocumentRepositoryID;

    SELECT COUNT(*) AS RowsUpdated
    FROM @Changed;

    COMMIT TRAN
END TRY
BEGIN CATCH
    IF XACT_STATE() &amp;lt;&amp;gt; 0
        ROLLBACK TRAN
    THROW
END CATCH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What makes this “SQL Server cool” (and why it matters)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SQL Server normally prints messages like “(1 row affected)” after every statement. That is fine in ad hoc work, but noisy in scripts that do multiple steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With SET NOCOUNT ON:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;result sets stay clean (only the output you intentionally select),&lt;/li&gt;
&lt;li&gt;less chatter between server and client,&lt;/li&gt;
&lt;li&gt;stored procedures often become easier to consume from apps and jobs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;SET XACT_ABORT ON&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With XACT_ABORT ON, when a runtime error happens (conversion, constraint violation, etc.), SQL Server forces the transaction into a state where it cannot silently continue. In practice, this reduces the chance you end up with a transaction left open, or partially executed logic that you forget to undo.&lt;/p&gt;
&lt;p&gt;It pairs perfectly with TRY/CATCH because it pushes you toward “all or nothing”.&lt;/p&gt;
&lt;p&gt;3) TRY/CATCH + XACT_STATE(), predictable rollback logic&lt;/p&gt;
&lt;p&gt;XACT_STATE() helps because it tells you the transaction state:&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;1 there is an active, committable transaction&lt;br&gt;
-1 the transaction is uncommittable, you must rollback &lt;br&gt;
 0 no active transaction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That is why this pattern is so common:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IF XACT_STATE() &amp;lt;&amp;gt; 0
    ROLLBACK TRAN;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4) Table variables as “scoped in memory tables”&lt;/p&gt;
&lt;p&gt;This script uses two table variables:&lt;/p&gt;
&lt;p&gt;@InvoiceIds is a safe target list&lt;/p&gt;
&lt;p&gt;@Changed is an audit collector&lt;/p&gt;
&lt;p&gt;Why that’s useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you avoid long IN (...) lists inside the update,&lt;/li&gt;
&lt;li&gt;your target list can be validated and deduped (the PRIMARY KEY&lt;br&gt;
prevents duplicates),&lt;/li&gt;
&lt;li&gt;you keep the update set based, readable, and reviewable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Important detail for accuracy: table variables are often called “in memory”, but they can spill to tempdb depending on size and query plan. Still, they are great for small and medium sets.&lt;/p&gt;
&lt;p&gt;5) OUTPUT deleted, inserted, instant before/after audit&lt;/p&gt;
&lt;p&gt;This is one of the most underrated features for operational work.&lt;/p&gt;
&lt;p&gt;OUTPUT gives you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deleted.* values before the update &lt;/li&gt;
&lt;li&gt;inserted.* values after the update&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;show exactly what changed, &lt;/li&gt;
&lt;li&gt;store it into @Changed, optionally persist&lt;/li&gt;
&lt;li&gt;it into a real audit table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the difference between “I ran a script” and “I can prove exactly what the script did”.&lt;/p&gt;
&lt;p&gt;Takeaways : &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;NOCOUNT keeps scripts readable and reduces noise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;XACT_ABORT makes failure behavior safer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TRY/CATCH plus XACT_STATE() gives you consistent rollback behavior.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Table variables make targeting and audit capture clean and scoped.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OUTPUT gives you real auditing with almost no extra effort.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoiding unnecessary updates is a performance win and a safety win.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12233/cool-sql-server-features-you-can-use-in-real-world</guid>
<pubDate>Fri, 27 Feb 2026 08:17:57 +0000</pubDate>
</item>
</channel>
</rss>