Self-Hosting#
Run icalendar-anonymizer locally with Docker for complete data privacy.
Why Self-Host?#
Some people won’t trust a web service with their calendar data. They need to run this locally. Docker makes that easy.
If your company policy says no external services, you can pull the Docker image, run it locally, and use it via localhost:8000. Your data never leaves your machine.
Quick Start#
Prerequisites#
Docker installed
Docker Compose installed (included with Docker Desktop)
Basic Setup#
# Clone the repository
git clone https://github.com/mergecal/icalendar-anonymizer.git
cd icalendar-anonymizer
# Start the service
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the service
docker-compose down
The service will be available at http://localhost:8000
Configuration#
Environment Variables#
Configure the service by editing docker-compose.yml or setting environment variables:
Server Configuration#
HOSTNetwork interface to bind to (default:
0.0.0.0)PORTPort number to listen on (default:
8000)WORKERSNumber of Gunicorn worker processes (default:
4)
File Handling#
MAX_FILE_SIZEMaximum upload size in bytes (default:
10485760= 10MB)
Example docker-compose.yml#
services:
icalendar-anonymizer:
build: .
ports:
- "8000:8000"
environment:
- HOST=0.0.0.0
- PORT=8000
- WORKERS=4
- MAX_FILE_SIZE=10485760
- FERNET_KEY=your-secret-key-here # Optional: enables live proxy links
restart: unless-stopped
Docker Commands#
Build the Image#
docker-compose build
Start the Service#
# Start in background
docker-compose up -d
# Start with logs visible
docker-compose up
View Logs#
# Follow logs
docker-compose logs -f
# View last 100 lines
docker-compose logs --tail=100
Stop the Service#
docker-compose down
Restart the Service#
docker-compose restart
Update to Latest Version#
git pull
docker-compose build
docker-compose up -d
Health Check#
The service includes a health check endpoint at /health that returns:
{
"status": "healthy",
"version": "0.1.0",
"r2_enabled": false,
"fernet_enabled": false
}
The fernet_enabled field indicates whether Fernet shareable links are available (FERNET_KEY environment variable is set).
Docker uses this endpoint to monitor service health. You can also check it manually:
curl http://localhost:8000/health
Security Considerations#
Non-Root User#
The Docker container runs as a non-root user (UID 1000) for security.
Network Isolation#
The service only exposes port 8000. No other services or ports are accessible.
SSRF Protection#
URL fetching includes SSRF protection that blocks:
Private IP ranges (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
Loopback addresses (127.0.0.1, localhost)
Link-local addresses (169.254.0.0/16)
Known limitation: DNS rebinding attacks may bypass these checks. See Issue #70 for details.
File Size Limits#
Default 10MB limit prevents DoS attacks via large file uploads. Adjust via MAX_FILE_SIZE if needed.
Production Deployment#
For production environments:
Use HTTPS: Put the service behind a reverse proxy (nginx, Caddy, Traefik) with TLS
Tighten CORS: Edit
main.pyto allow only specific origins instead of*Add authentication: See Issue #79 for planned authentication support
Monitor logs: Set up log aggregation and monitoring
Regular updates: Subscribe to security advisories and update promptly
Reverse Proxy Example (nginx)#
server {
listen 443 ssl http2;
server_name calendar.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8000;
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;
}
}
Troubleshooting#
Service Won’t Start#
Check logs:
docker-compose logs
Common issues:
Port 8000 already in use: Change
PORTin docker-compose.ymlPermission denied: Ensure Docker daemon is running
Health Check Failing#
Check if the service is responding:
docker-compose exec icalendar-anonymizer curl http://localhost:8000/health
If no response, check worker logs for errors.
Build Fails#
Ensure you have the .git directory (needed for version detection):
ls -la .git
If missing, clone the repository instead of downloading a ZIP archive.
Image Too Large#
The image is built with multi-stage builds to stay under 200MB. If larger:
Clean Docker build cache:
docker system pruneRebuild:
docker-compose build --no-cache
Performance Issues#
Adjust worker count based on CPU cores:
environment:
- WORKERS=8 # Increase for more cores
Recommended: (CPU cores * 2) + 1