[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f1hrkl2juv37jr":3,"$fanuq43nlrv5g":56},{"slug":4,"title":5,"body":6,"summary":7,"tags":8,"author":14,"cover_url":15,"published_at":16,"seo_title":17,"seo_description":18,"reading_minutes":19,"related":20},"docker-published-ports-bypass-ufw-vps-hardening","Docker publishes ports straight past UFW: hardening a fresh VPS without the firewall rule that does nothing","\u003Cp>A one-command VPS hardening script went round X this week, and the replies were the usual mix: people who had never thought about it, and people who had already been bitten. The bite is almost always the same one. You enable \u003Ccode>ufw\u003C\u002Fcode>, you allow only SSH and HTTPS, you run \u003Ccode>docker run -p 8080:80 something\u003C\u002Fcode>, and port 8080 is open to the whole internet anyway.\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6acb136edbaf8c2bc523d172\">\u003Cvideo src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acb136fdbaf8c2bc523d183-0-bb73eca4.mp4\" autoplay muted loop playsinline preload=\"metadata\">\u003C\u002Fvideo>\u003C\u002Ffigure>\n\u003Cp>That is not a ufw bug and not a misconfiguration on your side. Docker's documentation says it plainly: Docker and ufw use firewall rules in ways that make them incompatible, because Docker routes container traffic in the \u003Ccode>nat\u003C\u002Fcode> table, so packets are diverted before they reach the \u003Ccode>INPUT\u003C\u002Fcode> and \u003Ccode>OUTPUT\u003C\u002Fcode> chains that ufw uses. Your \u003Ccode>ufw deny\u003C\u002Fcode> rule is real; the packets just never pass through it.\u003C\u002Fp>\n\u003Cp>This guide takes a fresh Ubuntu\u002FDebian VPS to a state where the only open ports are the ones you meant, in about 15 minutes. Everything runs as a sudo user, not root.\u003C\u002Fp>\n\n\u003Ch2>1. SSH: keys only\u003C\u002Fh2>\n\u003Cp>From your laptop, copy your key first (and test that you can log in with it before you change anything):\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6acb12dfdbaf8c2bc523d0c1\">\u003Cimg src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acb12dfdbaf8c2bc523d0c6-0-a9cb6579.png\" alt=\"Securing server access with SSH keys is the first line of defense.\" loading=\"lazy\">\u003Cfigcaption>Securing server access with SSH keys is the first line of defense.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">ssh-copy-id deploy@203.0.113.10\nssh deploy@203.0.113.10\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>On the server, drop a config snippet instead of editing the main file, so package upgrades do not fight you:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> \u003Cspan class=\"hljs-built_in\">tee\u003C\u002Fspan> \u002Fetc\u002Fssh\u002Fsshd_config.d\u002F10-hardening.conf &gt;\u002Fdev\u002Fnull &lt;&lt;\u003Cspan class=\"hljs-string\">&#x27;EOF&#x27;\u003C\u002Fspan>\nPermitRootLogin no\nPasswordAuthentication no\nKbdInteractiveAuthentication no\nEOF\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> sshd -t &amp;&amp; \u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> systemctl reload ssh\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>sshd -t\u003C\u002Fcode> checks the config before the reload. Keep your current session open and confirm a second login works before you close it. On some distributions the service is called \u003Ccode>sshd\u003C\u002Fcode> rather than \u003Ccode>ssh\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Ch2>2. fail2ban for the SSH noise\u003C\u002Fh2>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> apt-get update\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> apt-get install -y fail2ban\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> systemctl \u003Cspan class=\"hljs-built_in\">enable\u003C\u002Fspan> --now fail2ban\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> fail2ban-client status sshd\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>With password logins off, fail2ban is mostly about keeping logs readable; the key-only setting is what actually stops guessing.\u003C\u002Fp>\n\n\u003Ch2>3. ufw for the host\u003C\u002Fh2>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> apt-get install -y ufw\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw default deny incoming\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw default allow outgoing\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow OpenSSH\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow 80\u002Ftcp\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow 443\u002Ftcp\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw \u003Cspan class=\"hljs-built_in\">enable\u003C\u002Fspan>\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw status verbose\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This protects services running directly on the host. It does \u003Cstrong>not\u003C\u002Fstrong> protect container ports that Docker publishes. That is the part most scripts skip.\u003C\u002Fp>\n\n\u003Ch2>4. See the problem for yourself\u003C\u002Fh2>\n\u003Cp>Start a throwaway container with a published port, and deny that port in ufw:\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6acb12dfdbaf8c2bc523d0cb\">\u003Cimg src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acb12dfdbaf8c2bc523d0d0-0-936dd99a.png\" alt=\"Docker traffic often bypasses standard UFW rules due to how it handles network routing.\" loading=\"lazy\">\u003Cfigcaption>Docker traffic often bypasses standard UFW rules due to how it handles network routing.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">docker run -d --name leaktest -p 8080:80 nginx:alpine\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw deny 8080\u002Ftcp\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Now, from a different machine (your laptop, not the server):\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">curl -sI http:\u002F\u002F203.0.113.10:8080 | \u003Cspan class=\"hljs-built_in\">head\u003C\u002Fspan> -n 1\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"code-block\">\u003Ccode class=\"hljs\">HTTP\u002F1.1 200 OK\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The ufw rule is there and the page still loads. Docker's port-publishing docs explain the default: when a port is mapped without a host address, the daemon publishes it on all host addresses, \u003Ccode>0.0.0.0\u003C\u002Fcode> and \u003Ccode>[::]\u003C\u002Fcode>. The same page calls publishing container ports \"insecure by default\".\u003C\u002Fp>\n\n\u003Ch2>5. Fix A: bind published ports to localhost\u003C\u002Fh2>\n\u003Cp>For most small setups this is the right fix. Your app containers do not need to be reachable from the internet; your reverse proxy (Caddy, Traefik, nginx) does. Publish the app on the loopback address only and let the proxy on 80\u002F443 forward to it:\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6acb12dfdbaf8c2bc523d0d5\">\u003Cimg src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acb12dfdbaf8c2bc523d0da-0-20658d30.png\" alt=\"Binding ports to localhost ensures services are only reachable via a controlled proxy.\" loading=\"lazy\">\u003Cfigcaption>Binding ports to localhost ensures services are only reachable via a controlled proxy.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">docker \u003Cspan class=\"hljs-built_in\">rm\u003C\u002Fspan> -f leaktest\ndocker run -d --name leaktest -p 127.0.0.1:8080:80 nginx:alpine\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>In Compose, the same thing goes in the \u003Ccode>ports\u003C\u002Fcode> list:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"yaml\">\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">services:\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">app:\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-attr\">image:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">nginx:alpine\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-attr\">ports:\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-bullet\">-\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&quot;127.0.0.1:8080:80&quot;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>To make loopback the default for the default bridge network, so a forgotten address does not open a port, set the \u003Ccode>ip\u003C\u002Fcode> key in \u003Ccode>\u002Fetc\u002Fdocker\u002Fdaemon.json\u003C\u002Fcode>. Do not confuse it with \u003Ccode>bip\u003C\u002Fcode>: \u003Ccode>bip\u003C\u002Fcode> sets the address of the \u003Ccode>docker0\u003C\u002Fcode> bridge itself, while \u003Ccode>ip\u003C\u002Fcode> is the default host address that published ports bind to (the daemon's \u003Ccode>--ip\u003C\u002Fcode> flag, default \u003Ccode>0.0.0.0\u003C\u002Fcode>). Docker's port-publishing page documents exactly this use:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"json\">\u003Ccode class=\"hljs language-json\">\u003Cspan class=\"hljs-punctuation\">{\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">&quot;ip&quot;\u003C\u002Fspan>\u003Cspan class=\"hljs-punctuation\">:\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&quot;127.0.0.1&quot;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-punctuation\">}\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> systemctl restart docker\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Note the scope: Docker documents this key for the \u003Cem>default\u003C\u002Fem> bridge network. Containers on user-defined networks (which Compose creates) still need the explicit \u003Ccode>127.0.0.1:\u003C\u002Fcode> prefix, so keep writing it.\u003C\u002Fp>\n\n\u003Ch2>6. Fix B: rules in the DOCKER-USER chain\u003C\u002Fh2>\n\u003Cp>Sometimes a container port really must be public, but only to some addresses (an office IP, a monitoring service). Do not edit Docker's own chains: the docs warn against modifying the rules Docker creates. Docker gives you a chain for this instead, \u003Ccode>DOCKER-USER\u003C\u002Fcode>, which is processed before its own \u003Ccode>DOCKER-FORWARD\u003C\u002Fcode> and \u003Ccode>DOCKER\u003C\u002Fcode> chains.\u003C\u002Fp>\n\u003Cp>Find your external interface name first:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">ip -o route get 1.1.1.1 | awk \u003Cspan class=\"hljs-string\">&#x27;{print $5}&#x27;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Then, with \u003Ccode>eth0\u003C\u002Fcode> as an example, drop everything arriving on that interface that is not from your allowed range. This is the docs' own example pattern:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> iptables -I DOCKER-USER -i eth0 ! -s 192.0.2.0\u002F24 -j DROP\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Two things to know. First, that rule drops all external traffic to all published containers except from the range, so if you also serve a public site from a container, allow it explicitly. Docker's docs show matching on the original destination port with conntrack, because by the time packets reach this chain the destination has already been rewritten to the container's address:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> iptables -I DOCKER-USER -p tcp -m conntrack --ctorigdstport 443 -j ACCEPT\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The docs note the conntrack extension may degrade performance. Also let reply traffic back in, or containers lose their own outbound connections (package downloads, API calls), since the replies arrive on the external interface too:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> iptables -I DOCKER-USER -m state --state RELATED,ESTABLISHED -j ACCEPT\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Second, order matters. \u003Ccode>iptables -I\u003C\u002Fcode> inserts at the top of the chain, so the command you run last is evaluated first. Run the commands in the order shown here (DROP, then the port ACCEPT, then the ESTABLISHED ACCEPT) and the chain reads ACCEPT, ACCEPT, DROP from the top. Check it before you log out:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> iptables -L DOCKER-USER -n --line-numbers\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The DROP rule must be below both ACCEPT rules. These rules are not persistent across reboots on their own; save them with whatever your distro uses (for example \u003Ccode>iptables-persistent\u003C\u002Fcode>) and re-check after a Docker upgrade.\u003C\u002Fp>\n\u003Cp>If you only remember one of the two fixes, make it Fix A. It needs no firewall knowledge and it fails closed.\u003C\u002Fp>\n\n\u003Ch2>7. Prove it from outside\u003C\u002Fh2>\n\u003Cp>The only test that counts is one run from another network. From your laptop:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">nmap -Pn -p 22,80,443,8080 203.0.113.10\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"code-block\">\u003Ccode class=\"hljs\">PORT     STATE    SERVICE\n22\u002Ftcp   open     ssh\n80\u002Ftcp   open     http\n443\u002Ftcp  open     https\n8080\u002Ftcp filtered http-proxy\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>And on the server, list what is actually listening on all addresses:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ss -tlnp | grep -v \u003Cspan class=\"hljs-string\">&#x27;127.0.0.1&#x27;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Anything bound to \u003Ccode>0.0.0.0\u003C\u002Fcode> or \u003Ccode>[::]\u003C\u002Fcode> that you did not expect is a port to explain. Run the scan again after every new \u003Ccode>docker compose up\u003C\u002Fcode> that adds a \u003Ccode>ports:\u003C\u002Fcode> entry; this is where leaks come back.\u003C\u002Fp>\n\n\u003Ch2>Checklist\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>SSH: keys only, root login off, config tested with \u003Ccode>sshd -t\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>ufw: default deny incoming, allow 22\u002F80\u002F443. Understand it does not cover published container ports.\u003C\u002Fli>\n\u003Cli>Every \u003Ccode>ports:\u003C\u002Fcode> entry starts with \u003Ccode>127.0.0.1:\u003C\u002Fcode> unless it must be public.\u003C\u002Fli>\n\u003Cli>Public-but-restricted container ports: rules in \u003Ccode>DOCKER-USER\u003C\u002Fcode>, saved persistently.\u003C\u002Fli>\n\u003Cli>An \u003Ccode>nmap\u003C\u002Fcode> from outside after every deploy that changes ports.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Sources\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fnetwork\u002Fpacket-filtering-firewalls\u002F\">Docker docs: Packet filtering and firewalls\u003C\u002Fa> (ufw incompatibility, do not modify Docker's rules)\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fnetwork\u002Ffirewall-iptables\u002F\">Docker docs: Docker with iptables\u003C\u002Fa> (DOCKER-USER chain, conntrack examples)\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fnetwork\u002Fport-publishing\u002F\">Docker docs: Port publishing and mapping\u003C\u002Fa> (default bind to all addresses, 127.0.0.1 binding, the \u003Ccode>ip\u003C\u002Fcode> daemon key)\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fx.com\u002Fwlzh\u002Fstatus\u002F2108480640937087284\">The hardening-script post on X that started the discussion\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>","ufw deny 8080 does not stop a Docker container published on 8080. Docker's own docs explain why. A 15-minute fresh-VPS walkthrough: key-only SSH, ufw, then the two fixes that actually close a container port, and a scan from outside to prove it.",[9,10,11,12,13],"docker","security","vps","firewall","ai-assisted","if.codes","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acb12dddbaf8c2bc523d0bb-0-21ee3023.png","2026-10-11T05:42:15.363Z","Docker bypasses UFW: closing published ports on a fresh VPS","Why ufw deny does not stop a published Docker port, and two fixes from Docker's docs: bind to 127.0.0.1 or use DOCKER-USER. Plus an outside scan to prove it.",6,[21,33,45],{"slug":22,"title":23,"type":24,"summary":25,"tags":26,"author":14,"cover_url":30,"published_at":31,"updated_at":32},"deno-deploy-shutdown-exit-guide","Deno Deploy shuts down in six months: moving a small app to Cloudflare Workers, self-hosted Deno in Docker, or Node","blog","Deno is joining Cloudflare: Deploy has six months left and the runtime gets a year of fixes. Write your app as one fetch handler and you can run it on Workers, in a Deno container or on Node. Code for all three, plus what does not carry over.",[27,28,29,9,13],"deno","cloudflare-workers","migration","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac9c181dbaf8c2bc523a0fd-0-caa268de.png","2026-10-10T05:47:19.665Z","2026-10-10T05:47:19.666Z",{"slug":34,"title":35,"type":24,"summary":36,"tags":37,"author":14,"cover_url":42,"published_at":43,"updated_at":44},"durable-object-alarm-loop-guards","The Durable Object alarm that cost $10,000: guarding setAlarm() loops with backoff, idempotency and a kill switch","Durable Object alarms are at-least-once, retried, and usually rescheduled from inside the handler, which makes a billing loop easy to write. Four guards in TypeScript, a kill switch, and a Vitest test that proves the loop stops.",[38,39,40,41,13],"cloudflare","durable-objects","typescript","cost-control","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac8709b392a85804f209fb3-0-9143ed0c.png","2026-10-09T06:09:10.127Z","2026-10-09T06:09:10.128Z",{"slug":46,"title":47,"type":24,"summary":48,"tags":49,"author":14,"cover_url":54,"published_at":55,"updated_at":55},"cctld-hijack-counterfeit-certs-caa-accounturi-ct-watch","Counterfeit certs via hijacked ccTLDs: CAA with accounturi and a CT watch for your domains in 15 minutes","Attackers took over the .gh, .sl and .as registries and got 12 valid certificates for Google domains. CAA would not have stopped the hijack. Here is the CAA record that limits the damage afterwards, and a CT watch script that tells you within a day.",[50,51,52,53,13],"tls","caa","certificate-transparency","dns","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac75337392a85804f207d25-0-12f538ac.png","2026-10-08T22:47:12.408Z",[57,60,62,65,67,79,91,102,111,122,135,149,161,173,184,195,203,214,225,234,245,255,264,273],{"slug":4,"title":5,"type":24,"summary":7,"tags":58,"author":14,"cover_url":15,"published_at":16,"updated_at":59,"reading_minutes":19},[9,10,11,12,13],"2026-10-11T05:42:15.364Z",{"slug":22,"title":23,"type":24,"summary":25,"tags":61,"author":14,"cover_url":30,"published_at":31,"updated_at":32,"reading_minutes":19},[27,28,29,9,13],{"slug":34,"title":35,"type":24,"summary":36,"tags":63,"author":14,"cover_url":42,"published_at":43,"updated_at":44,"reading_minutes":64},[38,39,40,41,13],7,{"slug":46,"title":47,"type":24,"summary":48,"tags":66,"author":14,"cover_url":54,"published_at":55,"updated_at":55,"reading_minutes":19},[50,51,52,53,13],{"slug":68,"title":69,"type":24,"summary":70,"tags":71,"author":14,"cover_url":76,"published_at":77,"updated_at":78,"reading_minutes":19},"embeddinggemma-2-qdrant-truncation-recall","EmbeddingGemma 2 in Qdrant: one 740M model for text, images and audio, and what truncating 768 to 128 dims costs your recall","Google's open multimodal embedder runs locally and truncates from 768 to 128 dims. Index one Qdrant collection at three sizes from a single encode pass, then measure recall@10 on your own queries instead of trusting a benchmark.",[72,73,74,75,13],"embeddings","qdrant","rag","open-models","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac5cceedf0d655df505306e-0-d17d0fef.png","2026-10-07T07:21:20.071Z","2026-10-07T07:21:20.072Z",{"slug":80,"title":81,"type":24,"summary":82,"tags":83,"author":14,"cover_url":87,"published_at":88,"updated_at":89,"reading_minutes":90},"cloudflare-access-strict-service-token-auth-migration","Strict service token auth in Cloudflare Access: moving your scripts and CI over before it bites","Cloudflare Access now has a strict mode for service tokens: 401\u002F403 instead of a 302 to the login page, only Service Auth policies count, and no CF_Authorization cookie. New orgs get it forced on from 5 October. A 15-minute check and switch for existing orgs.",[38,84,85,86,13],"zero-trust","ci-cd","authentication","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac4a8860956594c947bd197-0-f768b25b.png","2026-10-06T08:30:13.154Z","2026-10-06T08:30:13.155Z",5,{"slug":92,"title":93,"type":24,"summary":94,"tags":95,"author":14,"cover_url":99,"published_at":100,"updated_at":101,"reading_minutes":19},"cloudflare-traces-trace-rules-debug-one-customer","Why was that request blocked? Tracing one customer at 100% with Cloudflare Traces and Trace Rules","Cloudflare Traces (open beta) shows a request's path through WAF rules, transforms, cache, Workers and origin as one trace. A recipe: low baseline sampling, a 100% Trace Rule for one host or debug header, traceparent to your origin, OTLP export to your own collector, and what December pricing means.",[38,96,97,98,13],"observability","opentelemetry","tracing","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac338052cb6b40613ac2b7c-0-2294d114.png","2026-10-05T06:22:19.055Z","2026-10-05T06:22:19.056Z",{"slug":103,"title":104,"type":24,"summary":105,"tags":106,"author":14,"cover_url":109,"published_at":110,"updated_at":110,"reading_minutes":90},"copyescape-cve-2026-17106-patch-docker-cp","CopyEscape (CVE-2026-17106): patch docker cp, and stop copying out of running containers","A race in docker cp lets a malicious container write files anywhere the copying process can write on the host. That matters for CI runners and AI-agent sandboxes that copy results out. Check your versions, patch, and change copy-out jobs to stop the container first.",[9,10,107,108,13],"cve","ci","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac218ebfd770659725abe68-0-eee7c8f7.png","2026-10-04T23:51:14.689Z",{"slug":112,"title":113,"type":24,"summary":114,"tags":115,"author":14,"cover_url":118,"published_at":119,"updated_at":120,"reading_minutes":121},"protected-quick-tunnels-vs-tailscale-funnel","Share localhost with three named people: Cloudflare's Protected Quick Tunnels vs Tailscale Funnel","cloudflared 2026.9.3 adds --allowed-mail: your quick tunnel now sits behind an email one-time PIN, checked against an allow-list on your own machine, free and without a Cloudflare account. The commands, what it protects, and when Tailscale Serve or Funnel is the better fit.",[38,116,117,10,13],"tailscale","tunnels","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac218d8fd770659725abe3a-0-40f8cb2e.png","2026-10-04T23:19:14.764Z","2026-10-04T23:19:14.765Z",4,{"slug":123,"title":124,"type":24,"summary":125,"tags":126,"author":14,"cover_url":132,"published_at":133,"updated_at":134,"reading_minutes":19},"si-domains-super-intelligence-data",".si after 'Super Intelligence': did one UN speech move a ccTLD?","Trump renamed AI 'super intelligence' at the UN on 22 September 2026 and Slovenia's .si went from about 190,000 names to almost 276,000 in a month. Registry numbers, prices, and 87 WHOIS checks: the obvious AI names were gone years ago; the compounds went in days.",[127,128,129,130,131,13],"domains","si","tld","data","ai","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abaaee53e21d5cbd14d442d-0-d6243bc5.png","2026-10-04T22:36:14.598Z","2026-10-04T22:36:14.599Z",{"slug":136,"title":137,"type":24,"summary":138,"tags":139,"author":14,"cover_url":145,"published_at":146,"updated_at":147,"reading_minutes":148},"palantir-agent-stack-python","Steal Palantir's agent stack: typed tools, one LLM gateway, swappable models","An X thread boils Palantir's AIP docs down to four agent patterns. We check each one against the docs, then build them in one stdlib-only Python file: typed business-object tools, a gateway that masks PII, caches and retries, a model set in config, and schedule\u002Fevent\u002FAPI triggers.",[140,141,142,143,144,13],"ai-agents","llm","python","architecture","palantir","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abd88f9c951ea7137fa3872-0-48eb7eee.png","2026-10-01T23:05:10.531Z","2026-10-01T23:05:10.532Z",10,{"slug":150,"title":151,"type":24,"summary":152,"tags":153,"author":14,"cover_url":157,"published_at":158,"updated_at":159,"reading_minutes":160},"claude-code-effort-levels","Effort levels in Claude Code: when max effort pays off and when it just burns tokens","Anthropic's effort deep dive (Terminal-Bench 3.0 plus three builds) shows higher effort mostly buys verification and edge-case testing, not smarter code. A rule of thumb per task type, the commands to set effort, and a script to measure cost vs pass rate on your own repo.",[154,155,141,156,13],"claude-code","ai-coding","developer-tools","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abd88edc951ea7137fa3804-0-2716005a.png","2026-10-01T22:32:14.139Z","2026-10-02T04:44:58.001Z",9,{"slug":162,"title":163,"type":24,"summary":164,"tags":165,"author":14,"cover_url":169,"published_at":170,"updated_at":171,"reading_minutes":172},"agentic-inbox-cloudflare-setup","Self-host an AI email agent on Cloudflare Workers: agentic-inbox set up and costed","Cloudflare's open-source agentic-inbox runs a full email client on Workers, with one SQLite Durable Object per mailbox and a Kimi K2.5 agent that drafts replies. Covers the post-deploy steps people miss (Access, sending, routing, mailbox first) and the cost.",[38,166,140,167,168,13],"workers","email","self-hosting","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abd88dac951ea7137fa378b-0-5b0ec96d.png","2026-10-01T08:17:18.646Z","2026-10-05T05:56:11.919Z",8,{"slug":174,"title":175,"type":24,"summary":176,"tags":177,"author":14,"cover_url":181,"published_at":182,"updated_at":183,"reading_minutes":172},"audit-ai-agent-public-traces","Nearly a million leaked links: auditing what your AI agents leave on the public web","OpenAI's agent swarm left almost a million public shortener URLs holding credentials. Here's a tested shell + gitleaks audit to find the shortlinks, pastes and webhooks your own agents created, scan them for secrets and close the channels.",[10,178,179,180,141,13],"agents","secrets","gitleaks","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abaad873e21d5cbd14d4397-0-0f4f51f7.png","2026-10-01T07:43:19.642Z","2026-10-01T08:44:43.041Z",{"slug":185,"title":186,"type":24,"summary":187,"tags":188,"author":14,"cover_url":192,"published_at":193,"updated_at":194,"reading_minutes":172},"mikrotrick-check-patch-mikrotik","MikroTrick: check and patch your MikroTik in 15 minutes","Two chained RouterOS bugs give anyone who can reach SSH full admin, no password needed, and attacks started before the patch. Find exposed SSH, check the version, grep for the published IoCs, patch and move management behind WireGuard.",[10,189,190,191,168,13],"mikrotik","routeros","ssh","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abcd9c0838b650cb96b3d10-0-6cd107e0.png","2026-10-01T07:02:15.03Z","2026-10-01T08:44:41.391Z",{"slug":196,"title":197,"type":24,"summary":198,"tags":199,"author":14,"cover_url":200,"published_at":201,"updated_at":202,"reading_minutes":172},"agent-sandbox-dns-egress-lockdown","Your agent sandbox leaks through DNS: lock down egress in 15 minutes","An OpenAI model escaped its sandbox by tunnelling questions through DNS. Here is a tested Docker Compose setup for coding agents: a DNS allowlist, a logging egress proxy and a kill switch that actually fires.",[10,9,178,53,168,13],"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abaaca13e21d5cbd14d4306-0-cb93fe1b.png","2026-10-01T03:00:15.943Z","2026-10-01T08:44:43.165Z",{"slug":204,"title":205,"type":24,"summary":206,"tags":207,"author":14,"cover_url":211,"published_at":212,"updated_at":213,"reading_minutes":64},"who-blocks-ai-crawlers-robots-txt","Who blocks AI crawlers? robots.txt vs the network edge, with numbers","I scanned robots.txt on the top 300 sites: 33 of 138 block GPTBot, 14 block training but allow AI search. What each AI bot directive controls, why robots.txt is only a request, and a copy-paste policy plus nginx rule for small SaaS sites.",[131,208,209,38,210,13],"robots-txt","seo","saas","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abcd9c1838b650cb96b3d1b-0-11f94198.png","2026-09-30T21:00:20.673Z","2026-10-01T20:47:34.092Z",{"slug":215,"title":216,"type":24,"summary":217,"tags":218,"author":14,"cover_url":222,"published_at":223,"updated_at":224,"reading_minutes":121},"bullet-time-with-first-last-frame-video","Bullet time with first\u002Flast-frame video: orbiting a frozen moment from three stills","A freeze-frame camera orbit built from generated stills: one action shot, two camera-move angles, two first\u002Flast-frame clips between them, stitched and ping-ponged. The pipeline, the seams, and where the model re-imagines the water.",[131,219,220,221],"comfyui","video-generation","flowdsl","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abae46c45201648bfd477a7-0-6f4d036e.png","2026-09-28T22:42:41Z","2026-09-28T22:42:41.6Z",{"slug":226,"title":227,"type":24,"summary":228,"tags":229,"author":14,"cover_url":231,"published_at":232,"updated_at":233,"reading_minutes":64},"an-ai-media-pipeline-that-shows-its-work","An AI media pipeline that shows its work: ComfyUI presets, FlowDSL routing and the misses","How the images on my sites are generated: four ComfyUI presets behind one Go module, job rows as state, FlowDSL flows for routing, per-post media in the admin — and the bugs and model misses I hit shipping it. This post's own images were made the same way.",[131,221,219,230],"image-generation","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6aba8ba317ceba3543925be4-0-2f6b8a5c.png","2026-09-28T15:57:50Z","2026-10-01T20:47:34.327Z",{"slug":235,"title":236,"type":24,"summary":237,"tags":238,"author":14,"cover_url":241,"published_at":242,"updated_at":243,"reading_minutes":244},"openai-embeddings-python-mongodb","Transforming Text into Vectors: OpenAI Embeddings in Python","Learn how to generate text embeddings with the OpenAI API in Python to power semantic search, recommendations, and more. Includes practical examples with MongoDB integration and cost analysis.",[239,131,142,240],"openai","mongodb","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abad0fa45201648bfd46c2d-0-2e60b732.png","2024-11-23T00:00:00Z","2026-09-28T22:31:01.385Z",3,{"slug":246,"title":247,"type":24,"summary":248,"tags":249,"author":14,"cover_url":251,"published_at":252,"updated_at":253,"reading_minutes":254},"check-pricing-availability-ing-domains","Last Chance to Grab Short .ING Domains: The Extended List Part II","Welcome back to the second part of our exciting exploration into the .ING domain zone! This time, I've expanded our horizons to bring you an even larger selection of .ING domain names. List of over 24,000 domain names inside.",[127,250],"business","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abad0fa45201648bfd46c38-0-c55f4c8d.png","2023-12-14T00:00:00Z","2026-09-28T22:31:01.453Z",1,{"slug":256,"title":257,"type":24,"summary":258,"tags":259,"author":14,"cover_url":260,"published_at":261,"updated_at":262,"reading_minutes":263},"impressive-ing-domains","Unveiling the Impressive .ING Domains","Discover the vast potential of the new .ING domain zone in my latest blog post! I've used AI and a Python script to unearth a treasure trove of available domain names. From budget-friendly picks to exclusive premium domains, there's something for every ambition. Plus, a special list of unique, lesser-known domains awaits.",[127,250],"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abad0fa45201648bfd46c43-0-03be24b7.png","2023-12-11T00:00:00Z","2026-09-28T22:31:01.527Z",2,{"slug":265,"title":266,"type":24,"summary":267,"tags":268,"author":14,"cover_url":270,"published_at":271,"updated_at":272,"reading_minutes":244},"secured-web-server-in-5-minutes","Fortify Web Server Security in 5 Minutes with Tailscale","Tailscale revolutionizes secure networking with its user-friendly approach, effortlessly connecting devices across diverse networks.",[12,116,269],"webserver","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abad0fa45201648bfd46c4e-0-eae6f62d.png","2023-11-03T00:00:00Z","2026-09-28T22:31:01.597Z",{"slug":274,"title":275,"type":24,"summary":276,"tags":277,"author":14,"cover_url":280,"published_at":281,"updated_at":282,"reading_minutes":19},"lets-encrypt-free-ssl","How to Secure Your Website with Free SSL Certificates for a Lifetime","Let’s Encrypt certificates have revolutionized internet security by providing free, automated, and widely trusted SSL\u002FTLS certificates. The non-profit Certificate Authority (CA) has significantly contributed to a more secure web environment by simplifying the process of securing websites with HTTPS.",[278,279,269],"ssl","https","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6abad0fa45201648bfd46c59-0-bf2a9a0a.png","2023-11-01T00:00:00Z","2026-09-28T22:39:13.555Z"]