This application uses GitHub Packages for Docker images and includes Docker Compose configuration with two services:
- API Service - Main Node.js API (from
ghcr.io/osiastedian/syshub-api) - Cron Service - Scheduled tasks using the same image with different command
Key Benefits:
- ✅ No local build needed - uses pre-built GitHub Package
- ✅ Both services use the same image
- ✅ Cron service just overrides the command to run cron
- ✅ Automatic updates when new images are pushed
# Ensure Docker and Docker Compose are installed
docker --version
docker-compose --version
# Login to GitHub Container Registry (if image is private)
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin# Copy environment template
cp .env-example .env
# Edit .env with your configuration
nano .envRequired variables:
- Firebase configuration
- Collection names
- Encryption keys
- RPC credentials
# Pull latest image from GitHub Packages
docker-compose pull
# Start services
docker-compose up -d
# View logs
docker-compose logs -fNo build step needed! Images are pre-built and published to GitHub Packages.
# Check service status
docker-compose ps
# Should show:
# Name Command State Ports
# syshub-api_api_1 npm start Up 0.0.0.0:3000->3000/tcp
# syshub-api_cron_1 /app/start... Up
# Test API
curl http://localhost:3000/health
# Check cron logs
docker-compose logs cronPort: 3000 (configurable via PORT_HTTP)
Health check:
curl http://localhost:3000/healthView logs:
docker-compose logs -f apiPurpose: Runs scheduled tasks automatically
Configured tasks:
- Token cleanup: Daily at 2 AM UTC
View logs:
docker-compose logs -f cron
# Or check the log file
docker-compose exec cron cat /app/logs/token-cleanup.logVerify cron jobs:
docker-compose exec cron cat /etc/crontabs/rootEdit crontab file to change schedule:
# Format: minute hour day month weekday command
# Daily at 2 AM UTC
0 2 * * * cd /app && /usr/local/bin/node scripts/cleanup-revoked-tokens.js >> /app/logs/token-cleanup.log 2>&1
# Twice daily (2 AM and 2 PM)
0 2,14 * * * cd /app && /usr/local/bin/node scripts/cleanup-revoked-tokens.js >> /app/logs/token-cleanup.log 2>&1
# Every hour
0 * * * * cd /app && /usr/local/bin/node scripts/cleanup-revoked-tokens.js >> /app/logs/token-cleanup.log 2>&1Apply changes:
# Rebuild cron service
docker-compose up -d --build cronVia .env file (recommended):
# .env
NODE_ENV=production
PORT_HTTP=3000
FIREBASE_PROJECT_ID=your-project
# ... etcVia docker-compose override:
# docker-compose.override.yml
version: '3.8'
services:
api:
environment:
- DEBUG=true
- LOG_LEVEL=debug# Start all services
docker-compose up -d
# Start specific service
docker-compose up -d api
docker-compose up -d cron
# Stop all services
docker-compose down
# Stop but keep volumes
docker-compose stop
# Restart a service
docker-compose restart api# All services
docker-compose logs -f
# Specific service
docker-compose logs -f api
docker-compose logs -f cron
# Last 100 lines
docker-compose logs --tail=100 api
# Since specific time
docker-compose logs --since 2025-12-15T10:00:00# Run token cleanup manually
docker-compose exec cron node /app/scripts/cleanup-revoked-tokens.js
# Dry run
docker-compose exec -e DRY_RUN=true cron node /app/scripts/cleanup-revoked-tokens.js
# Access API container shell
docker-compose exec api sh
# Access cron container shell
docker-compose exec cron sh# Pull latest code
git pull
# Rebuild images
docker-compose build
# Restart with new images
docker-compose up -d
# Or combine (rebuild and restart)
docker-compose up -d --build- Set
NODE_ENV=productionin.env - Use strong encryption keys
- Never commit
.envor Firebase credentials - Configure Cloudflare proxy
- Set up proper Firebase security rules
- Enable Docker logging driver
- Configure resource limits
Add to docker-compose.yml:
services:
api:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
restart: always
cron:
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
restart: alwaysJSON logging driver:
services:
api:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"Syslog (for centralized logging):
services:
api:
logging:
driver: "syslog"
options:
syslog-address: "tcp://192.168.0.1:514"
tag: "syshub-api"Add to docker-compose.yml:
services:
api:
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40sservices:
api:
volumes:
- ./logs:/app/logs
cron:
volumes:
- ./logs:/app/logsThen create logs directory:
mkdir -p logs
chmod 755 logs# Check container status
docker-compose ps
# Check resource usage
docker stats
# Check specific container
docker stats syshub-api_cron_1# Watch token cleanup logs
tail -f logs/token-cleanup.log
# Check last cleanup run
docker-compose exec cron tail /app/logs/token-cleanup.log
# Check cron daemon logs
docker-compose logs --tail=50 cronSet up monitoring alerts:
-
Container health:
# Check if containers are running docker-compose ps | grep -q "Up" || echo "Alert: Containers down!"
-
Cron execution:
# Check if cleanup ran today grep "$(date +%Y-%m-%d)" logs/token-cleanup.log || echo "Alert: Cleanup hasn't run today"
-
Disk space:
# Check Docker disk usage docker system df
Check cron service logs:
docker-compose logs cronVerify crontab:
docker-compose exec cron cat /etc/crontabs/rootTest script manually:
docker-compose exec cron node /app/scripts/cleanup-revoked-tokens.jsCheck timezone:
docker-compose exec cron date
# Should match your expected timezone (default: UTC)# Fix log permissions
docker-compose exec cron chmod -R 755 /app/logs
# Check script permissions
docker-compose exec cron ls -la /app/scripts/# View crash logs
docker-compose logs --tail=100 api
# Check exit code
docker-compose ps
# Restart with debug
docker-compose up api # Without -d to see output# Check memory usage
docker stats
# Add memory limits (see Production Deployment section)
# Or increase available memory in Docker settings# Backup .env file (store securely!)
cp .env .env.backup
# Backup Docker volumes (if using)
docker run --rm -v syshub-api_data:/data -v $(pwd):/backup alpine tar czf /backup/data-backup.tar.gz /data# Stop services
docker-compose down
# Restore .env
cp .env.backup .env
# Rebuild and start
docker-compose up -d --build
# Verify
docker-compose ps
docker-compose logs -f# docker-compose.override.yml
version: '3.8'
services:
api:
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
command: npm run devdocker-compose up
# Auto-reloads on code changes# Use production .env
NODE_ENV=production
# Build optimized images
docker-compose build --no-cache
# Run in background
docker-compose up -d
# Monitor
docker-compose logs -f# Stop and remove containers, networks
docker-compose down
# Remove volumes too (WARNING: deletes data)
docker-compose down -v
# Remove images
docker-compose down --rmi all# Remove build cache
docker builder prune
# Remove unused images
docker image prune -a
# Remove everything unused
docker system prune -a --volumes- Never commit
.env- Use.env-exampleas template - Use Docker secrets for sensitive data in production
- Set resource limits to prevent resource exhaustion
- Enable health checks for automatic recovery
- Use volume mounts for logs in production
- Monitor container metrics regularly
- Keep images updated with security patches
- Use multi-stage builds to reduce image size
- Run as non-root user when possible
- Enable logging driver for centralized logs
- ✅ Configure environment variables
- ✅ Test locally with
docker-compose up - ✅ Verify cron jobs execute
- ✅ Set up monitoring and alerts
- ✅ Configure resource limits for production
- ✅ Set up automated backups
- ✅ Deploy to production environment