Deployment

Docker setup and production deployment for the frontend

Deployment

Docker Setup

Development (docker-compose.yml)

services:
  app:
    build:
      context: .
      target: dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - node_modules:/app/node_modules
    environment:
      - NODE_ENV=development
      - NUXT_PUBLIC_API_BASE_URL=http://localhost
    command: npm run dev

volumes:
  node_modules:

Key points:

  • Source code is mounted for hot-reload
  • node_modules uses a named volume (not mounted from host)
  • Nuxt dev server binds to 0.0.0.0 for Docker access

Production (Dockerfile)

The multi-stage Dockerfile produces an optimized production image:

# Dev stage
FROM node:20-alpine AS dev
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000

# Production stage
FROM node:20-alpine AS prod
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]

Dokploy Deployment

Setup

  1. Create a new application in Dokploy
  2. Set source to Docker (from GitHub Container Registry)
  3. Configure the image: ghcr.io/{owner}/{repo}:main
  4. Set up a domain with HTTPS

Environment Variables

Set these in Dokploy application settings:

NUXT_PUBLIC_API_BASE_URL=https://api.yourdomain.com
NUXT_PUBLIC_FIREBASE_API_KEY=your-firebase-api-key
NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NUXT_PUBLIC_FIREBASE_PROJECT_ID=your-firebase-project-id
NUXT_PUBLIC_UMAMI_HOST=https://analytics.yourdomain.com
NUXT_PUBLIC_UMAMI_ID=your-site-id

Deployment Webhook

  1. In Dokploy, copy the webhook URL from your application settings
  2. Add it as a GitHub secret: DOKPLOY_WEBHOOK_URL
  3. Pushes to main will automatically build and deploy

Deployment Architecture

GitHub (push to main)
    │
    ├── Backend CI/CD
    │   └── Test → Build → Push to GHCR → Dokploy webhook → Deploy
    │
    └── Frontend CI/CD
        └── Test → Build → Push to GHCR → Dokploy webhook → Deploy

Dokploy Server
    ├── Backend (FrankenPHP) ← https://api.yourdomain.com
    ├── Frontend (Node.js)   ← https://yourdomain.com
    ├── PostgreSQL
    └── Redis

Both services are deployed as Docker containers managed by Dokploy, with automatic HTTPS via Let's Encrypt.

Installing Dokploy

Dokploy is a self-hosted deployment platform. Install it on your server:

curl -sSL https://dokploy.com/install.sh | sh

Access the Dokploy dashboard at https://your-server-ip:3000.

DNS Configuration

RecordDomainTarget
Ayourdomain.comYour server IP
Aapi.yourdomain.comYour server IP

Dokploy handles HTTPS certificates automatically via Let's Encrypt.

Production Checklist

Verify everything before going live.

Frontend

  • NUXT_PUBLIC_API_BASE_URL points to the production backend
  • Analytics configured (Umami host + ID, if using)
  • CSP headers allow the production API domain

Firebase

  • NUXT_PUBLIC_FIREBASE_API_KEY is set on the frontend
  • NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN is set
  • NUXT_PUBLIC_FIREBASE_PROJECT_ID matches the backend

Cross-Project

  • CORS_ALLOW_ORIGIN on backend matches the frontend domain
  • Stripe success/cancel URLs point to the production frontend
  • All redirect URLs in the backend point to valid frontend routes

Infrastructure

  • HTTPS is configured on the frontend domain
  • DNS records point to the server
  • GitHub secrets are set for CI/CD (DOKPLOY_WEBHOOK_URL)
  • CI/CD pipeline passes (test → build → deploy)

Smoke Test

After deployment, verify these flows work end-to-end:

  1. Landing page loads at https://yourdomain.com
  2. Register a new user
  3. Check welcome email arrives (via Brevo)
  4. Login with the new user
  5. Complete a Stripe test checkout
  6. Verify subscription appears on profile page
  7. Test forgot password flow
  8. Test social login (if configured)
  9. Access admin panel at https://api.yourdomain.com/admin