Docker & Compose Deployment
Deploy JChat using the pre-bundled docker-compose.yml or build a custom container image from source.
Overview
Every JChat release package comes pre-bundled with a production-ready docker-compose.yml, Dockerfile, and Caddyfile. Customers do not need to construct a Docker Compose stack from scratch—simply extract the release archive and launch.
Choosing Your Deployment Mode
Choose the approach that fits your operational requirements:
1. Standard Deployment (Using Personalized or Bundled docker-compose.yml)
Recommended for standard production use. You can download a personalized docker-compose.yml directly from your JChat Store Dashboard (under Purchases > Docker Setup (.yml)) with your license key pre-configured, or use the bundled file.
Uses the official pre-built image (ghcr.io/jchatcloud/jchat:latest). No local building or compilation needed. Runs JChat, PostgreSQL 18, Redis, and Caddy automatically.
docker compose up -d2. Custom Code Changes (Building Your Own Image)
If you customize JChat's source code, components, or API features, build your custom container directly using the included Dockerfile with the --build flag. The bundled docker-compose.yml automatically handles building from source.
docker compose up --build -dPre-Bundled docker-compose.yml
Below is the exact production Compose stack included in your release package:
services:
jchat:
image: ghcr.io/jchatcloud/jchat:latest
build:
context: .
dockerfile: Dockerfile
container_name: jchat-app
restart: unless-stopped
environment:
NODE_ENV: production
JCHAT_PORT: "3000"
JCHAT_INTERNAL_DB_HOST: db
JCHAT_INTERNAL_REDIS_HOST: redis
JCHAT_ENV_PATH: /app/config/.env
volumes:
- ./config:/app/config
- ./data:/app/data
- ./addons:/app/addons
- uploads:/app/uploads
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- jchat-network
db:
image: postgres:18-alpine
container_name: jchat-db
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER:-jchat}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-jchat_secret}
POSTGRES_DB: ${POSTGRES_DB:-jchat}
ports:
- "5434:5432"
volumes:
- postgres_data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-jchat}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- jchat-network
redis:
image: redis:8.0.6-alpine3.21
container_name: jchat-redis
restart: always
ports:
- "6380:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- jchat-network
caddy:
image: caddy:alpine
container_name: caddy
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- jchat
networks:
- jchat-network
minio:
image: minio/minio:latest
profiles: ["minio"]
container_name: jchat-minio
restart: unless-stopped
command: server /data --console-address ":9001"
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
networks:
- jchat-network
minio-init:
image: minio/mc:latest
profiles: ["minio"]
container_name: jchat-minio-init
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 $${MINIO_ROOT_USER:-minioadmin} $${MINIO_ROOT_PASSWORD:-minioadmin};
mc mb --ignore-existing local/$${JCHAT_MINIO_BUCKET_NAME:-jchat};
mc anonymous set public local/$${JCHAT_MINIO_BUCKET_NAME:-jchat};
echo 'MinIO bucket ready.';
"
networks:
- jchat-network
networks:
jchat-network:
driver: bridge
volumes:
postgres_data:
redis_data:
uploads:
minio_data:
caddy_data:
caddy_config:Starting and Managing the Stack
Essential operational commands for your Docker deployment:
# Start using the official pre-built image:
docker compose up -d
# View live application logs:
docker compose logs -f jchat# Build and launch with your custom source modifications:
docker compose up --build -d
# Check build & application status:
docker compose ps# Stop the stack safely:
docker compose down
# Restart containers after config changes:
docker compose restart jchatUsing Nginx Instead of Caddy
While Caddy is bundled by default for zero-configuration automatic SSL, you can easily substitute Nginx if required by your infrastructure standards:
1. Replace Caddy in docker-compose.yml
In your docker-compose.yml, replace the caddy service with an official nginx:alpine container. Notice the ./nginx.conf mount: this reads the configuration directly from your root project folder:
nginx:
image: nginx:alpine
container_name: jchat-nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
depends_on:
- jchat
networks:
- jchat-network2. Create nginx.conf in the Root Directory
Create an nginx.conf file in the root deployment directory directly alongside docker-compose.yml (e.g., at /path/to/jchat/nginx.conf). Ensure WebSocket upgrade headers, client IP forwarding, and file upload limits (50MB) are included:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name chat.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name chat.example.com;
ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 50M;
location / {
proxy_pass http://jchat:3000;
proxy_http_version 1.1;
# Real-time WebSocket Upgrades
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Standard Forwarding Headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Keep persistent WebSocket connections alive
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}3. Launch Containers with Nginx
Start the stack with your new Nginx configuration active:
docker compose up -d