Guides6 min read
Deploying Potato on a Server
Production deployment guide for Potato including Docker, cloud platforms, and SSL configuration.
By Potato Teamยท
Deploying Potato on a Server
This guide covers deploying Potato for production use, including server setup, Docker deployment, cloud platforms, and security configuration.
Deployment Options
| Method | Best For | Complexity |
|---|---|---|
| Local | Development, testing | Low |
| Docker | Reproducible deployments | Medium |
| Cloud VM | Full control, custom setup | Medium |
| Docker Compose | Multi-container setups | Medium |
| Kubernetes | Large-scale deployments | High |
Basic Server Deployment
Prerequisites
# Ubuntu/Debian server
sudo apt update
sudo apt install python3.9 python3-pip nginx certbot python3-certbot-nginx
# Create directory structure
mkdir -p /opt/potato/projects
cd /opt/potatoInstallation
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install Potato
pip install potato-annotation
# Verify installation
potato --versionRunning with Gunicorn
# Install production server
pip install gunicorn
# Run with gunicorn
gunicorn -w 4 -b 127.0.0.1:8000 \
--chdir /opt/potato/projects/my_project \
"potato.server:create_app(config_path='config.yaml')"Systemd Service
Create /etc/systemd/system/potato.service:
[Unit]
Description=Potato Annotation Server
After=network.target
[Service]
Type=simple
User=potato
Group=potato
WorkingDirectory=/opt/potato/projects/my_project
Environment="PATH=/opt/potato/venv/bin"
ExecStart=/opt/potato/venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 \
"potato.server:create_app(config_path='config.yaml')"
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl enable potato
sudo systemctl start potato
sudo systemctl status potatoNginx Configuration
Basic Reverse Proxy
Create /etc/nginx/sites-available/potato:
server {
listen 80;
server_name annotation.example.com;
location / {
proxy_pass http://127.0.0.1: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;
# WebSocket support (if needed)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Static files
location /static/ {
alias /opt/potato/projects/my_project/static/;
expires 30d;
add_header Cache-Control "public, no-transform";
}
# Upload size limit
client_max_body_size 100M;
}Enable the site:
sudo ln -s /etc/nginx/sites-available/potato /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxSSL with Let's Encrypt
# Get SSL certificate
sudo certbot --nginx -d annotation.example.com
# Auto-renewal
sudo systemctl enable certbot.timerDocker Deployment
Dockerfile
FROM python:3.9-slim
WORKDIR /app
# Install dependencies
RUN pip install potato-annotation gunicorn
# Copy project files
COPY config.yaml .
COPY data/ ./data/
# Create directories
RUN mkdir -p annotations logs
# Expose port
EXPOSE 8000
# Run server
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", \
"potato.server:create_app(config_path='config.yaml')"]Build and Run
# Build image
docker build -t potato-annotation .
# Run container
docker run -d \
--name potato \
-p 8000:8000 \
-v $(pwd)/annotations:/app/annotations \
-v $(pwd)/logs:/app/logs \
potato-annotationDocker Compose
# docker-compose.yml
version: '3.8'
services:
potato:
build: .
ports:
- "8000:8000"
volumes:
- ./data:/app/data:ro
- ./annotations:/app/annotations
- ./logs:/app/logs
environment:
- POTATO_ENV=production
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- potato
restart: unless-stoppedCloud Platform Deployment
AWS EC2
# Launch EC2 instance (Ubuntu 22.04)
# Configure security group: ports 22, 80, 443
# SSH to instance
ssh -i your-key.pem ubuntu@your-instance-ip
# Follow basic server deployment steps above
# For persistent storage, attach EBS volume
sudo mount /dev/xvdf /opt/potato/dataGoogle Cloud Platform
# Create VM instance
gcloud compute instances create potato-server \
--zone=us-central1-a \
--machine-type=e2-medium \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud
# Configure firewall
gcloud compute firewall-rules create allow-http \
--allow tcp:80,tcp:443DigitalOcean
# Create droplet via CLI
doctl compute droplet create potato-server \
--size s-2vcpu-4gb \
--image ubuntu-22-04-x64 \
--region nyc1Configuration for Production
Production Config
# config.yaml
annotation_task_name: "Production Annotation Task"
# Note: Server settings (host, port, workers) are CLI flags:
# potato -p 8000 --host 0.0.0.0 config.yaml
# Or use gunicorn for production with multiple workers
# Logging
logging:
level: INFO
file: logs/potato.log
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
rotation:
max_size: 10MB
backup_count: 5
# Data
data_files:
- items.jsonl
item_properties:
id_key: id
text_key: text
# Output
output_annotation_dir: annotations/
output_annotation_format: jsonlEnvironment Variables
# /opt/potato/.env
POTATO_SECRET_KEY=your-secure-random-key-here
POTATO_ENV=production
OPENAI_API_KEY=sk-... # If using AI featuresLoad in systemd:
[Service]
EnvironmentFile=/opt/potato/.envSecurity Best Practices
Authentication
user_config:
auth_type: password
# Strong password requirements
password_policy:
min_length: 12
require_uppercase: true
require_number: true
# Session security
session:
secure_cookie: true
http_only: true
same_site: strictHTTPS Configuration
server {
listen 443 ssl http2;
server_name annotation.example.com;
ssl_certificate /etc/letsencrypt/live/annotation.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/annotation.example.com/privkey.pem;
# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# Security headers
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# ... rest of config
}Firewall
# UFW configuration
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enableMonitoring
Health Check Endpoint
# Check server health
curl http://localhost:8000/health
# Expected response
{"status": "healthy", "version": "2.0.0"}Log Monitoring
# View logs
sudo journalctl -u potato -f
# Or check log file
tail -f /opt/potato/logs/potato.logPrometheus Metrics (Optional)
# config.yaml
monitoring:
prometheus:
enabled: true
port: 9090Backup Strategy
Automated Backups
# backup.sh
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/opt/potato/backups
# Backup annotations
tar -czf $BACKUP_DIR/annotations_$DATE.tar.gz /opt/potato/projects/*/annotations/
# Backup configs
tar -czf $BACKUP_DIR/configs_$DATE.tar.gz /opt/potato/projects/*/config.yaml
# Remove old backups (keep 7 days)
find $BACKUP_DIR -mtime +7 -delete
# Optional: sync to cloud storage
# aws s3 sync $BACKUP_DIR s3://your-bucket/potato-backups/Add to crontab:
# Run daily at 2am
0 2 * * * /opt/potato/backup.shScaling
Multiple Workers
# Increase gunicorn workers based on CPU cores
gunicorn -w $((2 * $(nproc) + 1)) -b 0.0.0.0:8000 ...Load Balancing
upstream potato_servers {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
server {
location / {
proxy_pass http://potato_servers;
}
}Troubleshooting
Common Issues
Port already in use:
sudo lsof -i :8000
sudo kill -9 <PID>Permission denied:
sudo chown -R potato:potato /opt/potatoOut of memory:
# Add swap space
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfileFor additional help, see the full documentation or GitHub discussions.