This guide covers different methods for self-hosting the TimelyOne application.
- Docker Compose (Recommended)
- Manual Deployment
- VPS Deployment
- Reverse Proxy Configuration
- Production Checklist
The easiest way to self-host the application is using Docker Compose, which handles both the app and PostgreSQL database.
- Docker and Docker Compose installed
- Domain name (optional, but recommended for HTTPS)
-
Clone the repository
git clone <repository-url> cd timelyone
-
Create environment file
cp .env.example .env
-
Edit
.envand set required variablesnano .env
Key variables to set:
DB_PASSWORD: Strong password for PostgreSQLNEXTAUTH_SECRET: Generate withopenssl rand -base64 32APP_URL: Your domain or IP (e.g.,https://calendar.yourdomain.com)
-
Start the services
docker-compose up -d
-
Check logs
docker-compose logs -f app
-
Access the application
- Open
http://localhost:3000(or your configured APP_URL) - Complete the setup wizard
- Open
# Start services
docker-compose up -d
# Stop services
docker-compose down
# View logs
docker-compose logs -f
# Restart app only
docker-compose restart app
# Update to latest version
git pull
docker-compose build --no-cache
docker-compose up -d
# Backup database
docker exec calendar-db pg_dump -U calendar_user all_in_one_calendar > backup.sql
# Restore database
cat backup.sql | docker exec -i calendar-db psql -U calendar_user all_in_one_calendarFor deploying without Docker on a VPS or local machine.
- Node.js 20+
- PostgreSQL 14+
- PM2 (optional, for process management)
-
Install dependencies
npm install
-
Set up PostgreSQL
# Create database createdb all_in_one_calendar # Create user (optional) psql -c "CREATE USER calendar_user WITH PASSWORD 'your_password';" psql -c "GRANT ALL PRIVILEGES ON DATABASE all_in_one_calendar TO calendar_user;"
-
Configure environment
cp .env.example .env nano .env
-
Run migrations
npx prisma migrate deploy npx prisma generate
-
Build the application
npm run build
-
Start the application
Option A: Direct start
npm start
Option B: With PM2
npm install -g pm2 pm2 start npm --name "calendar" -- start pm2 save pm2 startup
Example deployment on a Ubuntu 22.04 VPS (DigitalOcean, Linode, etc.)
# Update system
sudo apt update && sudo apt upgrade -y
# Install Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Install PostgreSQL
sudo apt install -y postgresql postgresql-contrib
# Install Docker (alternative)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER# Clone repository
cd /opt
sudo git clone <repository-url> calendar
sudo chown -R $USER:$USER calendar
cd calendar
# Set up environment
cp .env.example .env
nano .envdocker-compose up -d# Create update script
cat > /opt/calendar/update.sh << 'EOF'
#!/bin/bash
cd /opt/calendar
git pull
docker-compose build --no-cache
docker-compose up -d
EOF
chmod +x /opt/calendar/update.sh
# Add to cron (weekly updates)
(crontab -l 2>/dev/null; echo "0 3 * * 0 /opt/calendar/update.sh") | crontab -server {
listen 80;
server_name calendar.yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name calendar.yourdomain.com;
# SSL configuration (use certbot for Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/calendar.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/calendar.yourdomain.com/privkey.pem;
# Proxy settings
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_cache_bypass $http_upgrade;
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;
}
}Install SSL with Certbot:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d calendar.yourdomain.comCreate /etc/caddy/Caddyfile:
calendar.yourdomain.com {
reverse_proxy localhost:3000
}Start Caddy:
sudo caddy run --config /etc/caddy/CaddyfileAdd labels to docker-compose.yml:
services:
app:
labels:
- "traefik.enable=true"
- "traefik.http.routers.calendar.rule=Host(`calendar.yourdomain.com`)"
- "traefik.http.routers.calendar.entrypoints=websecure"
- "traefik.http.routers.calendar.tls.certresolver=letsencrypt"Before going to production, ensure:
- Change
DB_PASSWORDto a strong, unique password - Generate a secure
NEXTAUTH_SECRET(openssl rand -base64 32) - Use HTTPS with a valid SSL certificate
- Configure firewall (only ports 80, 443, and 22 open)
- Set up fail2ban to prevent brute force attacks
- Regular security updates:
apt update && apt upgrade
- Set up automated backups
# Add to crontab 0 2 * * * docker exec calendar-db pg_dump -U calendar_user all_in_one_calendar | gzip > /backups/calendar_$(date +\%Y\%m\%d).sql.gz
- Configure backup retention (keep last 30 days)
- Test backup restoration
- Set up uptime monitoring (UptimeRobot, StatusCake, etc.)
- Configure email alerts for errors
- Monitor disk space usage
- Set up log rotation
- Enable HTTP/2
- Configure CDN (optional, for assets)
- Set up database connection pooling
- Configure caching headers
- Document your deployment
- Set up automatic updates (with testing)
- Create rollback procedure
- Test disaster recovery
# Check logs
docker-compose logs app
# Common issues:
# 1. Database not ready - wait a few seconds and restart
docker-compose restart app
# 2. Environment variables not set
nano .env
# 3. Port 3000 already in use
sudo lsof -i :3000# Check PostgreSQL is running
docker-compose ps postgres
# Check connection from app container
docker-compose exec app npx prisma db pull# Check firewall
sudo ufw status
# Allow ports
sudo ufw allow 80
sudo ufw allow 443# Check disk usage
df -h
# Clean Docker images
docker system prune -a
# Rotate logs
docker-compose down
sudo truncate -s 0 /var/lib/docker/containers/*/*-json.log
docker-compose up -dFor issues or questions:
- Check GitHub Issues
- Review documentation
- Check application logs
To update to the latest version:
cd /opt/calendar
git pull
docker-compose build --no-cache
docker-compose up -dAlways backup your database before updating!