Files
LedgerLine/docs/roadmap/phase-1.md
T
Movses AslanyanandClaude Sonnet 5.5 5e514ecf25 Add deployment phase and Traefik compose override
Insert a new Phase 1 (deployment: Compose + Traefik on a server, marked
Done) between the base project and the OTel concepts phase, and shift
the old phases 1-10 to 2-11. Update summary, intro, README and CLAUDE.md
references (spoiler rules now target Phase 9, the bottleneck hunt).

Add docker-compose.traefik.yml: an override that fronts the gateway with
Traefik and Let's Encrypt and removes all other published host ports.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 15:38:29 +03:30

75 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1 — Deployment: Ledgerline on a server behind Traefik
*Part of `docs/roadmap/` — see [`intro.md`](intro.md) for platform/background context and [`summary.md`](summary.md) for how every phase fits together. Prev: [`phase-0.md`](phase-0.md) · Next: [`phase-2.md`](phase-2.md)*
**Status:** Done
**Message:** Ledgerline is running on a remote server and served over HTTPS at
**https://ledgerline.vione.cloud**. Verified against the live deployment, not
just the config: the frontend loads, `/api/health/all` reports every service
`ok`, and the origin serves a real Let's Encrypt certificate (valid until
2027-01-07, auto-renewed by Traefik).
- **Target:** the throwaway server `czy` (Ubuntu 24.04, 1 vCPU, 1 GB RAM), repo
at `/opt/apps/LedgerLine`. Docker 29.9 and Compose v5.6 installed from
Docker's apt repo. A 2 GB swapfile was added (persisted in `/etc/fstab`) —
nine containers do not fit in 1 GB of RAM without it, and steady state still
uses roughly 700 MB plus swap.
- **How it's wired:** `docker-compose.traefik.yml` is an *override*, not an
edit of `docker-compose.yml`, so local development is unchanged. It adds
Traefik v3.6 on ports 80/443 (Docker provider, `exposedByDefault=false`,
HTTP→HTTPS redirect, Let's Encrypt via HTTP-01), routes
``Host(`ledgerline.vione.cloud`)`` to the gateway on port 8000, and strips
the published host ports from every other service (`ports: !reset []`) so
Postgres, Redis and the services are reachable only on the Compose network.
- **No application or `tests/` changes.** The Dockerfile and base compose file
are untouched; schema applied and data seeded on the server with the same
steps as `make seed` (800 accounts, 250,000 transactions).
- **Deploy / redeploy command** (always both files — a bare `docker compose up`
would use the base file alone and publish every port):
```bash
docker compose -f docker-compose.yml -f docker-compose.traefik.yml up -d --build
```
- **Cloudflare gotchas hit on the way:**
- The first certificate attempt failed with an ACME 404 because the
Cloudflare DNS record did not yet point at the server — a packet capture
on the server showed no inbound traffic from Cloudflare at all. Traefik
only retries issuance on restart, so after fixing the record it needed
`docker compose ... restart traefik`.
- With the orange-cloud proxy on, the SSL/TLS mode must be **Full** —
**Flexible** combined with Traefik's HTTPS redirect causes a redirect loop.
- **Caveats to remember:** the deployment is public, including the
`/api/admin/chaos` endpoints (anyone who finds them can flip flags);
internet scanners probed the site within seconds of it going live. The
server is disposable by design, and Traefik's state lives in the
`letsencrypt` volume, which is lost on an OS reinstall (a new certificate is
simply issued on the next run).
**Time-box:** 1 evening.
**Deliverable:** the unmodified-behaviour Ledgerline system reachable at a real
domain over HTTPS, reproducible with one compose command.
### Concepts
- **Traefik's model:** *entrypoints* (the ports it listens on), *routers*
(rule → service), *services* (where to send traffic), *middlewares*, and
*providers* (where config comes from — here, Docker labels on containers).
Compare with nginx, where the same information lives in one static config
file.
- **Compose override files.** `-f base -f override` merges the files;
`!reset` clears an inherited key (here, `ports`) instead of appending to it.
- **ACME HTTP-01 behind a CDN.** Let's Encrypt must be able to reach port 80 on
the *hostname's actual origin*. With Cloudflare proxying, that only works
once the DNS record points at the right server.
- **Why this phase exists before observability.** The telemetry work in
Phases 2–11 is more convincing when the system under observation is a real
deployment rather than a laptop, and the platform (`observability-ansible`)
is already a remote deployment — Ledgerline now sits on the same footing.
**Done when:** `https://ledgerline.vione.cloud` shows the frontend with a valid
certificate; `/api/health/all` is all `ok`; only ports 22, 80 and 443 are
reachable on the server; and the deploy is one documented compose command.