Ctrl K
ComunidadGuías…

DEPLOY.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Deploying Wilik

This assumes you've already done the Quick start in [README.md](README.md#quick-start) (clone, `.env`, `docker compose up -d`) and have it running. This doc covers everything that comes after: how updates ship, keeping your install up to date, HTTPS/reverse proxies, backups, rolling back, and (if this applies to you) migrating an older deployment onto this setup.

## How updates ship

This describes the pipeline that produces the default images in `docker-compose.yml` (`ghcr.io/joostvanopdorp/wilik-*`). If you're just running Wilik as-is, there's nothing to do here: it runs on the upstream repo, and new images land in GHCR for your host to pull (see [Keeping Wilik up to date](#keeping-wilik-up-to-date)). It's only actionable for you directly if you're running your own fork with your own CI and registry, since then `main` refers to your fork.

1. Push to `main`.
2. GitHub Actions (`.github/workflows/build-and-push.yml`) builds the backend and frontend images and pushes them to GHCR, tagged `latest` and with the commit SHA.
3. Your host picks up the new `latest` images the next time it pulls: by hand, from cron, or with an updater (see below).
4. On every backend start, `entrypoint.sh` backs up the SQLite file, runs `flask db upgrade` (applies any new migrations), then runs `flask bootstrap-db` (a no-op unless the database is empty) before starting gunicorn.

No local Docker build and no manual steps for schema changes: push to `main`, pull on the host, done.

## Keeping Wilik up to date

Wilik doesn't ship an updater: nothing in `docker-compose.yml` touches your Docker daemon or restarts containers on its own. How updates reach your host is up to you.

**By hand.** Pull the new images, then restart what changed:
```
docker compose pull
docker compose up -d
```
(`docker compose up -d` on its own does **not** pull new images, it only recreates containers whose config changed. You need the `pull` first.) Using backups? Add `--profile backup` to both commands, or set `COMPOSE_PROFILES=backup` in `.env` once.

**From cron.** The same two commands on a schedule, e.g. every night at 04:00 (`crontab -e`):
```
0 4 * * * cd /path/to/wilik && docker compose pull -q && docker compose up -d
```

**With Watchtower.** For updates within minutes of a release, add [Watchtower](https://github.com/nicholas-fedor/watchtower) in `docker-compose.override.yml` (create it if you don't have one; Compose loads it automatically):
```yaml
services:
  watchtower:
    image: nickfedor/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_LABEL_ENABLE: "true"   # only containers labelled for it, see docker-compose.yml
      WATCHTOWER_POLL_INTERVAL: "300"   # seconds
    labels:
      - "com.centurylinklabs.watchtower.enable=true"   # also update Watchtower itself
    restart: unless-stopped
```
Then `docker compose up -d`. Know what you're adding: Watchtower gets write access to the Docker socket, which amounts to root on the host. It's a third-party tool, and this project doesn't test it. (`nickfedor/watchtower` is a maintained fork; the original `containrrr/watchtower` is archived and fails on current Docker versions.)

**With your own tooling** (Komodo, Renovate, Diun, ...). `backend` and `frontend` use the rolling `latest` tag and `backup` uses `v2`, so anything that watches image digests works.

### Upgrading from a version with the bundled Watchtower

Older versions of `docker-compose.yml` started a Watchtower by default. If yours did, it keeps running and updating Wilik, also after you pull the new `docker-compose.yml`: Compose leaves the container in place (it warns about an "orphan container") and the `backend`/`frontend`/`backup` containers keep their Watchtower label.

- **To keep automatic updates**, add the Watchtower snippet above to `docker-compose.override.yml` and run `docker compose up -d`. From then on it's part of your own setup.
- **To drop it**, run `docker compose up -d --remove-orphans` and keep up to date another way (see above). Without either step it keeps running as before.

## HTTPS and reverse proxies

`docker-compose.yml` is kept generic on purpose, so you can pull future updates to it without fighting merge conflicts with your own setup. If you route Wilik through a reverse proxy (Traefik, Caddy, nginx-proxy, ...), put that config in `docker-compose.override.yml` instead: Compose loads it automatically alongside `docker-compose.yml`, no extra flags needed. It's gitignored, so it's entirely yours, git never touches it. See `docker-compose.override.yml.example` for a Traefik-based template.

If that proxy or tunnel terminates HTTPS for you, set `SESSION_COOKIE_SECURE=true` in `.env` so the session cookie is never sent over plain HTTP. It's off by default since LAN-only or plain-http setups would otherwise get silently locked out of login.

## Backups

Off-site backups are **optional**: the `backup` service sits behind a Compose profile and is skipped entirely by a plain `docker compose up -d`. When enabled, it makes an automatic off-site backup. It stops the `backend` container briefly (for a consistent snapshot, see the `docker-volume-backup.stop-during-backup` label on `backend`), archives the `wilik-data` volume, and uploads it to an S3-compatible bucket using [offen/docker-volume-backup](https://github.com/offen/docker-volume-backup). This uses static credentials (access key + secret key), not an OAuth login, so setup is just filling in `.env`, no browser flow, no expiring tokens to manage.

Setup:

1. Create (or reuse) an S3-compatible bucket. Any provider works (AWS S3, Backblaze B2, MinIO, ...). A distinct `AWS_S3_PATH` (see below) keeps it separate from anything else already in that bucket.
2. In `.env`, set:
   ```
   BACKUP_S3_BUCKET=your-bucket-name
   BACKUP_S3_ACCESS_KEY_ID=your-access-key-id
   BACKUP_S3_SECRET_ACCESS_KEY=your-secret-access-key
   ```
   The default `BACKUP_S3_ENDPOINT` (`s3.amazonaws.com`) only works for some AWS regions. If your bucket is in e.g. `eu-west-1`, set `BACKUP_S3_ENDPOINT=s3.eu-west-1.amazonaws.com` instead (AWS returns a `PermanentRedirect` error otherwise). Non-AWS providers should set their own S3 endpoint here too.
3. Optionally set `BACKUP_NOTIFICATION_URL` to get notified if a backup fails, e.g. for [ntfy](https://ntfy.sh): `ntfy://ntfy.sh/your-topic-name?title=Wilik` (or `ntfy://user:pass@your-host/topic?title=Wilik` if self-hosted). Add `?title=Wilik` to tell it apart from notifications for other apps. Any [shoutrrr](https://containrrr.dev/shoutrrr/) service works the same way.
4. Start it with the `backup` profile enabled:
   ```
   docker compose --profile backup up -d
   ```
   (A plain `docker compose up -d`, without `--profile backup`, leaves it out entirely, e.g. if you set up backups later, or never want them.)

Runs daily at 03:00 by default (`BACKUP_CRON_EXPRESSION`) and keeps 30 days of backups (`BACKUP_RETENTION_DAYS`), both configurable via `.env`. The schedule is in UTC unless you set `TZ` in `.env` (e.g. `TZ=Europe/Brussels`), which also keeps it at the same local time across daylight saving changes. Backups land under the `wilik/` path in your bucket.

## Rolling back

Old images stay in GHCR tagged by commit SHA. To roll back:
```
docker compose pull backend  # or manually retag an older SHA as :latest in GHCR
docker compose up -d
```
Note: rolling back the *app* does not roll back the *database schema*. If the bad release included a migration, rolling back the image alone won't undo it. Restore from a `wilik-data` backup instead if that happens.

## Migrating an older deployment onto this setup

Historical, one-time step. Skip this section entirely unless you're moving an *existing* Wilik install (one that predates this Docker/CI setup) onto it. A fresh install never needs this.

1. **Back up the `wilik-data` volume** before touching anything.
2. Make sure the GHCR packages (`wilik-backend`, `wilik-frontend`) are set to **Public** in GitHub's package settings, so your host can pull them without registry credentials.
3. Copy the updated `docker-compose.yml` and your `.env` (with `SECRET_KEY`) to your host.
4. Run the initial migration **stamp**, once, before starting the stack normally:
   ```
   docker compose run --rm backend flask db stamp head
   ```
   This tells Alembic "the database already matches this migration" without trying to re-create tables that already exist from the old `db.create_all()` setup. Skipping this step and letting the normal entrypoint run `flask db upgrade` first would fail, since it would try to `CREATE TABLE` on tables that are already there.
5. Start everything normally: `docker compose up -d`. This brings up `backend` and `frontend`.
6. Verify the app loads and existing data (users, wishlists) is intact.
7. Pick how you'll keep it up to date: see [Keeping Wilik up to date](#keeping-wilik-up-to-date).