Deployment¶
Every service in the ecosystem uses one deployment pattern. This page describes it.
No host-specific detail here
Operational specifics — server addresses, usernames, secret configuration — are not part of this public site. They live in a closed runbook inside the relevant repository.
The general pattern¶
Internet
│
▼
┌─────────────────┐
│ edge nginx │ TLS termination · HSTS · rate limit
│ (container) │ each vhost → an internal service
└────────┬────────┘
│ shared Docker network
┌────────┴──────────────────────────────┐
│ │
▼ ▼ ▼
app A app B static site
(Go + Next) (Go + Next) (nginx)
│ │
└────────┬───────┘
▼
PostgreSQL · Redis (shared)
Core principles:
- One edge, many vhosts. A single nginx container on the outside owns ports
80/443. Each domain has its own
serverblock and proxies to an internal service. - Internal services are not exposed. Applications listen only on the shared
Docker network, or bind to
127.0.0.1. They cannot be reached directly from outside. - Shared infrastructure. One PostgreSQL and one Redis instance serve many applications; each application has its own database/schema.
- Docker Compose — each application has its own compose stack, attached to the shared network.
The edge nginx¶
The edge is responsible for:
| Role | Notes |
|---|---|
| TLS termination | Let's Encrypt certificates, renewed automatically |
| HSTS | max-age=63072000; includeSubDomains |
| Rate limiting | By zone: auth (strict) · app (lenient) · api |
| Reverse proxy | vhost → internal service |
| Rejecting unknown hosts | Default server → drop the connection |
Edge configuration is managed through git
The edge nginx conf.d directory is synced from a specific repository via
git. Any manual edit on the host will be overwritten by
git reset --hard at the next deploy.
Adding or changing a vhost is therefore done by committing to the repository and letting CI distribute it.
A second pattern — a service owning its own vhost
There is also a pattern where a vhost that concerns only one service lives
in that service's repository rather than in a central file, and its
deploy installs the config into the edge's conf.d as a separate file.
The advantage: a change is contained in one repository and does not wait on another team's deploy. The condition: the config must be fully self-contained — it may not depend on a rate-limit zone or default server defined in another file.
This site itself works that way — see This docs platform.
Certificates¶
- Let's Encrypt, via
certbotin webroot mode. - The ACME challenge is served over port 80 at
/.well-known/acme-challenge/. - Renewal is automatic, weekly by cron; on success nginx is reloaded.
To add a new domain:
- Point DNS at the server.
- Add the domain to the ACME block on port 80.
- Obtain the certificate with certbot.
- Add the HTTPS vhost and point it at the certificate.
- Run
nginx -t, then reload.
Static sites (documentation portals)¶
Documentation sites are pre-built static HTML. The simplest way to run them:
- build
site/with MkDocs, - copy the result to the server,
- have a small
nginx:alpinecontainer serve it, - have the edge nginx proxy to that container.
There is no application runtime, so resource use is low and there is little to break.
This site runs exactly like that — see This docs platform for the detail.
Deploying applications¶
Two patterns are in use for applications:
| Pattern | Notes |
|---|---|
| Build on the host | CI syncs the repository to the host and runs docker compose build && up -d |
| Via a registry | CI builds the image and pushes it to a registry; the host runs pull && up -d |
The trend is towards fewer dependencies — there are cases that moved from an external registry to building on the host.
Partial deploys: CI determines which services to rebuild from the changed
paths (paths-filter). A change in one application does not disturb the others.
Rollback¶
- Static sites — unpack the archive of the previous build.
- Applications — return to the previous image tag (it can be pinned with a
<SVC>_IMAGE_TAGvariable).
Health checks¶
Every service has a /health endpoint. Compose healthcheck definitions verify
that infrastructure such as PostgreSQL and Redis is ready, and start the
application only once they are.
Deployment checklist¶
- [ ] DNS pointed correctly
- [ ] Certificate issued and covered by automatic renewal
- [ ] Edge vhost added and committed to the repository
- [ ]
nginx -tpasses - [ ] Internal services not exposed externally
- [ ]
/healthresponding - [ ] Secrets via environment variables, absent from the repository
- [ ] A clear way to roll back
For the automation detail, see CI/CD.