Spinning up a container is five minutes of work. Everything that makes a service belong to the platform rather than sit next to it (reachable the right way, watched the right way, not a landmine for whoever’s on call when something breaks, which on a personal platform is always the same one person) is a checklist of decisions that docker compose up doesn’t make for you. I’ve caught myself skipping most of this checklist at least once each, usually for something I told myself was “just a quick thing,” and every time, the shortcut showed up later as a worse problem than the five minutes it would’ve taken to think about up front.
None of these decisions are exotic. They’re the same five categories every time, and writing them down as a fixed list is mostly a defense against the version of me that’s excited about the new service and wants to skip straight to using it.
Where does it live on the network
Not every service needs the same exposure, and the default should be the least exposure that still lets the service do its job. A service that’s only ever going to be used from inside the network doesn’t need a path to the outside at all: the decision to put it on a segment reachable from the internet, even behind auth, is a decision that should be made deliberately, not inherited by default because that’s where the last three services went.
This also isn’t a one-time decision that disappears once made. A service placed on an internal-only segment today because “nothing external needs it yet” is a service someone will eventually want to reach from outside, and the honest version of this checklist item is deciding now whether that’s a placement that’s supposed to change later, or a permanent boundary that a future request to loosen should be pushed back on. The stakes on this decision go up considerably once the service in question belongs to someone else entirely rather than to me — see Client Isolation Tiers for what changes once a workload is externally owned instead of internal-by-default.
What’s its ingress path
Assuming the service needs to be reached by something, how does traffic get to it: a reverse proxy entry, a direct port exposure, a tunnel endpoint? This is a smaller decision than network placement but a more concrete one, because it’s the thing that has to be undone carefully if the service is ever retired: a forgotten reverse-proxy route or an open port for a service that’s no longer running is exactly the kind of stale entry that turns into an unexplained “why can something reach this” question months later.
The ingress decision and the network-placement decision aren’t the same question asked twice. A service can be correctly placed on a restricted segment and still have a badly-chosen ingress path: TLS termination happening somewhere it shouldn’t, a proxy rule that’s broader than the one hostname it needs to match. Both have to be decided, and neither one substitutes for the other.
How does it get wired into observability
A service that exists but produces no signal is a service that fails silently, and “I’ll add monitoring later” is the checklist item most likely to just never happen once the service is working and attention has moved on. This means deciding, at setup time, how this specific service reports its own health: does it expose metrics a scraper can pick up, does it log in a way that’s actually useful once it lands in whatever log aggregation the platform runs, does it need its own entry in whatever external uptime checking exists.
That last one matters specifically because it’s easy to assume a service that has metrics and logs is “monitored” and skip the outside-in check, but internal metrics can’t see a firewall rule or DNS record that makes the service unreachable from where it needs to be reached from. Wiring a new service into observability means deciding all three of these, not just the one that happens to be easiest to bolt on after the fact.
Where do its secrets live
Every service that isn’t a completely static, unauthenticated tool has at least one credential (an API token, a database password, a signing key) and “where does it live” is a decision that has to be made before the service starts, not discovered later when someone asks “wait, is that key just sitting in the compose file.” The platform-level answer to this should already exist (a secrets store, an env-file convention, whatever the platform has standardized on), and the checklist item isn’t inventing a new answer per service, it’s making sure this specific service’s secrets go through the existing answer instead of taking the path of least resistance that happens to be fastest to get running today.
This is also the item most likely to accumulate quiet debt: a secret hardcoded temporarily “just to get it working” that’s still hardcoded three months later because the service has been working fine and nobody’s had a reason to touch that file since.
How does it get backed up, or explicitly not
The last decision is the one it’s easiest to skip because skipping it produces no visible symptom — until the day it does. Every new service either holds state worth recovering (a database, uploaded files, configuration that took real effort to build) or it genuinely doesn’t (a stateless proxy, a cache that rebuilds itself, a tool that’s trivially reinstallable from its own config-as-code). The checklist item isn’t “back everything up,” it’s making that call explicitly, one way or the other, at setup time, so that “we didn’t back this up” is a decision on record rather than a gap nobody noticed until the service’s data was gone.
A service with state that never gets an explicit backup decision defaults to “not backed up” by omission, and the failure mode there isn’t subtle: it’s the one where the recovery conversation starts with “wait, did anyone ever set up backups for this.”
It also helps to separate “backed up” from “restorable,” because they aren’t the same claim. A backup job that’s been running quietly for months but has never once been tested by restoring from it is a belief, not a guarantee, and on a personal platform, where the backup job itself is one more piece of unmonitored infrastructure unless it’s wired into the same observability decision made above, it’s entirely possible for that job to have been silently failing for a while before anyone needed the thing it was supposed to protect. The checklist item isn’t complete at “a backup job exists for this service,” it’s complete at “a backup job exists, and I know it produces something restorable,” which is a meaningfully higher bar and the one that matters the day it’s needed.
The order matters more than the list
Having all five categories written down doesn’t by itself prevent the most common failure mode, which is doing them in the wrong order: specifically, starting the container first and treating the rest as cleanup. Once a service is running and reachable, the pressure to go back and finish the observability wiring, or move the hardcoded credential into the real secrets flow, drops sharply, because the service now looks done. It responds to requests. It does the thing it was added to do. The gap between “looks done” and “actually done” is invisible from the outside, which is exactly why it tends to stay open.
The more reliable ordering, in my experience, is to treat network placement and secrets handling as decisions that block starting the container at all — not because they’re technically hard to retrofit, but because retrofitting them requires going back and touching a running thing, which is friction that reliably doesn’t get paid later. Ingress and observability wiring can reasonably happen in the same sitting as bringing the service up, immediately after, before moving on to whatever the service was needed for. Backup policy is the one item that can legitimately wait a little longer without harm, provided “wait” means “explicitly deferred with a reason,” not “forgotten”: a stateless service really can have its backup decision made correctly as “not needed,” and that’s a fine place to land as long as it was decided rather than defaulted into.
The pattern behind all of this is that a checklist only does its job if it’s consulted before the satisfying part (the thing runs, it works) removes the motivation to consult it. A checklist that lives in a person’s head, to be applied “when I remember,” reliably gets skipped exactly when it’s most useful — on the service added at the end of a long day, the one added because something else is currently broken and needs a quick replacement, the one that feels too small to deserve the full five items. Those are the services most likely to still be missing observability wiring and a real secrets story a year later, not because anyone decided to skip the checklist, but because nobody consulted it in the first place.
The actual point of the checklist
None of these five categories are hard individually. Network placement is one conversation with yourself about exposure. Ingress is picking the right proxy entry. Observability wiring is three small additions, not one big one. Secrets have a platform-level answer already; using it is the whole task. Backup is a yes/no decision with a reason attached.
The value of holding them as a fixed checklist rather than trusting memory is specifically that “just start the container” feels complete on its own (the service runs, it responds, it looks done) while quietly skipping all five of these. A personal platform doesn’t have a second person to catch the gap in code review, and it doesn’t have an onboarding process that forces the checklist on you the first time. The checklist is the substitute for both of those things: not a bureaucratic gate, just a fixed list of the categories of decision that “run the container” quietly defers, applied the same way every time a new service joins the platform.