Short write-ups kept while building and running the lab. Each note stays deliberately compact — enough to reproduce the result, not a full manual.
Notes archive
Filtering happens locally in your browser — nothing is sent anywhere.
Showing 6 of 10 notes
WebAugust 11, 20266 min read
Understanding reverse proxies
A reverse proxy takes a request that was addressed to your public hostname and forwards it to a service that never has to know about the outside world. Getting the header handling right is most of the work.
The edge owns TLS, hostname routing and timeouts; the application owns business logic. Keeping that split clean avoids most "works locally, fails in production" reports.
Forward the original host and scheme, or the application will generate wrong absolute URLs.
Set upstream read and connect timeouts explicitly — defaults are rarely what you want.
Terminate TLS once, at the edge, and keep the internal hop simple.
Log the upstream response time separately from the total request time.
LinuxJuly 29, 20267 min read
Linux service monitoring basics
A unit reported as active (running) only means the process exists. Turning that into a useful signal means asking the service to prove it can still do its job.
Process liveness, port reachability and functional response are three different checks. Alerting on the first alone produces both false calm and false alarms.
Combine systemctl is-active with a real request against the service.
Give every check a timeout shorter than the interval it runs on.
Record consecutive failures before alerting, so one slow response is not an incident.
Keep restart counters visible — a service that restarts hourly is failing quietly.
NetworkingJuly 8, 20268 min read
A practical introduction to DNS
DNS problems rarely look like DNS problems. Understanding the order of resolution and how TTLs age makes intermittent failures much easier to explain.
Query the authoritative server directly before blaming the record; most "the change did not apply" reports are caches still serving a previous answer.
Lower TTLs before a migration, not during it.
A and AAAA records need to move together, or dual-stack clients split traffic.
Check every authoritative server — inconsistency between them looks random to users.
Negative answers are cached too, so a missing record can outlive its fix.
APIJune 22, 20265 min read
Designing simple API integrations
Most small integrations fail for the same three reasons. Deciding on timeouts, retry behaviour and idempotency up front removes nearly all of them.
Treat the remote service as something that will be slow, unavailable and occasionally wrong — then the failure path is designed instead of discovered.
Always set a connect and a read timeout; an unbounded call blocks a worker forever.
Retry only idempotent operations, with backoff and a hard attempt limit.
Send an idempotency key for anything that creates state.
Log the request identifier returned by the remote side — it is what support will ask for.
AutomationMay 30, 20266 min read
systemd timers instead of cron
Timers give scheduled work the same lifecycle, logging and dependency handling as any other unit — which is usually worth the slightly longer syntax.
The main practical gain is observability: a timer's last run, next run and full output are all queryable without extra tooling.
systemctl list-timers answers "did it run?" immediately.
Persistent=true catches up on runs missed while the host was down.
RandomizedDelaySec keeps many hosts from starting at the same second.
Output goes to the journal, so no per-job log redirection is needed.
NetworkingMay 12, 20266 min read
Reading TLS handshake failures
Handshake errors are noisy but structured. Knowing which side gave up, and at which step, narrows the cause to one of about four possibilities.
An incomplete chain is the most common cause and the easiest to miss, because desktop browsers often repair it silently while other clients do not.
Test with the exact hostname — a missing SNI produces a misleading certificate.
Verify the intermediate chain, not just the leaf certificate.
Check clock skew on the client before suspecting the server.
Confirm which protocol versions and cipher suites the edge actually offers.
WebApril 24, 20265 min read
Cache headers that actually help
Static assets and HTML documents need opposite policies. Sending one policy for both is why a deploy either does not appear or is downloaded again every visit.
Version your asset filenames and cache them aggressively; keep documents short-lived and revalidated. Everything else follows from that split.
Fingerprinted assets can safely use a long max-age with immutable.
HTML should revalidate, so a deploy is visible on the next request.
Keep ETag generation consistent across hosts, or revalidation always misses.
Measure with a cold cache — warm-cache numbers hide the real first visit.
LinuxApril 3, 20267 min read
Structured logging on a single host
You do not need a log cluster to get the benefits of structured logs. Consistent fields and one searchable stream cover most single-server debugging.
The goal is to answer "what happened to this one request" without opening four files. A shared request identifier does most of that on its own.
Emit one event per line with a stable set of keys.
Propagate a request identifier from the edge into application logs.
Log durations as numbers, not formatted strings.
Set retention per unit so noisy services cannot fill the disk.
APIMarch 17, 20265 min read
Rate limiting without surprises
A limit that is invisible until it is hit will be hit. Publishing the remaining quota turns rate limiting from an outage into a scheduling problem.
Clients behave far better when the response tells them what to do next, rather than simply refusing the request.
Return 429 with a Retry-After value the client can honour.
Expose remaining quota and reset time on every response, not just failures.
Allow a small burst above the steady rate for interactive use.
Apply limits per credential, not per address, when clients share networks.
AutomationFebruary 26, 20266 min read
Idempotent server scripts
A maintenance script is only useful if running it twice is safe. Writing for reruns from the start is much easier than retrofitting it after a partial failure.
Check the desired state before changing anything, and make every step describe what it would do when asked.
Start with set -euo pipefail so failures stop the run.
Test for the end state instead of assuming the starting one.
Write to a temporary file and move it into place atomically.
Provide a dry-run mode that prints the intended changes only.
No notes match your search. Try a different keyword or category.