Files
scrabble-game/deploy/ansible/README.md
T
Ilia Denisov 48b06f4594
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 16s
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m21s
docs: finalize documentation to the production state
The project is live in production, so the staged-development scaffolding is removed.

- Delete the staged trackers PLAN.md and PRERELEASE.md.
- Rewrite CLAUDE.md: drop the per-stage workflow; codify the ongoing development
  principles (How we work) and the production model (Branching, CI & production):
  manual prod-deploy / prod-rollback, semver release tags, Ansible provisioning,
  expand-contract migrations.
- De-stage the living docs (README, ARCHITECTURE, TESTING, deploy/ansible, loadtest,
  platform/telegram READMEs) and the docker-compose tuning comments: drop the
  Stage N / R1-R7 / pre-release labels, keep every number and rationale, and fix the
  now-dangling PLAN.md / PRERELEASE.md references to describe the current state.
- Reword stale 'later stage' Go doc comments for subsystems that have shipped.
2026-06-22 08:33:30 +02:00

50 lines
1.9 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.
# Prod host provisioning
Idempotent Ansible that prepares the two production hosts. It installs Docker, a
non-sudo `deploy` service account, SSH hardening, a default-deny firewall,
fail2ban, unattended security upgrades and time sync. It does **not** deploy the
application — that is `.gitea/workflows/prod-deploy.yaml`'s job, running as the
`deploy` account this playbook creates.
Hosts are referenced by `~/.ssh/config` aliases (`scrabble-main-ops`,
`scrabble-tg-ops`), so no IPs or key paths live in the repo.
## Prerequisites (controller)
- `ansible` with the bundled collections (`community.general`, `community.docker`,
`ansible.posix`).
- The two hosts reachable as root via the ssh-config aliases, host keys already
accepted into `known_hosts` (`host_key_checking = True`).
## One-time: the CI deploy key
The CI prod-deploy workflow logs into the hosts as `deploy` using a dedicated
key. Generate it once on the controller, authorize its public half via the
playbook, and store its private half **only** in the Gitea `PROD_SSH_KEY` secret:
```sh
ssh-keygen -t ed25519 -N '' -C scrabble-ci-deploy \
-f ~/.ssh/scrabble_ci_deploy_ed25519
# private half -> Gitea secret PROD_SSH_KEY (set via API); never commit it
```
## Run
```sh
cd deploy/ansible
ansible-playbook site.yml
```
The playbook reads the public key from `~/.ssh/scrabble_ci_deploy_ed25519.pub` by
default; override with `-e deploy_ci_pubkey_path=/path/to/key.pub`. Re-running is
safe (idempotent) and survives a host resize.
## What each host gets
- **both** (`common`): docker-ce + compose plugin, `daemon.json` (live-restore,
10m×3 log rotation), `deploy` user (docker group, no sudo), key-only sshd,
`ufw` default-deny incoming + allow SSH, fail2ban sshd jail, unattended
upgrades, chrony, `/opt/scrabble/{config,certs,dumps,images}`.
- **main**: `ufw` opens 80/443/9443; the external `edge` docker network.
- **tg**: verifies direct `api.telegram.org` egress (the no-VPN assumption).