[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fihz9jn6qgpva":3,"$fanuq43nlrv5g":57},{"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},"go-1-27-http1-connection-reuse-body-draining","710 ms to 150 ms for 100 requests: what Go 1.27's HTTP\u002F1 connection reuse fixes, and the body-draining habit to keep for older clients","\u003Cp>If your Go service calls an LLM API, a webhook receiver or any REST endpoint over HTTP\u002F1, there is a good chance it has been opening a fresh TCP and TLS connection for almost every request. The cause is small: a response body you closed without reading to the end. On October 14 the Go team (Nicholas Husin and Damien Neil) wrote up why this happens and what Go 1.27 changes. In their benchmark, 100 calls to \u003Ccode>index.golang.org\u003C\u002Fcode> over HTTP\u002F1 took about 710 ms on Go 1.26 and about 150 ms on Go 1.27.\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6ad1d95469fb9bde4cc896a5\">\u003Cvideo src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ad1d95569fb9bde4cc896ab-0-43a0fcf3.mp4\" autoplay muted loop playsinline preload=\"metadata\">\u003C\u002Fvideo>\u003C\u002Ffigure>\u003Cp>This post gives you a program that shows the problem on your own machine, the two patterns that cause it, and what to do if you can't move to Go 1.27 yet.\u003C\u002Fp>\u003Ch2>Why an unread body breaks reuse\u003C\u002Fh2>\u003Cp>HTTP\u002F1 sends responses back to back on the same connection. The client can only find where the next response starts once it has read the current body to the very end. If you call \u003Ccode>resp.Body.Close()\u003C\u002Fcode> while bytes are still unread, older versions of \u003Ccode>net\u002Fhttp\u003C\u002Fcode> can't safely reuse the connection, so they close it. Your next request pays for a new TCP handshake and, on HTTPS, a new TLS handshake.\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6ad1d8dc69fb9bde4cc89601\">\u003Cimg src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ad1d8dc69fb9bde4cc89606-0-f4ac5b44.png\" alt=\"An unread response body acts as a blockage that prevents the connection from being reused.\" loading=\"lazy\">\u003Cfigcaption>An unread response body acts as a blockage that prevents the connection from being reused.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>The Go blog names two common ways this happens:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cstrong>Ignoring the body.\u003C\u002Fstrong> You only care about the status code, but the server still sends something like \u003Ccode>{\"success\": true, \"message\": \"update processed\"}\u003C\u002Fcode>.\u003C\u002Fli>\u003Cli>\u003Cstrong>Stopping just short of the end.\u003C\u002Fstrong> \u003Ccode>json.NewDecoder(resp.Body).Decode(&amp;v)\u003C\u002Fcode> stops after the closing \u003Ccode>}\u003C\u002Fcode>. A trailing newline after the JSON object is still unread, and that is enough.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>The first pattern looks completely innocent:\u003C\u002Fp>\u003Cpre class=\"code-block\" data-lang=\"go\">\u003Ccode class=\"hljs language-go\">\u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">func\u003C\u002Fspan> \u003Cspan class=\"hljs-title\">getStatus\u003C\u002Fspan>\u003Cspan class=\"hljs-params\">(url \u003Cspan class=\"hljs-type\">string\u003C\u002Fspan>)\u003C\u002Fspan>\u003C\u002Fspan> (\u003Cspan class=\"hljs-type\">int\u003C\u002Fspan>, \u003Cspan class=\"hljs-type\">error\u003C\u002Fspan>) {\n    resp, err := http.Get(url)\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> err != \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan> {\n        \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, err\n    }\n    \u003Cspan class=\"hljs-keyword\">defer\u003C\u002Fspan> resp.Body.Close()\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> resp.StatusCode, \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan>\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>What Go 1.27 changes\u003C\u002Fh2>\u003Cp>From Go 1.27, \u003Ccode>net\u002Fhttp.Transport\u003C\u002Fcode> drains an unread HTTP\u002F1 response body itself when you close it. Per the Go blog, the drain:\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6ad1d8dc69fb9bde4cc8960b\">\u003Cimg src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ad1d8dc69fb9bde4cc89610-0-77d31a65.png\" alt=\"Go 1.27 significantly reduces latency by eliminating redundant handshakes.\" loading=\"lazy\">\u003Cfigcaption>Go 1.27 significantly reduces latency by eliminating redundant handshakes.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cul>\u003Cli>runs asynchronously in the background, so \u003Ccode>Close()\u003C\u002Fcode> doesn't block;\u003C\u002Fli>\u003Cli>gives up after 50 ms or 256 KB, whichever comes first, so a huge or slow body doesn't tie up the connection;\u003C\u002Fli>\u003Cli>is skipped when the response carries \u003Ccode>Connection: close\u003C\u002Fcode>, since that connection can't be reused anyway.\u003C\u002Fli>\u003C\u002Ful>\u003Cp>So \u003Ccode>getStatus\u003C\u002Fcode> above now reuses connections with no code change. This is the result of their 100-request benchmark:\u003C\u002Fp>\u003Cfigure data-chart='{\"type\":\"bar\",\"title\":\"100 sequential HTTP\u002F1 calls to index.golang.org\",\"unit\":\"ms\",\"labels\":[\"Go 1.26\",\"Go 1.27\"],\"series\":[{\"name\":\"Total time\",\"values\":[710,150]}],\"note\":\"Approximate figures as published; HTTP\u002F2 disabled with GODEBUG=http2client=0\",\"source\":{\"label\":\"The Go Blog, Oct 14 2026\",\"url\":\"https:\u002F\u002Fgo.dev\u002Fblog\u002Fhttp-connection-reuse\"}}'>\u003Cfigcaption>100 sequential HTTP\u002F1 calls to index.golang.org: about 710 ms on Go 1.26, about 150 ms on Go 1.27 (source: The Go Blog)\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>Roughly 5x, and all of it comes from not redoing handshakes. The further away the server is, the bigger the gap: every new connection costs at least one extra round trip for TCP plus more for TLS.\u003C\u002Fp>\u003Ch2>See it on your machine\u003C\u002Fh2>\u003Cp>This program makes sequential GET requests and counts how many went out on a reused connection, using \u003Ccode>httptrace.GotConnInfo.Reused\u003C\u002Fcode>. With no \u003Ccode>-url\u003C\u002Fcode> it starts a local test server that returns a small JSON body with a trailing newline. \u003Ccode>-drain\u003C\u002Fcode> reads the body to EOF before closing.\u003C\u002Fp>\u003Cpre class=\"code-block\" data-lang=\"go\">\u003Ccode class=\"hljs language-go\">\u003Cspan class=\"hljs-keyword\">package\u003C\u002Fspan> main\n\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> (\n    \u003Cspan class=\"hljs-string\">&quot;flag&quot;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&quot;fmt&quot;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&quot;io&quot;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&quot;net\u002Fhttp&quot;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&quot;net\u002Fhttp\u002Fhttptest&quot;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&quot;net\u002Fhttp\u002Fhttptrace&quot;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&quot;time&quot;\u003C\u002Fspan>\n)\n\n\u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">func\u003C\u002Fspan> \u003Cspan class=\"hljs-title\">main\u003C\u002Fspan>\u003Cspan class=\"hljs-params\">()\u003C\u002Fspan>\u003C\u002Fspan> {\n    url := flag.String(\u003Cspan class=\"hljs-string\">&quot;url&quot;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&quot;&quot;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&quot;URL to call (default: a local test server)&quot;\u003C\u002Fspan>)\n    n := flag.Int(\u003Cspan class=\"hljs-string\">&quot;n&quot;\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&quot;number of sequential requests&quot;\u003C\u002Fspan>)\n    drain := flag.Bool(\u003Cspan class=\"hljs-string\">&quot;drain&quot;\u003C\u002Fspan>, \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&quot;read the body to EOF before closing&quot;\u003C\u002Fspan>)\n    flag.Parse()\n\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> *url == \u003Cspan class=\"hljs-string\">&quot;&quot;\u003C\u002Fspan> {\n        srv := httptest.NewServer(http.HandlerFunc(\u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">func\u003C\u002Fspan>\u003Cspan class=\"hljs-params\">(w http.ResponseWriter, r *http.Request)\u003C\u002Fspan>\u003C\u002Fspan> {\n            w.Header().Set(\u003Cspan class=\"hljs-string\">&quot;Content-Type&quot;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&quot;application\u002Fjson&quot;\u003C\u002Fspan>)\n            fmt.Fprintln(w, \u003Cspan class=\"hljs-string\">`{&quot;success&quot;: true, &quot;message&quot;: &quot;update processed&quot;}`\u003C\u002Fspan>)\n        }))\n        \u003Cspan class=\"hljs-keyword\">defer\u003C\u002Fspan> srv.Close()\n        *url = srv.URL\n    }\n\n    reused := \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n    trace := &amp;httptrace.ClientTrace{\n        GotConn: \u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">func\u003C\u002Fspan>\u003Cspan class=\"hljs-params\">(info httptrace.GotConnInfo)\u003C\u002Fspan>\u003C\u002Fspan> {\n            \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> info.Reused {\n                reused++\n            }\n        },\n    }\n\n    start := time.Now()\n    \u003Cspan class=\"hljs-keyword\">for\u003C\u002Fspan> i := \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>; i &lt; *n; i++ {\n        req, err := http.NewRequest(\u003Cspan class=\"hljs-string\">&quot;GET&quot;\u003C\u002Fspan>, *url, \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan>)\n        \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> err != \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan> {\n            \u003Cspan class=\"hljs-built_in\">panic\u003C\u002Fspan>(err)\n        }\n        req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))\n        resp, err := http.DefaultClient.Do(req)\n        \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> err != \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan> {\n            \u003Cspan class=\"hljs-built_in\">panic\u003C\u002Fspan>(err)\n        }\n        \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> *drain {\n            io.Copy(io.Discard, resp.Body)\n        }\n        resp.Body.Close()\n    }\n    fmt.Printf(\u003Cspan class=\"hljs-string\">&quot;%d requests in %v, %d on a reused connection\\n&quot;\u003C\u002Fspan>,\n        *n, time.Since(start).Round(time.Millisecond), reused)\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Save it as \u003Ccode>main.go\u003C\u002Fcode> in an empty directory and run it four ways. The last two hit the same host as the Go team's benchmark, with HTTP\u002F2 turned off so you're testing HTTP\u002F1:\u003C\u002Fp>\u003Cpre class=\"code-block\" data-lang=\"bash\">\u003Ccode class=\"hljs language-bash\">go run main.go\ngo run main.go -drain\nGODEBUG=http2client=0 go run main.go -url https:\u002F\u002Findex.golang.org\u002Findex\nGODEBUG=http2client=0 go run main.go -drain -url https:\u002F\u002Findex.golang.org\u002Findex\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>This is what we got on Go 1.26.2 on a MacBook in Europe:\u003C\u002Fp>\u003Cpre class=\"code-block\">\u003Ccode class=\"hljs\">100 requests in 22ms, 0 on a reused connection\n100 requests in 9ms, 99 on a reused connection\n100 requests in 8.09s, 0 on a reused connection\n100 requests in 1.638s, 99 on a reused connection\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Without draining, not a single request reused a connection. Against a real HTTPS host that cost about 5x in wall time, the same ratio the Go blog reports. Our absolute numbers are higher than theirs because of the distance to the server and because \u003Ccode>\u002Findex\u003C\u002Fcode> returns a much larger body than a status endpoint. Run the same program under Go 1.27 and the no-drain case should come in close to the drained one, as long as the body fits under the 256 KB and 50 ms limits.\u003C\u002Fp>\u003Ch2>On Go 1.26 or older: drain it yourself\u003C\u002Fh2>\u003Cp>Until every service you run is on Go 1.27, keep the old habit: read what's left of the body before closing it, with a cap so a large or slow response doesn't keep you reading forever. This mirrors the limit Go 1.27 picked:\u003C\u002Fp>\n\u003Cfigure data-post-media=\"6ad1d8dc69fb9bde4cc89615\">\u003Cimg src=\"https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ad1d8dc69fb9bde4cc8961a-0-a8c3a87b.png\" alt=\"Manually draining the response body ensures the connection returns to the pool.\" loading=\"lazy\">\u003Cfigcaption>Manually draining the response body ensures the connection returns to the pool.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cpre class=\"code-block\" data-lang=\"go\">\u003Ccode class=\"hljs language-go\">\u003Cspan class=\"hljs-comment\">\u002F\u002F drainAndClose reads up to 256 KB of whatever is left in body, then closes it.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-comment\">\u002F\u002F If the body is fully read, the connection goes back to the pool for reuse.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">func\u003C\u002Fspan> \u003Cspan class=\"hljs-title\">drainAndClose\u003C\u002Fspan>\u003Cspan class=\"hljs-params\">(body io.ReadCloser)\u003C\u002Fspan>\u003C\u002Fspan> {\n    io.CopyN(io.Discard, body, \u003Cspan class=\"hljs-number\">256\u003C\u002Fspan>&lt;&lt;\u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>)\n    body.Close()\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Use it in place of \u003Ccode>defer resp.Body.Close()\u003C\u002Fcode> wherever you don't read the body to EOF yourself, including after \u003Ccode>json.Decoder.Decode\u003C\u002Fcode>:\u003C\u002Fp>\u003Cpre class=\"code-block\" data-lang=\"go\">\u003Ccode class=\"hljs language-go\">resp, err := http.Get(url)\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> err != \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> err\n}\n\u003Cspan class=\"hljs-keyword\">defer\u003C\u002Fspan> drainAndClose(resp.Body)\n\n\u003Cspan class=\"hljs-keyword\">var\u003C\u002Fspan> out Result\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> err := json.NewDecoder(resp.Body).Decode(&amp;out); err != \u003Cspan class=\"hljs-literal\">nil\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> err\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>A few notes on this helper:\u003C\u002Fp>\u003Cul>\u003Cli>If more than 256 KB is left, the connection is still closed. That's deliberate: reading megabytes just to save a handshake is a bad trade.\u003C\u002Fli>\u003Cli>Unlike the Go 1.27 drain, this one runs synchronously, so a slow server can delay your return. If that matters, put a deadline on the request with \u003Ccode>context.WithTimeout\u003C\u002Fcode>.\u003C\u002Fli>\u003Cli>HTTP\u002F2 multiplexes streams on one connection and isn't affected by this. You will only see the problem on HTTP\u002F1 connections: plain HTTP, servers or proxies that don't offer h2, and custom transports with HTTP\u002F2 off.\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>What to check in your code\u003C\u002Fh2>\u003Cul>\u003Cli>Search for \u003Ccode>defer resp.Body.Close()\u003C\u002Fcode> in handlers that only look at \u003Ccode>resp.StatusCode\u003C\u002Fcode>. Those are the most likely offenders.\u003C\u002Fli>\u003Cli>Look for \u003Ccode>json.NewDecoder(resp.Body).Decode\u003C\u002Fcode> with nothing reading the rest of the body afterwards.\u003C\u002Fli>\u003Cli>Run the trace above (or add the \u003Ccode>GotConn\u003C\u002Fcode> hook to a staging client) against your real upstreams. A reuse count near zero on sequential calls is the symptom.\u003C\u002Fli>\u003Cli>When you upgrade to Go 1.27, keep the helper in shared client code for a while. It costs nothing when the body is already at EOF.\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Sources\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Ca href=\"https:\u002F\u002Fgo.dev\u002Fblog\u002Fhttp-connection-reuse\">The Go Blog: Better HTTP\u002F1 connection reuse (Nicholas Husin, Damien Neil, Oct 14 2026)\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fnews.ycombinator.com\u002Fitem?id=50090369\">Hacker News discussion\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fpkg.go.dev\u002Fnet\u002Fhttp\u002Fhttptrace\">net\u002Fhttp\u002Fhttptrace package docs\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Ful>","Go 1.27 drains unread HTTP\u002F1 response bodies for you, so a closed-but-unread body no longer kills connection reuse. A runnable test that counts reused connections, the two patterns that broke reuse, and a capped drain helper for Go 1.26 and older.",[9,10,11,12,13],"go","http","performance","networking","ai-assisted","if.codes","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ad1d8da69fb9bde4cc895fb-0-e539bbf2.png","2026-10-16T23:32:12.783Z","Go 1.27 HTTP\u002F1 connection reuse: 710 ms to 150 ms, and draining bodies on older Go","Go 1.27 drains unread HTTP\u002F1 response bodies so connections get reused. A runnable test, the patterns that broke reuse, and a drain helper for Go 1.26.",6,[21,34,45],{"slug":22,"title":23,"type":24,"summary":25,"tags":26,"author":14,"cover_url":31,"published_at":32,"updated_at":33},"claude-code-subagent-prompt-cache-ttl","Claude Code subagents get a 5-minute cache even on a subscription: when to set it to 1h, and how to check","blog","On a subscription your main Claude Code conversation gets a one-hour prompt cache, but subagents, workflows and compaction stay at five minutes. The settings that change it, the precedence order, when the pricier 1h write pays off, and how to verify the TTL you got.",[27,28,29,30,13],"claude-code","prompt-caching","subagents","llm-costs","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ad0968473d443ad8fa7adbe-0-f2f3fe8c.png","2026-10-15T22:21:15.624Z","2026-10-15T22:21:15.625Z",{"slug":35,"title":36,"type":24,"summary":37,"tags":38,"author":14,"cover_url":42,"published_at":43,"updated_at":44},"postgres-slow-vps-benchmark-the-disk-first","Postgres feels slow on your VPS? Benchmark the disk before you touch postgresql.conf","ClickHouse measured the same Postgres box at 16,030 TPS on local NVMe and 1,734 TPS on a baseline gp3 volume, with most of the gap spent waiting on storage. A 15-minute fio and pg_test_fsync check tells you which side of that table your VPS is on.",[39,40,11,41,13],"postgres","self-hosting","databases","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acdb5d473d443ad8fa7555c-0-dd05a138.png","2026-10-13T05:44:15.759Z","2026-10-13T05:44:15.76Z",{"slug":46,"title":47,"type":24,"summary":48,"tags":49,"author":14,"cover_url":54,"published_at":55,"updated_at":56},"quoted-tilde-in-path-check","A quoted ~ in your PATH runs whatever sits in .\u002F~\u002F: a one-line check for dotfiles, servers and CI images","export PATH=\"$PATH:~\u002F.local\u002Fbin\" never expands the tilde. Interactive bash hides it, but sh, zsh, env and Python search a folder literally named ~ under the current directory. The check, the fix, and where to grep.",[50,51,52,53,13],"linux","shell","security","devops","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acd3f0073d443ad8fa743bf-0-c8db0f5d.png","2026-10-12T23:53:16.705Z","2026-10-12T23:53:16.706Z",[58,60,62,65,68,79,90,103,114,126,137,148,157,167,180,194,205,216,227,238,246,257,268,277,288,298,307,316],{"slug":4,"title":5,"type":24,"summary":7,"tags":59,"author":14,"cover_url":15,"published_at":16,"updated_at":16,"reading_minutes":19},[9,10,11,12,13],{"slug":22,"title":23,"type":24,"summary":25,"tags":61,"author":14,"cover_url":31,"published_at":32,"updated_at":33,"reading_minutes":19},[27,28,29,30,13],{"slug":35,"title":36,"type":24,"summary":37,"tags":63,"author":14,"cover_url":42,"published_at":43,"updated_at":44,"reading_minutes":64},[39,40,11,41,13],5,{"slug":46,"title":47,"type":24,"summary":48,"tags":66,"author":14,"cover_url":54,"published_at":55,"updated_at":56,"reading_minutes":67},[50,51,52,53,13],4,{"slug":69,"title":70,"type":24,"summary":71,"tags":72,"author":14,"cover_url":76,"published_at":77,"updated_at":78,"reading_minutes":19},"docker-published-ports-bypass-ufw-vps-hardening","Docker publishes ports straight past UFW: hardening a fresh VPS without the firewall rule that does nothing","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.",[73,52,74,75,13],"docker","vps","firewall","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6acb12dddbaf8c2bc523d0bb-0-21ee3023.png","2026-10-11T05:42:15.363Z","2026-10-11T05:42:15.364Z",{"slug":80,"title":81,"type":24,"summary":82,"tags":83,"author":14,"cover_url":87,"published_at":88,"updated_at":89,"reading_minutes":19},"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","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.",[84,85,86,73,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":91,"title":92,"type":24,"summary":93,"tags":94,"author":14,"cover_url":99,"published_at":100,"updated_at":101,"reading_minutes":102},"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.",[95,96,97,98,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",7,{"slug":104,"title":105,"type":24,"summary":106,"tags":107,"author":14,"cover_url":112,"published_at":113,"updated_at":113,"reading_minutes":19},"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.",[108,109,110,111,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",{"slug":115,"title":116,"type":24,"summary":117,"tags":118,"author":14,"cover_url":123,"published_at":124,"updated_at":125,"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.",[119,120,121,122,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":127,"title":128,"type":24,"summary":129,"tags":130,"author":14,"cover_url":134,"published_at":135,"updated_at":136,"reading_minutes":64},"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.",[95,131,132,133,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",{"slug":138,"title":139,"type":24,"summary":140,"tags":141,"author":14,"cover_url":145,"published_at":146,"updated_at":147,"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.",[95,142,143,144,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":149,"title":150,"type":24,"summary":151,"tags":152,"author":14,"cover_url":155,"published_at":156,"updated_at":156,"reading_minutes":64},"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.",[73,52,153,154,13],"cve","ci","https:\u002F\u002Fmedia.stufio.com\u002Fmedia\u002Fifcodes\u002Fmediagen\u002F6a\u002F6ac218ebfd770659725abe68-0-eee7c8f7.png","2026-10-04T23:51:14.689Z",{"slug":158,"title":159,"type":24,"summary":160,"tags":161,"author":14,"cover_url":164,"published_at":165,"updated_at":166,"reading_minutes":67},"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.",[95,162,163,52,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",{"slug":168,"title":169,"type":24,"summary":170,"tags":171,"author":14,"cover_url":177,"published_at":178,"updated_at":179,"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.",[172,173,174,175,176,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":181,"title":182,"type":24,"summary":183,"tags":184,"author":14,"cover_url":190,"published_at":191,"updated_at":192,"reading_minutes":193},"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.",[185,186,187,188,189,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":195,"title":196,"type":24,"summary":197,"tags":198,"author":14,"cover_url":201,"published_at":202,"updated_at":203,"reading_minutes":204},"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.",[27,199,186,200,13],"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":206,"title":207,"type":24,"summary":208,"tags":209,"author":14,"cover_url":212,"published_at":213,"updated_at":214,"reading_minutes":215},"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.",[95,210,185,211,40,13],"workers","email","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":217,"title":218,"type":24,"summary":219,"tags":220,"author":14,"cover_url":224,"published_at":225,"updated_at":226,"reading_minutes":215},"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.",[52,221,222,223,186,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":228,"title":229,"type":24,"summary":230,"tags":231,"author":14,"cover_url":235,"published_at":236,"updated_at":237,"reading_minutes":215},"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.",[52,232,233,234,40,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":239,"title":240,"type":24,"summary":241,"tags":242,"author":14,"cover_url":243,"published_at":244,"updated_at":245,"reading_minutes":215},"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.",[52,73,221,111,40,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":247,"title":248,"type":24,"summary":249,"tags":250,"author":14,"cover_url":254,"published_at":255,"updated_at":256,"reading_minutes":102},"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.",[176,251,252,95,253,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":258,"title":259,"type":24,"summary":260,"tags":261,"author":14,"cover_url":265,"published_at":266,"updated_at":267,"reading_minutes":67},"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.",[176,262,263,264],"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":269,"title":270,"type":24,"summary":271,"tags":272,"author":14,"cover_url":274,"published_at":275,"updated_at":276,"reading_minutes":102},"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.",[176,264,262,273],"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":278,"title":279,"type":24,"summary":280,"tags":281,"author":14,"cover_url":284,"published_at":285,"updated_at":286,"reading_minutes":287},"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.",[282,176,187,283],"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":289,"title":290,"type":24,"summary":291,"tags":292,"author":14,"cover_url":294,"published_at":295,"updated_at":296,"reading_minutes":297},"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.",[172,293],"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":299,"title":300,"type":24,"summary":301,"tags":302,"author":14,"cover_url":303,"published_at":304,"updated_at":305,"reading_minutes":306},"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.",[172,293],"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":308,"title":309,"type":24,"summary":310,"tags":311,"author":14,"cover_url":313,"published_at":314,"updated_at":315,"reading_minutes":287},"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.",[75,162,312],"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":317,"title":318,"type":24,"summary":319,"tags":320,"author":14,"cover_url":323,"published_at":324,"updated_at":325,"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.",[321,322,312],"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"]