From 13fca11c8112176f63589f3499d2eb2662e764fc Mon Sep 17 00:00:00 2001 From: renee-png Date: Sun, 26 Jul 2026 09:15:40 -0400 Subject: [PATCH] Fix deploy config to match the actual VPS (Caddy, not Traefik) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The server fronts everything with Caddy (container root-caddy-1), has no Dockge and no Traefik, and keeps compose stacks in /docker — not /opt/stacks. Every traefik.* label in this compose file was inert, so the container would build and run while never being routed. Join the external `web` network Caddy is on so it can reach the container by name (info-share-spot:3000) and publish no host port. Routing now lives in /root/Caddyfile on the server. Rewrite DEPLOY.md against the real topology, including the Caddyfile validate-before-reload step — a bad Caddyfile takes down every site on the box, and Caddy serves a stale in-memory config until something reloads it, which hides the breakage until the next restart. Co-Authored-By: Claude Opus 5 --- DEPLOY.md | 124 +++++++++++++++++++++++++-------------------- docker-compose.yml | 27 +++++----- 2 files changed, 83 insertions(+), 68 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index fefe54a..bf46f05 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,80 +1,92 @@ -# Deploying to a Hostinger VPS (Docker + Dockge + Traefik) +# Deploying to the avriahost VPS (Docker + Caddy) This app is a TanStack Start (SSR) app. The Docker build produces a self-contained Node server (`.output/server/index.mjs`) via the Nitro `node-server` preset and runs -it in a container. Traefik sits in front and gives it automatic HTTPS. +it in a container on port 3000. **Caddy** sits in front and gives it automatic HTTPS. -## 0. One-time: install the catalog apps +> Earlier revisions of this file described a Hostinger-catalog Docker + Dockge + +> Traefik setup. That is **not** what the server runs. There is no Dockge and no +> Traefik on this box, and `traefik.*` compose labels are silently ignored by +> Caddy — the container builds and runs perfectly while never being routed. -From hPanel → VPS → your server → **Catalog**, install: +## The actual server -1. **Docker** (base engine) -2. **Traefik** (reverse proxy + Let's Encrypt HTTPS) -3. **Dockge** (web UI to manage compose stacks + logs) +| | | +|---|---| +| Host | `2.25.155.250` (`srv1720881.hstgr.cloud`), hostname `avriahost`, Ubuntu 24.04 | +| Reverse proxy | Caddy, container `root-caddy-1`, owns :80/:443, automatic Let's Encrypt | +| Caddy config | `/root/Caddyfile` (compose project dir `/root`) | +| Compose stacks | `/docker/` — **not** `/opt/stacks` | +| This stack | `/docker/info-share-spot` | +| Public URL | https://info-share-spot.srv1720881.hstgr.cloud | +| Git host | self-hosted Gitea at `http://2.25.155.250:32774` (SSH on port 44139) | -## 1. Point your domain at the VPS +Caddy shares the external `web` Docker network with this app, so it reaches the +container **by name** — `info-share-spot:3000`. The app therefore publishes no +host port at all. -In your DNS (Hostinger → Domains → DNS), add an **A record** for the subdomain you -want (e.g. `app.yourdomain.com`) pointing at the VPS's public IP. Wait for it to -resolve before step 4 (Let's Encrypt needs it). +## Routing -## 2. Find your Traefik values +The route lives in `/root/Caddyfile`: -The compose file has 3 placeholders to match to your Traefik install. On the VPS: - -```bash -# Traefik's docker network name (what to put for the `traefik` network): -docker network ls | grep -i traefik - -# Traefik's entrypoint + certresolver names (look in its config/labels): -docker inspect traefik | grep -iE "entrypoints|certresolver|acme" +```caddyfile +info-share-spot.srv1720881.hstgr.cloud { + reverse_proxy info-share-spot:3000 +} ``` -Typical values are network `traefik`, entrypoint `websecure`, resolver `letsencrypt`, -but **use whatever your install shows.** Edit `docker-compose.yml` accordingly and set -your real domain in the `Host(...)` rule. - -## 3. Get the code onto the VPS as a Dockge stack - -Dockge watches `/opt/stacks`. Clone the repo into a stack folder: +Always validate before reloading — a bad Caddyfile takes down *every* site on the +box, and Caddy keeps serving a stale in-memory config until something reloads it, +which hides the breakage until the next restart: ```bash -cd /opt/stacks -git clone https://github.com/renee-png/info-share-spot.git +docker exec root-caddy-1 caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile +docker exec -w /etc/caddy root-caddy-1 caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile ``` -The committed `.env` already holds the (public-safe) `SUPABASE_URL` and -`SUPABASE_PUBLISHABLE_KEY` that compose passes to the container at runtime. - -## 4. Deploy in Dockge - -1. Open Dockge → the `info-share-spot` stack appears automatically. -2. Confirm the 3 edited Traefik labels + domain look right. -3. Click **Deploy** (this runs `docker compose up -d --build`). - -First build takes a few minutes (installs deps + builds). When it's up, visit -`https://app.yourdomain.com` — Traefik will have issued the TLS cert. - -## 5. Create your admin account - -The database (Supabase EDU project) is already migrated and empty, so the **first** -account you create at `/auth → Create account` becomes the **admin**. - -## Updating later +## Deploying an update ```bash -cd /opt/stacks/info-share-spot +cd /docker/info-share-spot git pull +docker compose up -d --build ``` -Then in Dockge hit **Deploy** again (rebuilds the image and restarts). That's your -push-to-server loop: `git push` locally → `git pull` + Deploy on the VPS. +First build takes a few minutes (`bun install` + Vite/Nitro SSR build on 2 cores). + +**`git pull` needs credentials**: the Gitea repo is private, so the VPS needs its +own read-only deploy key. The public key is at `/root/.ssh/gitea_deploy.pub`; add +it under the repo's Settings → Deploy Keys (read-only), then point the remote at +SSH: + +```bash +git remote set-url origin ssh://git@2.25.155.250:44139/admin/info-share-spot.git +``` + +Until that key is installed, push code up from a workstation instead: + +```bash +rsync -az --exclude .env.secret /path/to/info-share-spot/ root@2.25.155.250:/docker/info-share-spot/ +ssh root@2.25.155.250 'chown -R root:root /docker/info-share-spot' +``` + +## Environment + +- The committed `.env` holds only the **public-safe** `SUPABASE_URL` and + `SUPABASE_PUBLISHABLE_KEY` (the publishable key is designed for browsers). + Compose substitutes them from that file at build and run time. +- Real secrets go in `.env.secret` next to the compose file — gitignored, loaded + by compose if present, never committed. Add `SUPABASE_SERVICE_ROLE_KEY` there + if you later use the server-side admin client. +- Supabase project is `qgmcpounpkgsjlwosjdi`. Note this is a **different** project + from the ACMACC one used by the avria.cloud app — don't cross the wires. ## Notes -- **Google sign-in** still needs the Google provider enabled in the Supabase EDU - dashboard (Auth → Providers) and your production URL added under Auth → URL - Configuration. Email/password works without any of that. -- **Container port** is 3000 (Traefik routes to it; you don't expose it publicly). -- **Service-role key**: not required. If you later use the server-side admin client, - add `SUPABASE_SERVICE_ROLE_KEY` via Dockge's env editor — never commit it. +- **Google sign-in** needs the Google provider enabled in the Supabase dashboard + (Auth → Providers) and the production URL added under Auth → URL Configuration. + Email/password works without any of that. +- The **first** account created at `/auth` becomes the admin. This has already + happened on this project. +- `edu.avriahost.com` on this server returns 502 — it proxies to + `host.docker.internal:8080` and nothing listens there. Unrelated to this app. diff --git a/docker-compose.yml b/docker-compose.yml index 4feeab6..bf047f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,13 @@ -# Deploy stack for the Hostinger VPS (Docker + Dockge + Traefik). -# Lives in Dockge's stacks dir (/docker/info-share-spot) so Dockge manages it. +# Deploy stack for the avriahost VPS (Docker + Caddy). +# Lives in /docker/info-share-spot. # -# Traefik on this VPS runs in host-network mode with the Docker provider, so the -# app just needs traefik.enable + a router; no shared "traefik" network is needed. -# It's served at the VPS wildcard hostname with automatic Let's Encrypt HTTPS. +# This VPS fronts everything with Caddy (container `root-caddy-1`), NOT Traefik. +# Caddy holds :80/:443, terminates TLS with automatic Let's Encrypt, and routes +# by hostname from /root/Caddyfile. It shares the external `web` network with +# this app, so it reaches us as `info-share-spot:3000` — no published host port. +# +# Route lives in /root/Caddyfile: +# info-share-spot.srv1720881.hstgr.cloud { reverse_proxy info-share-spot:3000 } services: app: @@ -22,10 +26,9 @@ services: SUPABASE_PUBLISHABLE_KEY: ${SUPABASE_PUBLISHABLE_KEY} HOST: 0.0.0.0 PORT: 3000 - labels: - - traefik.enable=true - - traefik.http.routers.infoshare.rule=Host(`info-share-spot.srv1720881.hstgr.cloud`) - - traefik.http.routers.infoshare.entrypoints=websecure - - traefik.http.routers.infoshare.tls=true - - traefik.http.routers.infoshare.tls.certresolver=letsencrypt - - traefik.http.services.infoshare.loadbalancer.server.port=3000 + networks: + - web + +networks: + web: + external: true