Files
Kurt_kalendar/ht_booking/DEPLOY.md
2026-05-16 23:03:29 +02:00

5.5 KiB

Deploying ht_booking (Tenis Rajec)

This app ships as a single Docker container that runs behind your existing shared Caddy reverse proxy. Caddy terminates HTTPS; the app container has no host ports and is reachable only through Caddy. The SQLite database lives on a Docker volume so it survives rebuilds and restarts.

Internet ──▶ Caddy (:80/:443, HTTPS)
                 │  reverse_proxy ht-booking:5150   (over tenisrajec-net)
                 ▼
           ht-booking container ──▶ /usr/app/data/production.sqlite
                                          (Docker volume: ht_booking_data)

Files in this repo that drive the deployment:

File Role
Dockerfile 3-stage build: CSS → Rust binary → slim runtime image
docker-compose.prod.yml the app service, volume, network
Caddyfile the site's reverse-proxy block (imported by central Caddy)
config/production.yaml Loco production config (no secrets)
.env.production.example template for secrets — copy to .env.production
Makefile make up / down / logs / restart

Prerequisites

  • The server already runs the shared Caddy stack (docker-compose.caddy.yml).
  • Docker + docker-compose are installed (they already are — Caddy uses them).
  • You can edit DNS for tenisrajec.sk.

One-time setup

1. Point DNS at the server

Create DNS A records so both names resolve to the server's public IP:

tenisrajec.sk        A    <server-ip>
www.tenisrajec.sk    A    <server-ip>

Do this first — Caddy needs the domain to resolve to obtain the TLS certificate. Propagation can take a while.

2. Clone the repo onto the server

cd ~
git clone <your-git-remote-url> ht_booking
cd ht_booking

(The rest of this guide assumes the repo is at ~/ht_booking.)

3. Create the shared network

The app and Caddy talk over a dedicated Docker network — same pattern as your other projects (biomed-net, farmeris-net, …):

docker network create tenisrajec-net \
  --driver bridge --opt com.docker.network.driver.mtu=1450

4. Create the secrets file

cp .env.production.example .env.production
openssl rand -hex 32          # copy the output into JWT_SECRET
nano .env.production

Fill in:

  • JWT_SECRET — paste the openssl output (required — the app won't start without it).
  • ADMIN_EMAIL / ADMIN_PASSWORD — the single admin login, seeded on first boot.

.env.production is gitignored — it stays only on the server.

5. Hook the site into the central Caddy

Caddy must (a) import this site's Caddyfile and (b) join tenisrajec-net.

a. Add one line to the central ~/Caddyfile:

import /etc/caddy/Caddyfile_tenisrajec

b. In ~/docker-compose.caddy.yml, under the caddy service add the Caddyfile mount to volumes:

      - ./ht_booking/Caddyfile:/etc/caddy/Caddyfile_tenisrajec

… add the network to the caddy service's networks: list …

    networks:
      - vonavucke-net
      - biomed-net
      - gitea-net
      - mqtt-net
      - farmeris-net
      - tenisrajec-net          # <-- add

… and declare it in the top-level networks: block:

  tenisrajec-net:
    external: true
    driver: bridge
    driver_opts:
      com.docker.network.driver.mtu: 1450

c. Recreate Caddy so it picks up the new mount and network:

cd ~
docker-compose -f docker-compose.caddy.yml up -d

6. Build and start the app

cd ~/ht_booking
make up

The first build takes a few minutes (it compiles the Rust release binary). On first boot the app creates the SQLite database, runs all migrations, and seeds the admin account and a default court — automatically.

7. Verify

make logs        # look for "listening on http://0.0.0.0:5150"
make ps          # STATUS should become "healthy"

Then open https://tenisrajec.sk — Caddy will have issued the certificate.


Updating after code changes

cd ~/ht_booking
git pull
make restart

make restart rebuilds the image and recreates the container. The database volume is untouched, so all bookings are preserved. Migrations for any new schema run automatically on boot.

If you changed templates/CSS, the image rebuilds app.css itself — you do not need to run npm run build:css on the server.


Backups

The whole database is one SQLite file inside the ht_booking_data volume. Copy it out at any time:

docker cp ht-booking:/usr/app/data/production.sqlite ./backup-$(date +%F).sqlite

Restore by stopping the app, copying a file back, and starting it:

make down
docker cp ./backup-2026-05-16.sqlite ht-booking:/usr/app/data/production.sqlite
make up

A nightly cron job running that docker cp into a backed-up directory is enough for this site.


Troubleshooting

Symptom Cause / fix
App exits immediately, logs mention JWT_SECRET / config JWT_SECRET is empty in .env.production. Set it, make restart.
502 Bad Gateway from Caddy App not up yet, or Caddy didn't join tenisrajec-net. Check make ps and step 5b.
Caddy can't get a certificate DNS not pointing at the server yet, or ports 80/443 blocked.
network tenisrajec-net not found Run step 3 before make up / recreating Caddy.
Need a shell in the container docker exec -it ht-booking bash

The app listens on 5150 inside its container only — it is intentionally not published to the host. All traffic goes through Caddy.