Deploy and operate
Get it live and keep it running.
Hosting and deployment
7 min readShipping is not the finish line, it is the point where the work becomes someone else's problem to rely on. A deploy setup you can trust has four properties, and each one exists to remove a specific way things go wrong later.
- Reproducible from a clean checkout: anyone, including you in six months, can clone the repo and build the exact thing that is live, with no missing manual step living only in your head.
- Connected to your repo: the host builds from your source control, not from files dragged up by hand, so what is live always traces back to a specific commit.
- Every push ships: a merge to your main branch triggers a build and deploy automatically, so shipping is not a separate ceremony you can forget to run.
- HTTPS on your domain: your real domain serves traffic over HTTPS with a valid certificate, not just the host's default subdomain.
- A one-step rollback: if a deploy breaks something, going back to the previous working version is a single action, not a scramble.
Why "reproducible from a clean checkout" matters most
It is the one property that catches every other mistake. If a fresh clone cannot build and run with nothing but the repo and its documented setup steps, something is hiding: an environment variable only set on your laptop, a manual database edit, a file that never got committed. A clean-checkout build is the cheapest test you have for "does this actually work, or does it just work on my machine."
| Symptom | What it usually means |
|---|---|
| "Works on my machine" but fails in a fresh clone | A dependency, config value, or setup step is undocumented |
| Deploying requires a person to remember a manual step | Part of the process lives outside the repo, in someone's memory |
| Nobody is sure which commit is actually live | The deploy is not tied to source control in a traceable way |
- Reproducible build
- A build that works the same way from a clean checkout every time, with no undocumented manual step.
- Rollback
- Reverting live traffic to a previous working deploy, ideally as a single action.
CI/CD: automate the path to production
7 min readCI/CD stands for continuous integration and continuous delivery (or deployment). Continuous integration means every change is built and tested automatically as soon as it is proposed. Continuous delivery means a change that passes those checks can reach production without someone manually repeating the steps by hand.
The path from a push to a live change
- 1PushA change is pushed, usually as a pull request
- 2Tests runAutomated checks run against the change
- 3Merge to protected mainMerge is blocked until checks pass
- 4Auto-deployThe merge triggers a deploy with no manual step
A protected main branch means nobody, including you, can push straight to it. Every change goes through a pull request, and the branch is configured to require passing checks before a merge button will even work. This is what turns "we are supposed to run tests" into something that is actually enforced instead of a habit that slips under deadline pressure.
Never commit secrets
An API key or password committed to a repo is compromised the moment it is pushed, even if you delete it in a later commit: it still exists in the repo's history, and public repos get scraped for exactly this within minutes. The fix is a secret scanner wired into the same CI pipeline that runs your tests, so a commit containing something that looks like a credential fails the check and never reaches main.
- Push a change as a pull request rather than directly to main.
- Automated tests, and a secret scanner, run against the change.
- The merge is blocked until every required check passes.
- Once merged, the deploy happens automatically, with no manual "now go run the deploy script" step.
- CI/CD
- Continuous integration and continuous delivery: automatically testing every change, then shipping the ones that pass with no manual step.
- Protected branch
- A branch, usually main, configured so changes can only land through a pull request that passes required checks.
- Secret scanner
- An automated check that flags credentials or keys accidentally committed to a repo before they reach main.
Scaling and caching
7 min readScaling is less about clever tricks and more about not painting yourself into a corner. Three habits cover most of what matters before traffic gets serious.
Keep app servers stateless
A stateless app server does not store anything about a specific user, like their session or uploaded files, only on its own local disk or memory. Session data goes in a shared store like a database or cache; uploads go to object storage. The payoff is that any request can be handled by any server, which is what makes it possible to run several servers behind a load balancer that spreads traffic across them. A stateful server, by contrast, ties a user to whichever one machine happens to hold their data, which caps how far you can scale and creates a single point of failure.
Put static assets on a CDN
A CDN (content delivery network) caches your static assets, images, scripts, stylesheets, on servers spread around the world, so a user in another country loads them from a nearby location instead of your one origin server. Cache headers tell the CDN, and the browser, how long it is safe to reuse a cached copy before checking for a new one. Get the headers right and most requests never have to reach your app server at all.
Right-size compute with a ceiling
Autoscaling that has no upper bound is not a safety net, it is a blank check: a traffic spike, a bug in a loop, or a bot flood can all scale your bill up right along with your compute. Set an explicit upper bound on how far you will scale, and pair it with a billing alert that notifies you well before a surprise becomes a surprise invoice.
| Habit | What it enables | What happens without it |
|---|---|---|
| Stateless app servers | Run several behind a load balancer | Scaling is capped and one server going down loses user data |
| CDN with cache headers | Static assets load fast, from close to the user | Every asset request hits your origin server, even far away |
| Compute ceiling + billing alert | Cost stays predictable | A spike or bug can scale your bill with no warning |
- Stateless
- An app server that keeps no user-specific data locally, so any instance can handle any request.
- Load balancer
- A layer that spreads incoming traffic across several servers instead of sending it all to one.
- CDN
- Content delivery network: a set of servers spread geographically that cache static assets close to users.
Monitoring and logs
7 min readOnce something is live, you find out it broke one of two ways: a user tells you, or your monitoring tells you first. The second one is always better, and it rests on four pieces working together.
- Centralized, searchable logs: every server's output lands in one place you can search, instead of SSHing into individual machines to read local files.
- No passwords or personal data in logs: logs get read, exported, and sometimes leaked. Treat them as something other people could eventually see, and never write a secret or a user's personal data into one.
- Error tracking with alerts on new errors: a dedicated tool that catches exceptions and notifies you specifically when a new kind of error shows up, not just a rising count of a known one.
- Request tracing end to end: the ability to follow one request through every service it touched, so a slow or broken request is a lookup, not a guessing game.
- Uptime and health checks: a check, often from outside your infrastructure, that regularly confirms the app is actually reachable and responding.
Why "no secrets in logs" is a hard rule, not a preference
Logs tend to be more widely accessible than the systems they describe: more people can read them, they get shipped to third-party tools, and they are kept around far longer than a single request. A password or a user's personal data logged once is effectively logged forever, copied into every backup and export that log ever touches. Treat log statements with the same care as anything else that leaves your system.
| Piece | Question it answers |
|---|---|
| Centralized logs | What actually happened, across every server, in one searchable place? |
| Error tracking | Did something new just start failing? |
| Request tracing | Where, in a chain of services, did this one request slow down or break? |
| Uptime and health checks | Is the app reachable and responding right now? |
- Error tracking
- A dedicated tool that captures exceptions and alerts on new or newly frequent errors, beyond what raw logs show at a glance.
- Request tracing
- Following a single request across every service it touches, to see where it slowed down or failed.
- Health check
- An automated, regular check, often from outside your own infrastructure, that confirms the app is reachable and responding.
Section 4 quiz
25 questions. Pass at 75% to master this section. Retakes are unlimited, and the quiz is where the learning sticks.
According to the lesson, what does "reproducible from a clean checkout" actually test?