Host production and PR previews on the VPS #303
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
spec
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
amaurycoudr/chess-project#303
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
Production and every PR preview run on free Render web services (ADR 0024). A free instance sleeps after 15 idle minutes and takes about a minute to wake, so the first Player to open a Room link after a quiet spell waits, and sleeping wipes every in-memory Room. Render's free tier also offers nothing for what comes next: the free Postgres expires after 30 days and the free Key Value loses its data on every restart, so accounts (the next increment) have no home there.
The owner has a VPS that is already provisioned for this: Ubuntu 26.04, SSH by key only for a
deployuser, ufw open on 22/80/443 only, Docker, a shared Traefik reverse proxy with Let's Encrypt, and DNS forchess.core-project.spaceand*.chess.core-project.space. Nothing of chess-project runs on it yet.Solution
Production and PR previews move to the VPS, behind the shared Traefik, and Render goes away.
maindeploys tohttps://chess.core-project.spaceonce CI is green on it. It never sleeps; a Room is lost only when production redeploys.https://pr-<n>.chess.core-project.space, redeployed on each push, removed when the PR closes, and never indexed by search engines.User Stories
https://chess.core-project.spaceto answer immediately at any hour, so that a Room link I receive never makes me wait for a server to wake.http://links to redirect to HTTPS, so that an old or hand-typed link still works./rpcon one origin, so that nothing about cross-origin requests can break a Move.main, so that the gate stays the only door to production.noindex, so that I can share a preview link without it showing up in search results.render.yamlgone once the VPS serves production and previews, so that there is one hosting setup to maintain.Seams
apps/e2e, driven against a deployed URL through a new target mode that starts no server and takes its base URL from the environment. Run after each preview deploy against that preview. Covers stories 1–8, 23. The existing local andbuiltmodes, and the CI guard against falling back to dev servers, stay as they are.http://redirects, and a preview carriesX-Robots-Tag: noindexwhile production does not. A failed check fails the run. Covers stories 9–22, 24–28, 31.Implementation Decisions
/rpcfrom one origin, as today (ADR 0024's one-origin decision survives the move). A multi-stage container build produces one image running the built API with the front's build output, the way the Render start command does now. No health endpoint is added;GET /(the served front) is the liveness probe.pr-<n>). The VPS never builds. The repo is private, so the package is private: each deploy logs the VPS into GHCR with the job's short-lived token for the pull and logs out after, so no registry credential stays on the server.proxynetwork and declares its Traefik router (host rule,websecureentrypoint, the Let's Encrypt resolver). Previews add a response-header middleware forX-Robots-Tag: noindex. One replica, restart unless stopped. Stacks are namedchessfor production andchess-pr-<n>for previews.ORIGIN_ALLOWLISTto its own HTTPS origin,FRONT_DIST_DIR, andPORT. The origin guard (ADR 0028) is unchanged.main. It deploys the image built for that commit, in a concurrency group that queues rather than cancels. A redeploy drops the in-memory Rooms, an accepted cost as under ADR 0024.chess-pr-*stacks, removes those whose PR is not open, then prunes unused images.deploywith a dedicated deploy key stored as a repo secret, the VPS's host key pinned in a secret rather than trusted on first use.deployruns Docker without sudo.render.yamlis removed and the Render services deleted.Testing Decisions
builttarget, which already drives build output rather than dev servers, and its guard that refuses to fall back to dev servers in CI. The deployed target follows the same pattern with a URL instead of started servers.presence.spec.tsmoves only the browser's clock and needs nothing from the server.noindex, so a preview middleware leaking into production fails the deploy.Out of Scope
Further Notes
deployuser with sudo, SSH by key only, root and password logins refused; ufw allows 22, 80 and 443 only; Docker 29 with Compose v5; Traefik v3.6 running as its own compose project on aproxynetwork, HTTP redirected to HTTPS, Let's Encrypt by HTTP challenge, no dashboard, containers exposed only when labelled; DNS A recordschessand*.chessoncore-project.spacepoint at the VPS; a dedicated deploy key is authorized fordeploy.mentioned in issue #304
mentioned in issue #305
mentioned in issue #306
mentioned in issue #307
mentioned in issue #308
mentioned in issue #309
mentioned in issue #310
mentioned in issue #311
marked this issue as related to #304
marked this issue as related to #305
marked this issue as related to #306
marked this issue as related to #307
marked this issue as related to #308
marked this issue as related to #309
marked this issue as related to #310