Docker Deployment
Hub Digital uses a multi-stage Docker build optimized for production.
Dockerfile Stages
| Stage | Base Image | Purpose |
|---|---|---|
base | node:22-alpine | Installs Corepack and pnpm |
builder | extends base | Installs deps and builds the Nuxt app |
runner | extends base | Minimal production image with .output/ |
Building the Image
# Using Make
make dist-prod
# Using Docker directly
docker build -f apps/web/Dockerfile \
--build-arg NUXT_PUBLIC_SITE_URL=https://hub.inov-norte.ipp.pt \
--build-arg DIRECTUS_URL=https://api.hub.inov-norte.ipp.pt \
-t hub-digital-ui .
Important:
NUXT_PUBLIC_*variables are inlined at build time and must be provided as build args.
Running the Container
docker run -p 3000:3000 hub-digital-ui
The container runs as non-root user (nuxt), exposes port 3000, and starts with node server/index.mjs.
CI/CD Pipeline
GitHub Actions
On every push to main, the workflow in .github/workflows/publish.yml:
- Checks out the repository
- Logs in to GitHub Container Registry (
ghcr.io) - Builds the Docker image with production build args
- Pushes to
ghcr.io/inov-norte/hub-digital-ui:main
Required GitHub Variables
NUXT_PUBLIC_SITE_URL, DIRECTUS_URL, NUXT_PUBLIC_AVATAR_UPLOAD_FOLDER, NUXT_PUBLIC_RESOURCE_UPLOAD_FOLDER, NUXT_PUBLIC_TOOL_UPLOAD_FOLDER, NUXT_PUBLIC_INVITE_ROLE, and other env vars.
Production Optimization
- CSS minification via LightningCSS
- JS minification via Terser
- Brotli + Gzip compression
- Hidden sourcemaps for debugging
- Non-root container user for security
- Memory:
NODE_OPTIONS="--max-old-space-size=8192"during build
Coming Soon Mode
NUXT_PUBLIC_COMING_SOON_ENABLED=true
NUXT_PUBLIC_COMING_SOON_LAUNCH_AT=2026-06-10T00:00:00+01:00
COMING_SOON_BYPASS_CODE=your-secret-code
Users bypass with ?code=your-secret-code in the URL.