Add Docker deploy config for VPS (node-server + Traefik)
- Dockerfile: bun build with Nitro node-server preset -> standalone Node runner - docker-compose.yml: Traefik labels for automatic HTTPS, runtime env from .env - .dockerignore + DEPLOY.md (Hostinger VPS: Docker + Dockge + Traefik steps) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
.git
|
||||||
|
node_modules
|
||||||
|
.output
|
||||||
|
.nitro
|
||||||
|
.tanstack
|
||||||
|
.wrangler
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.log
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
@@ -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.
|
||||||
+30
@@ -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"]
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user