Deployment

Production deployment guide for Cyborg7.

Docker (Recommended)

The Dockerfile produces a standalone Next.js container:

# Build
docker build -t cyborg7 \
--build-arg DATABASE_URL=postgresql://... \
--build-arg BETTER_AUTH_URL=https://your-domain.com \
--build-arg NEXT_PUBLIC_BETTER_AUTH_URL=https://your-domain.com \
--build-arg NEXT_PUBLIC_APP_URL=https://your-domain.com \
--build-arg NEXT_PUBLIC_DEPLOYMENT_MODE=self-hosted \
.
# Run
docker run -d \
--name cyborg7 \
-p 3000:3000 \
-e DATABASE_URL=postgresql://... \
-e BETTER_AUTH_SECRET=... \
-e RESEND_API_KEY=... \
-e REDIS_URL=redis://redis:6379 \
-e MQTT_BROKER_URL=mqtt://broker:1883 \
-e MQTT_ROLE=primary \
cyborg7

Docker Compose (Full Stack)

version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/cyborg7
- REDIS_URL=redis://redis:6379
- MQTT_BROKER_URL=mqtt://mqtt:1883
- MQTT_ROLE=primary
# ... other env vars
depends_on:
- db
- redis
- mqtt
db:
image: postgres:15-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: cyborg7
POSTGRES_PASSWORD: password
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
mqtt:
image: emqx/emqx:5-alpine
ports:
- "1883:1883"
volumes:
pgdata:
redisdata:

Build Arguments vs Runtime Variables

Next.js bakes NEXT_PUBLIC_* variables into the client bundle at build time. All other variables are read at runtime.

TypeWhenExamples
Build argsDocker --build-argNEXT_PUBLIC_APP_URL, NEXT_PUBLIC_DEPLOYMENT_MODE
Runtime envDocker -eDATABASE_URL, STRIPE_SECRET_KEY, RESEND_API_KEY

Reverse Proxy (nginx)

server {
listen 443 ssl;
server_name your-domain.com;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off; # required for SSE
proxy_read_timeout 86400; # keep SSE alive
}
}

Database Migrations

Run migrations before starting the app:

pnpm drizzle-kit migrate

Health Check

The app listens on port 3000. Check startup logs for:

Ready on http://0.0.0.0:3000
[Redis] Connected
[MQTT] Connected to broker