Docker provides a consistent environment for running Jack on any server. This is the recommended approach for self-hosted production deployments.
Prerequisites
- Docker Engine 20.10+ or Docker Desktop
- Docker Compose v2 (optional but recommended)
- At least 1GB RAM
- 500MB disk space (plus storage for database)
Quick Start
Pull and run the official image:
docker run -d \
--name jack-butler \
-p 3000:3000 \
-v jack-data:/app/data \
-e JWT_SECRET="your-secret-min-32-chars" \
-e ENCRYPTION_KEY="your-encryption-key-32-chars" \
ghcr.io/jackthebutler/jackthebutler:latest
Access the dashboard at http://localhost:3000
Docker Compose
For easier management, create a docker-compose.yml file:
version: '3.8'
services:
jack:
image: ghcr.io/jackthebutler/jackthebutler:latest
container_name: jack-butler
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- jack-data:/app/data
environment:
- NODE_ENV=production
- JWT_SECRET=${JWT_SECRET}
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
- DATABASE_PATH=/app/data/jack.db
volumes:
jack-data: Create a .env file with your secrets:
JWT_SECRET=your-secret-key-minimum-32-characters-long
ENCRYPTION_KEY=your-encryption-key-minimum-32-chars Then start the service:
docker compose up -d Generating Secrets
Generate secure random secrets:
# Using openssl
openssl rand -base64 32
# Or using /dev/urandom
head -c 32 /dev/urandom | base64 Security: Never commit your .env file to version control. Add it to .gitignore.
Reverse Proxy with Nginx
For production, run Jack behind a reverse proxy with SSL. Example Nginx configuration:
server {
listen 80;
server_name jack.yourhotel.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name jack.yourhotel.com;
ssl_certificate /etc/letsencrypt/live/jack.yourhotel.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jack.yourhotel.com/privkey.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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
} The WebSocket upgrade headers are important for real-time updates in the dashboard.
Updating Jack
To update to the latest version:
# Pull the latest image
docker compose pull
# Restart with the new image
docker compose up -d Your data is preserved in the named volume.
Backup & Restore
Backup
Copy the SQLite database from the volume:
# Stop the container first for consistency
docker compose stop
# Copy the database
docker cp jack-butler:/app/data/jack.db ./backup-$(date +%Y%m%d).db
# Restart
docker compose start Or backup without stopping (less consistent but no downtime):
docker exec jack-butler sqlite3 /app/data/jack.db ".backup /app/data/backup.db"
docker cp jack-butler:/app/data/backup.db ./backup-$(date +%Y%m%d).db Restore
# Stop the container
docker compose stop
# Copy backup into container
docker cp ./backup.db jack-butler:/app/data/jack.db
# Start the container
docker compose start Viewing Logs
# View recent logs
docker compose logs jack
# Follow logs in real-time
docker compose logs -f jack
# View last 100 lines
docker compose logs --tail 100 jack Troubleshooting
Container won't start
Check logs for errors:
docker compose logs jack Permission denied on volume
The container runs as a non-root user. Ensure volume permissions:
docker exec jack-butler chown -R node:node /app/data Database locked errors
SQLite can have issues with concurrent writes. Ensure only one instance of Jack is running and that the volume is not mounted by multiple containers.
Next Steps
- Complete the Setup Wizard
- Configure AI providers
- Set up WhatsApp or other channels