make check: A Cheap Smoke Test Before You Break Prod
Two commands, a few seconds, no container ever bound to port 443 — make check validates the compose file and boots Traefik once against the static config before docker compose up ever touches the box actually serving nissaar.com.
docker compose up -d --force-recreate traefik on vmi2633427 restarts the single reverse proxy sitting in front of every service on nissaar.com. A YAML mistake in the static config doesn't fail gracefully there — it fails as a dead entrypoint, on the box, mid-restart. make check exists specifically to make that failure happen somewhere cheaper first.
Validate the compose file, then boot Traefik once against the static config — neither step touches :443.
What the target actually runs
check: ## Validate the compose file and Traefik's static config
docker compose config -q && echo "compose: ok"
docker run --rm -v "$(CURDIR)/data:/data:ro" traefik \
--configFile=/data/config/traefik.yml --entrypoints.dummy.address=:9 2>&1 \
| head -20Two distinct checks, each catching a different class of mistake:
docker compose config -q parses docker-compose.yml, resolves all variable interpolation and YAML anchors, and validates the result — silently, with -q suppressing the resolved output, and a non-zero exit if anything doesn't parse. This catches a broken anchor, a missing environment variable, an indentation error, before a single container is touched.
The second line runs an actual, throwaway Traefik container against the real static configuration file, mounted read-only, with one deliberate twist: --entrypoints.dummy.address=:9. That flag doesn't matter for what it does — it matters because it gives Traefik an entrypoint to bind to that isn't :80 or :443, so this check container never collides with the real Traefik process already listening on those ports. Traefik starts, parses traefik.yml, logs its startup sequence, and head -20 captures just the top of that log — enough to see a config parse error if there is one, without needing to watch the container run indefinitely.
Why this catches what compose config alone misses
docker compose config validates YAML structure and Compose semantics. It has no idea whether traefik.yml — the file passed via --configFile, read entirely by Traefik itself — is valid Traefik configuration. A malformed provider block, an unknown entrypoint option, a typo in a certificate resolver name: none of that is Compose's problem, all of it is Traefik's, and none of it surfaces until Traefik actually tries to parse the file at startup. Running that startup once, throwaway, with a harmless dummy entrypoint, is the only way to catch it before the real container does.
The cost-benefit is deliberately lopsided
Both checks together run in a few seconds. Neither one binds to :443, neither one interrupts the live Traefik process, and neither requires any state beyond what's already in the repo. Compare that to the alternative: run git pull && make up directly, discover the static config doesn't parse, and now the box that fronts every self-hosted service is down until the mistake is found and fixed — under time pressure, on infrastructure other things depend on.
The general shape of this pattern
This is a smoke test in the strictest sense — not exhaustive, not a substitute for real testing, just cheap enough to run before every deploy and targeted enough to catch the specific failure mode (a parse error) that a restart would otherwise surface at the worst possible time. It generalizes past Traefik: any daemon that reads a static config file at startup can be smoke-tested the same way — run it once, disposably, against a harmless bind address, and read the first few lines of its own boot log.
Series: The Self-Hosting Stack. Next: keeping secrets in a private git repo without leaking them.