# Production deployment and rollback

The production host needs only a Compose file, `config.toml`, and persistent
data. It does not need a source checkout.

## Files

Create an application directory like this:

```text
/opt/ushort/
├── docker-compose.yml
├── config.toml
└── data/
```

Copy [`deploy/docker-compose.prod.yml`](../deploy/docker-compose.prod.yml) to
the server as `docker-compose.yml`. For repeatable releases, replace its image
tag with the verified multi-architecture digest:

```yaml
image: docker.io/sodium/ushort:0.1.2@sha256:<verified-index-digest>
```

Set `db_path = "data/urlshort.db"`. The executable always serves its embedded
frontend. Keep `config.toml` owned by the container identity (`1001:1001`) with
mode `0400`; the `data` directory must be writable by the same identity.

## Start and validate

```bash
cd /opt/ushort
docker compose config
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 ushort

curl -i http://127.0.0.1:18082/s/api/health
```

Adjust the health path to match `base_url`.

## Reverse proxy

Choose one nginx snippet and include it inside the public `server {}` block:

- [`deploy/nginx.path.conf`](../deploy/nginx.path.conf) for a path such as
  `https://example.com/s`;
- [`deploy/nginx.subdomain.conf`](../deploy/nginx.subdomain.conf) for a host
  such as `https://s.example.com`.

Both snippets proxy the frontend, API, and redirects to `127.0.0.1:18082`.
They apply `no-store` to the HTML entry point and `no-cache` to static assets.
The path snippet is written for `/s`; replace each `/s` location when using a
different configured prefix.

Test nginx before reloading it:

```bash
nginx -t
nginx -s reload
```

Then verify the public health endpoint, frontend, static assets, and an
existing short-code redirect. [`tests/smoke.sh`](../tests/smoke.sh) exercises
the complete trailing-slash route set against a disposable record.

## Update

1. Verify the published image contains both AMD64 and ARM64 manifests.
2. Pull the exact version and digest before changing the running service.
3. Create and integrity-check an online SQLite backup as described in
   [Data and database compatibility](data.md).
4. Update the image reference and run `docker compose up -d`.
5. Check health, logs, restart count, database integrity, and public routes.

## Rollback

Restore the previous image reference and run:

```bash
docker compose up -d
```

The schema is release-compatible. If the failed release changed or damaged
data, stop the service and restore the pre-update SQLite backup before bringing
the previous image back up. Preserve any legitimate writes made after the
backup before replacing the database.
