# Deploy on Lightsail Build the app image on your machine and copy it over SSH. Caddy on the instance terminates HTTPS and proxies to the app container. The app is not published on port 3080. `.env` is copied from this machine on each deploy. The SQLite file stays in `/opt/diverter-device-emulator/data`, and the Let's Encrypt certificate stays in a Docker volume. ## One-time setup 1. Create an Ubuntu 24.04 Lightsail instance and attach a static IP. 2. Pick a hostname and set a DNS A record to that IP. Put the hostname in `.env` as `PORTAL_HOST`. Set `PORTAL_USER` and `PORTAL_PASSWORD`. Leave `ALLOWED_IPS` unset. 3. In the Lightsail IPv4 firewall, allow SSH (22) from your IP, and TCP **80** and **443** from any IPv4 address. 4. Install Docker and Compose on the instance: ```bash sudo apt-get update && sudo apt-get install -y docker.io docker-compose-v2 && sudo systemctl enable --now docker ``` ## Deploy From this repo, with Docker Desktop running: ```bash ./deploy/ship.sh ``` That uses the `diverter-emu` host in `~/.ssh/config`, including its user and key. The script builds the app image for the server's CPU, copies it with the Caddy image, and runs both. The site is `https://`. Caddy requests the certificate on first start, which needs the DNS record and ports 80 and 443 already open. Responses send `Cache-Control` / `Cloudflare-CDN-Cache-Control: no-store` so Cloudflare does not cache HTML, CSS, or JS. CSS and JS URLs are also versioned, so a deploy does not keep serving a stale edge copy. After this change is live, purge Cloudflare once (Caching → Purge Everything) so the old `/styles.css` and `/app.js` drop out. Logs: ```bash ssh diverter-emu sudo bash -c 'cd /opt/diverter-device-emulator && docker compose logs -f' ```