diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..91c2ffe --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +node_modules +.output +.nitro +.tanstack +.wrangler +dist +dist-ssr +*.log +Dockerfile +.dockerignore diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..fefe54a --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,80 @@ +# Deploying to a Hostinger VPS (Docker + Dockge + Traefik) + +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. + +## 0. One-time: install the catalog apps + +From hPanel → VPS → your server → **Catalog**, install: + +1. **Docker** (base engine) +2. **Traefik** (reverse proxy + Let's Encrypt HTTPS) +3. **Dockge** (web UI to manage compose stacks + logs) + +## 1. Point your domain at the VPS + +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). + +## 2. Find your Traefik values + +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" +``` + +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: + +```bash +cd /opt/stacks +git clone https://github.com/renee-png/info-share-spot.git +``` + +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 + +```bash +cd /opt/stacks/info-share-spot +git pull +``` + +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. + +## 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. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5c6acc2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +# syntax=docker/dockerfile:1 + +# ---- Builder: install deps + build a standalone Node server (.output/) ---- +FROM oven/bun:1 AS builder +WORKDIR /app + +# Install dependencies against the committed lockfile +COPY package.json bun.lock ./ +RUN bun install --frozen-lockfile + +# Copy the rest of the source. .env is copied too so Vite bakes the +# VITE_SUPABASE_* values into the client bundle at build time (public-safe). +COPY . . + +# Build with the Nitro node-server preset -> self-contained .output/ +ENV NITRO_PRESET=node-server +RUN bun run build + +# ---- Runner: run the built server on Node (no install needed, .output is standalone) ---- +FROM node:22-slim AS runner +WORKDIR /app +ENV NODE_ENV=production +# Nitro node-server reads HOST/PORT; 0.0.0.0:3000 is the default we expose. +ENV HOST=0.0.0.0 +ENV PORT=3000 + +COPY --from=builder /app/.output ./.output + +EXPOSE 3000 +CMD ["node", ".output/server/index.mjs"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2f2a1bb --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,36 @@ +# Deploy stack for Hostinger VPS (Docker + Dockge + Traefik). +# Dockge picks this up when the folder lives under /opt/stacks/. +# +# Before deploying, edit the 3 places marked <<< CHANGE >>> to match your +# Traefik install and your domain. See DEPLOY.md for how to find the right values. + +services: + app: + build: . + image: info-share-spot:latest + container_name: info-share-spot + restart: unless-stopped + environment: + # SSR runtime vars (public-safe). Compose auto-substitutes these from the + # .env file sitting next to this compose file — no need to retype them. + SUPABASE_URL: ${SUPABASE_URL} + SUPABASE_PUBLISHABLE_KEY: ${SUPABASE_PUBLISHABLE_KEY} + # Only needed if you ever use the server-side admin (service-role) client. + # Keep this OUT of git — set it in Dockge's env editor instead. + # SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY} + HOST: 0.0.0.0 + PORT: 3000 + networks: + - traefik # <<< CHANGE >>> to your Traefik network name + labels: + - traefik.enable=true + - traefik.docker.network=traefik # <<< CHANGE >>> same network name as above + - traefik.http.routers.infoshare.rule=Host(`app.example.com`) # <<< CHANGE >>> your domain + - traefik.http.routers.infoshare.entrypoints=websecure + - traefik.http.routers.infoshare.tls=true + - traefik.http.routers.infoshare.tls.certresolver=letsencrypt # <<< CHANGE >>> your resolver name + - traefik.http.services.infoshare.loadbalancer.server.port=3000 + +networks: + traefik: + external: true # Traefik already created this network