DevOps Engineer|Gamer
Veni. Vidi. Vici.
Chapter 01
Everything below this line is running on this machine right now.
Chapter 01 / Live Infrastructure
01
A production URL shortener, built and deployed end to end on a single VPS — application, container, reverse proxy, TLS and CI. Not a tutorial follow-along: every layer was a decision, and the interesting part is the decisions.
56.8B
possible short codes
3
API endpoints
17
pinned dependencies
0
records lost per rebuild
Each of these had a cheaper option that I chose against. The reasoning is the point.
How are short codes generated?
● secrets random
Six characters from the full alphanumeric set gives about 56.8 billion combinations, which is ample. But size of the space is irrelevant if the generator is predictable. Python’s random is a Mersenne Twister seeded from system time — observe enough outputs and you can reconstruct the state and predict every subsequent code. secrets draws from the OS entropy pool instead. Same code length, same user experience, no enumeration risk.
Why SQLite and not Postgres?
● SQLite Postgres
At this scale Postgres would mean a second process, a second container, a network hop on every query and credentials to manage — real operational weight bought for zero benefit. SQLite is one file with none of that. The important part is that nothing in the codebase is SQLite-specific: everything goes through the ORM, so switching is a connection-string change rather than a rewrite. That is what makes the choice reversible rather than a corner.
Why does the DB dependency yield instead of return?
● yield + finally return
A return hands the session to the handler and the function is done — nothing runs afterwards. If that handler raises, the session is never closed and the connection leaks. Under load that is a slow exhaustion bug that only shows up in production. Yielding inside a try/finally means the framework resumes the generator after the response, and the close runs whether the handler succeeded or blew up.
Why put Nginx in front at all?
● reverse proxy expose the app directly
The application server can speak HTTP perfectly well on its own, so the proxy looks like a spare part until you count what it centralises: TLS termination and renewal, the HTTP-to-HTTPS redirect, static files served without waking the application, and a single public listener instead of one per service. Add a second service later and none of that has to be solved twice.
Why is application data on a volume?
● mounted volume container filesystem
A container’s writable layer dies with the container. Data written there survives exactly until the next rebuild, which turns every deploy into a decision about whether it is worth losing the database. Moving state onto a volume makes rebuilds boring, and boring rebuilds are what let you deploy often enough to keep changes small.
Known gaps, with the reasoning for leaving them open rather than the pretence that they are not there.
Creation is unauthenticated by design, which means anyone can mint links pointing anywhere. That is an abuse vector — someone else’s phishing link on my domain — and it is the first thing I would close. The fix lives in the proxy layer rather than the application, which is exactly why the proxy is there.
Tables are created from the model definitions when the app boots. That is fine while the schema is stable and I am the only developer, and it stops being fine the moment a column needs to change on live data. Alembic is the answer; I have not added it because there has been nothing to migrate yet, and unused migration infrastructure rots.
There is a compose definition for multiple replicas behind the proxy, and it is deliberately not running — because pointing several writers at one SQLite file over a shared volume produces lock contention and corruption, not throughput. The database migration has to land before the replica count goes up. Doing them in the wrong order would look like scaling and behave like an outage.
Every redirect increments a counter and the stats endpoint returns it, but nothing aggregates or graphs it. Real observability means metrics collection and dashboards, which is worth doing when there is enough traffic for a graph to say something.
Most people bail at the architecture diagram. You read the part about connection leaks.
Fine. You have earned the other half.
Ok. Enough infrastructure.
LET’S PLAY.
Chapter 02
Same operator, different system. This is where the patience comes from.
Games I have finished rather than owned. The hard ones are on this list for the same reason the connection-leak bug is on the other one — the interesting part is what it takes to get through.
What is actually in the disc tray right now.
In rotation
Long sessions, other people, plans that survive contact with nobody.
In rotation
Open world, and a standing refusal to use the map marker.
CHIRAG.EXE
System offline
DevOps is how I build systems.
Gaming is what I do when those systems are not on fire.