Production Deployment
This guide covers deploying TimeTiles to production using Docker and Docker Compose.
Overview
TimeTiles provides a production-ready Docker deployment with:
- Nginx reverse proxy with SSL/TLS termination
- Next.js application server (standalone build)
- PostgreSQL 17 with PostGIS 3.5+
- Certbot for automatic SSL certificate renewal
Quick Start
Option 1: Docker Compose (Recommended)
# 1. Clone deployment files
git clone --depth 1 --filter=blob:none --sparse https://github.com/jfilter/timetiles.git
cd timetiles
git sparse-checkout set deployment
# 2. Configure environment
cp deployment/.env.production.example deployment/.env.production
nano deployment/.env.production
# Set: DOMAIN_NAME, DB_PASSWORD, PAYLOAD_SECRET, LETSENCRYPT_EMAIL
# 3. Pull and start
timetiles pull
timetiles up
# 4. Initialize SSL (after DNS is configured)
timetiles sslOption 2: All-in-One Container
For demos, small teams, or quick trials:
docker run -d \
-p 80:80 -p 443:443 \
-v timetiles-data:/data \
-e PAYLOAD_SECRET=$(openssl rand -base64 32) \
-e DB_PASSWORD=$(openssl rand -base64 16) \
ghcr.io/jfilter/timetiles:latest-allinoneOption 3: Automated Server Setup (Ubuntu 24.04)
curl -sSL https://raw.githubusercontent.com/jfilter/timetiles/main/deployment/bootstrap/install.sh | sudo bashDeployment Options
| Option | Best For | Scaling | Maintenance |
|---|---|---|---|
| Docker Compose | Production, teams | Horizontal (multiple instances) | Standard Docker ops |
| All-in-One | Demos, small teams, personal | Single server only | Simple, self-contained |
| Bootstrap Script | Fresh Ubuntu servers | Same as Compose | Includes security hardening |
Docker Compose Architecture
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Nginx │────▶│ Next.js │────▶│ PostgreSQL │
│ (SSL/TLS) │ │ App │ │ + PostGIS │
└─────────────┘ └─────────────┘ └─────────────┘All-in-One Architecture
┌─────────────────────────────────────────┐
│ Single Container │
│ ┌───────┐ ┌────────┐ ┌───────────┐ │
│ │ Nginx │──│Next.js │──│ PostgreSQL│ │
│ └───────┘ └────────┘ └───────────┘ │
│ (supervisord manages all) │
└─────────────────────────────────────────┘Prerequisites
See Installation Guide for complete system requirements and prerequisites.
File Structure
After bootstrap or manual setup, files are in /opt/timetiles/:
/opt/timetiles/
├── timetiles # CLI script (symlinked to /usr/local/bin/timetiles)
├── docker-compose.prod.yml # Service orchestration
├── .env.production.example # Environment template
├── .env.production # Your configuration
├── nginx/ # Nginx configuration
│ ├── nginx.conf # Main configuration
│ └── sites-enabled/ # Site-specific configs
└── backups/ # Backup filesConfiguration
Create your environment file:
cp deployment/.env.production.example deployment/.env.production
nano deployment/.env.productionSee Configuration Guide for all environment variables. At minimum, configure:
DOMAIN_NAME- Your production domainDB_PASSWORD- Strong database passwordPAYLOAD_SECRET- Random 32+ character secret (generate with:openssl rand -base64 32)LETSENCRYPT_EMAIL- Email for SSL certificate notifications
SSL/TLS Setup
Let’s Encrypt (Recommended)
Automatic SSL certificates:
# After DNS is configured and services are running
timetiles sslCertificates auto-renew every 12 hours via Certbot.
Custom Certificates
- Place certificates in
deployment/nginx/ssl/:fullchain.pem(certificate + chain)privkey.pem(private key)
- Update nginx config to reference your certificates
- Restart:
docker-compose -f deployment/docker-compose.prod.yml restart nginx
Deployment Commands
Using timetiles CLI
# Service Management
timetiles up # Start all services
timetiles down # Stop all services
timetiles restart # Restart services
timetiles status # Check service health
# Maintenance
timetiles logs # View logs
timetiles update # Pull updates and redeploy
# Note: Database migrations run automatically on container startupDirect Docker Compose
For advanced usage:
# Define alias for convenience
alias dc-prod="docker-compose -f deployment/docker-compose.prod.yml --env-file deployment/.env.production"
# Examples
dc-prod ps # List containers
dc-prod logs web # View web logs
dc-prod exec web sh # Shell into web containerSecurity
Network Security
- Only ports 80 (HTTP) and 443 (HTTPS) are exposed
- Internal services communicate on private Docker network
- PostgreSQL is not exposed externally
Application Security
- Next.js runs as non-root user
- Environment secrets isolated
- HTTPS enforced with security headers
- Rate limiting on API endpoints
Security Checklist
- Strong database password (20+ characters)
- Random Payload secret (32+ characters)
- HTTPS enabled with valid certificate
- Firewall configured (allow only 80, 443, SSH)
- Regular security updates enabled
- Backup strategy in place
Health Checks
Verify deployment:
# Check all services
timetiles status
# Check application health
curl https://your-domain.com/api/health
# Should return: {"status":"ok","timestamp":"..."}Common Issues
Build Fails with Out of Memory
Add swap space:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfileOr build locally and push image to registry.
SSL Certificate Fails
Verify DNS and Let’s Encrypt challenge:
# Check DNS resolves to your server
nslookup your-domain.com
# Test HTTP challenge path
curl http://your-domain.com/.well-known/acme-challenge/testFor more troubleshooting, see Maintenance Guide.
Next Steps
After successful deployment:
- Set up monitoring: See Monitoring Guide
- Configure backups: See Backup Guide
- Performance tuning: See Maintenance Guide
- Review security: See Configuration Guide
Updating Production
With Pre-built Images (Default)
# Edit version in .env.production
# TIMETILES_VERSION=v1.2.0
# Pull new images and restart
timetiles updateWith Local Builds
If using docker-compose.override.yml for local builds:
git pull
timetiles build
timetiles upSee Maintenance Guide for routine operations.