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

Production Checklist

  • NUXT_PUBLIC_API_BASE_URL points to the production backend
  • Firebase config variables are set (if using social login)
  • Umami analytics is configured (optional)
  • HTTPS is configured on the domain
  • CSP headers allow the production API domain
  • CORS_ALLOW_ORIGIN on the backend includes the frontend domain
  • Stripe success/cancel URLs point to the production frontend