Files
malenia-web/deploy/README.md

83 lines
3.2 KiB
Markdown

# Production deployment
This stack exposes only Caddy on ports 80 and 443. PostgreSQL and the FastAPI backend
share an internal Docker network. The backend additionally uses a non-published egress
network for DNS and outbound requests to Pally and Remnawave. Caddy serves the Vite SPA and
proxies public `/api/*` requests to the backend after removing the `/api` prefix.
## First deployment
1. Point the `malenia.space` A record to the VPS public IPv4 address.
2. Install Docker Engine and the Docker Compose plugin on the VPS. Allow only TCP 22, 80,
and 443 through the host firewall.
3. Clone the repository to `/opt/malenia` and create `/opt/malenia/.env` from
`.env.example`. Set file mode `600` and replace all placeholder values.
4. Put `private.pem` and `public.pem` in `/opt/malenia/keys`, set `KEYS_DIR=/opt/malenia/keys`
in `.env`, then grant access only to the backend container user:
```bash
sudo chown -R 10001:10001 /opt/malenia/keys
sudo chmod 700 /opt/malenia/keys
sudo chmod 600 /opt/malenia/keys/*.pem
```
5. Build and start PostgreSQL, then apply migrations:
```bash
docker compose --env-file .env -f compose.production.yml up -d postgres
docker compose --env-file .env -f compose.production.yml --profile tools run --rm migrate
```
6. Start the application:
```bash
docker compose --env-file .env -f compose.production.yml up -d --build
```
7. Verify `https://malenia.space/api/health/` and the primary frontend flows.
## Releases
Before each release, run frontend checks locally. On the VPS, pull the intended revision,
apply migrations, then rebuild and recreate services:
```bash
git pull --ff-only
docker compose --env-file .env -f compose.production.yml --profile tools run --rm migrate
docker compose --env-file .env -f compose.production.yml up -d --build
```
The Pally callback URL is `https://malenia.space/api/payments/pally/result`.
## Local production-like test
This test uses the same images, API proxying, and rate-limit plugin as production, but
serves HTTP on `http://localhost:8080`. It does not need a domain, TLS certificate, or VPS.
1. Create a local `.env` from `.env.example` and fill the required backend integration
settings. `POSTGRES_HOST=postgres`, `PRIVATE_KEY_FP=/run/secrets/keys/private.pem`, and
`PUBLIC_KEY_FP=/run/secrets/keys/public.pem` must remain unchanged. The local `keys/`
directory must contain both PEM files. The local Compose override runs backend commands as
root only to read host-owned PEM files with mode `0600`; this override must not be used in
production.
2. Start PostgreSQL and apply migrations:
```bash
docker compose --env-file .env -f compose.production.yml -f compose.local.yml up -d postgres
docker compose --env-file .env -f compose.production.yml -f compose.local.yml --profile tools run --rm migrate
```
3. Build and run the stack:
```bash
docker compose --env-file .env -f compose.production.yml -f compose.local.yml up -d --build
```
4. Check the frontend at `http://localhost:8080` and the backend through Caddy at
`http://localhost:8080/api/health/`.
5. Stop the local stack while preserving its database volume:
```bash
docker compose --env-file .env -f compose.production.yml -f compose.local.yml down
```