Files
foldsite/docs/content/deployment/production.md
Tanishq Dubey ad81d7f3db
All checks were successful
Datadog Software Composition Analysis / Datadog SBOM Generation and Upload (push) Successful in 52s
Datadog Secrets Scanning / Datadog Static Analyzer (push) Successful in 1m1s
Datadog Static Analysis / Datadog Static Analyzer (push) Successful in 5m50s
docs refactor
2025-10-09 18:21:23 -04:00

16 KiB

version, date, author, title, description, summary, quick_tips
version date author title description summary quick_tips
1.0 2025-01-15 DWS Foldsite Team Production Deployment Deploying Foldsite for production use Complete guide to deploying Foldsite in production - from VPS servers to static hosting, with security, performance, and reliability best practices.
Use Gunicorn with multiple workers for dynamic deployments
Static export is fastest and cheapest for sites that don't change frequently
Always use HTTPS in production with proper SSL certificates

Production Deployment

Deploy Foldsite to serve real traffic with reliability, security, and performance.

Deployment Options

Option 1: Dynamic Server (Python)

Best for:

  • Frequently updated content
  • Sites needing template helpers in real-time
  • Admin file browser interface
  • Dynamic content generation

Characteristics:

  • Runs Python/Gunicorn server
  • Content updates appear immediately
  • Template helpers work dynamically
  • Requires server with Python

Hosting: VPS, dedicated server, PaaS platforms

Option 2: Static Export

Best for:

  • Infrequently updated sites
  • Maximum performance
  • Minimal cost
  • CDN delivery

Characteristics:

  • Pre-rendered HTML files
  • Blazing fast delivery
  • Can host anywhere (GitHub Pages, Netlify, S3)
  • Rebuild required for updates

Hosting: Static hosts, CDN, object storage

Dynamic Server Deployment

Prerequisites

  • Linux server (Ubuntu 20.04+ recommended)
  • Python 3.10+
  • Domain name
  • SSH access

Step 1: Server Setup

Update system:

sudo apt update
sudo apt upgrade -y

Install dependencies:

# Python and pip
sudo apt install -y python3.10 python3-pip python3-venv

# Build tools
sudo apt install -y build-essential python3-dev

# Nginx
sudo apt install -y nginx

# Certbot for SSL
sudo apt install -y certbot python3-certbot-nginx

Step 2: Deploy Foldsite

Create user:

sudo useradd -m -s /bin/bash foldsite
sudo su - foldsite

Clone and setup:

# Clone repository
git clone https://github.com/DWSresearch/foldsite.git
cd foldsite

# Create virtual environment
python3 -m venv venv
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt
pip install gunicorn  # Production WSGI server

Setup your content:

# Create site structure
mkdir -p ~/site/content
mkdir -p ~/site/templates
mkdir -p ~/site/styles

# Copy your content
# (upload via SCP, rsync, or git)

Create production config:

vim ~/foldsite/production-config.toml
[paths]
content_dir = "/home/foldsite/site/content"
templates_dir = "/home/foldsite/site/templates"
styles_dir = "/home/foldsite/site/styles"

[server]
listen_address = "127.0.0.1"  # Only accept local connections
listen_port = 8081
admin_browser = false  # Disable for security
max_threads = 8  # Adjust based on server
debug = false  # Never enable in production
access_log = true

Step 3: Systemd Service

Create service file:

sudo vim /etc/systemd/system/foldsite.service
[Unit]
Description=Foldsite Web Server
After=network.target

[Service]
Type=simple
User=foldsite
Group=foldsite
WorkingDirectory=/home/foldsite/foldsite
Environment="PATH=/home/foldsite/foldsite/venv/bin"
ExecStart=/home/foldsite/foldsite/venv/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:8081 \
    --access-logfile /var/log/foldsite/access.log \
    --error-logfile /var/log/foldsite/error.log \
    --config /home/foldsite/foldsite/production-config.toml \
    main:app

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Create log directory:

sudo mkdir -p /var/log/foldsite
sudo chown foldsite:foldsite /var/log/foldsite

Enable and start service:

sudo systemctl daemon-reload
sudo systemctl enable foldsite
sudo systemctl start foldsite

# Check status
sudo systemctl status foldsite

Step 4: Nginx Reverse Proxy

Create Nginx config:

sudo vim /etc/nginx/sites-available/foldsite
upstream foldsite {
    server 127.0.0.1:8081;
    keepalive 32;
}

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # Logs
    access_log /var/log/nginx/foldsite-access.log;
    error_log /var/log/nginx/foldsite-error.log;

    # Max upload size
    client_max_body_size 10M;

    # Proxy to Foldsite
    location / {
        proxy_pass http://foldsite;
        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;

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Cache static assets
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        proxy_pass http://foldsite;
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Security: deny access to hidden files
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Enable site:

sudo ln -s /etc/nginx/sites-available/foldsite /etc/nginx/sites-enabled/
sudo nginx -t  # Test configuration
sudo systemctl reload nginx

Step 5: SSL Certificate

Get certificate with Certbot:

sudo certbot --nginx -d your-domain.com -d www.your-domain.com

Follow prompts. Certbot will:

  • Obtain certificate from Let's Encrypt
  • Modify Nginx config for HTTPS
  • Setup auto-renewal

Verify auto-renewal:

sudo certbot renew --dry-run

Final Nginx config (with SSL): Certbot updates your config to include:

server {
    listen 443 ssl http2;
    server_name your-domain.com www.your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # ... rest of config
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    return 301 https://$server_name$request_uri;
}

Step 6: Firewall

Configure UFW:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status

Verification

Visit your domain:

https://your-domain.com

Should see your Foldsite with valid SSL!

Static Export Deployment

Generate Static Files

Note: Static export functionality may need to be implemented or use a static site generator mode

Conceptual approach:

# export.py
import os
from pathlib import Path
from src.rendering.renderer import render_page
from src.config.config import Configuration

def export_static(config_path, output_dir):
    """Export all pages to static HTML"""
    config = Configuration(config_path)
    config.load_config()

    output = Path(output_dir)
    output.mkdir(parents=True, exist_ok=True)

    # Walk content directory
    for content_file in config.content_dir.rglob('*'):
        if content_file.is_file() and not content_file.name.startswith('___'):
            # Generate output path
            rel_path = content_file.relative_to(config.content_dir)
            out_path = output / rel_path.with_suffix('.html')
            out_path.parent.mkdir(parents=True, exist_ok=True)

            # Render and save
            html = render_page(
                content_file,
                base_path=config.content_dir,
                template_path=config.templates_dir,
                style_path=config.styles_dir
            )

            with open(out_path, 'w') as f:
                f.write(html)

    # Copy styles
    import shutil
    shutil.copytree(config.styles_dir, output / 'styles')

if __name__ == '__main__':
    import sys
    export_static(sys.argv[1], sys.argv[2])

Usage:

python export.py config.toml ./dist

Deploy Static Files

GitHub Pages

# Export to docs/
python export.py config.toml ./docs

# Commit and push
git add docs/
git commit -m "Update site"
git push

# Enable Pages in GitHub repo settings
# Source: docs/ folder

Netlify

# Export
python export.py config.toml ./dist

# Install Netlify CLI
npm install -g netlify-cli

# Deploy
netlify deploy --prod --dir=dist

Or use continuous deployment:

# netlify.toml
[build]
  command = "pip install -r requirements.txt && python export.py config.toml dist"
  publish = "dist"

AWS S3 + CloudFront

# Export
python export.py config.toml ./dist

# Sync to S3
aws s3 sync ./dist s3://your-bucket-name --delete

# Invalidate CloudFront cache
aws cloudfront create-invalidation --distribution-id YOUR_DIST_ID --paths "/*"

Vercel

# Export
python export.py config.toml ./dist

# Deploy
vercel --prod ./dist

Performance Optimization

Nginx Caching

Add to Nginx config:

# Define cache path
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=foldsite_cache:10m max_size=1g inactive=60m use_temp_path=off;

server {
    # ...

    location / {
        proxy_cache foldsite_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_bypass $cookie_session;
        proxy_no_cache $cookie_session;
        add_header X-Cache-Status $upstream_cache_status;

        proxy_pass http://foldsite;
    }
}

Gzip Compression

# In /etc/nginx/nginx.conf
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;

Image Optimization

Foldsite automatically generates thumbnails, but optimize source images:

# Install optimization tools
sudo apt install jpegoptim optipng

# Optimize JPEGs
find content/ -name "*.jpg" -exec jpegoptim --strip-all {} \;

# Optimize PNGs
find content/ -name "*.png" -exec optipng -o2 {} \;

CDN Integration

Use CDN for static assets:

# Separate static assets
location /styles/ {
    alias /home/foldsite/site/styles/;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location /download/ {
    # Proxy to Foldsite for thumbnails
    proxy_pass http://foldsite;
    expires 30d;
}

Then point DNS for static.yourdomain.com to CDN origin.

Monitoring & Logging

Application Logs

View logs:

# Systemd logs
sudo journalctl -u foldsite -f

# Application logs
tail -f /var/log/foldsite/error.log
tail -f /var/log/foldsite/access.log

Nginx Logs

tail -f /var/log/nginx/foldsite-access.log
tail -f /var/log/nginx/foldsite-error.log

Log Rotation

Create /etc/logrotate.d/foldsite:

/var/log/foldsite/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 foldsite foldsite
    sharedscripts
    postrotate
        systemctl reload foldsite
    endscript
}

Monitoring Tools

Install basic monitoring:

# Netdata (system monitoring)
bash <(curl -Ss https://my-netdata.io/kickstart.sh)

# Access at http://your-server:19999

Check application health:

#!/bin/bash
# health-check.sh
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/)

if [ $response -eq 200 ]; then
    echo "Foldsite is healthy"
    exit 0
else
    echo "Foldsite is down (HTTP $response)"
    systemctl restart foldsite
    exit 1
fi

Run via cron:

*/5 * * * * /usr/local/bin/health-check.sh >> /var/log/foldsite/health.log 2>&1

Backup Strategy

Content Backup

#!/bin/bash
# backup.sh
BACKUP_DIR="/backups/foldsite"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# Backup content, templates, styles
tar czf $BACKUP_DIR/site-$DATE.tar.gz \
    /home/foldsite/site/

# Keep only last 30 days
find $BACKUP_DIR -name "site-*.tar.gz" -mtime +30 -delete

echo "Backup completed: site-$DATE.tar.gz"

Run daily via cron:

0 2 * * * /usr/local/bin/backup.sh

Remote Backup

# Sync to remote server
rsync -avz /home/foldsite/site/ user@backup-server:/backups/foldsite/

# Or sync to S3
aws s3 sync /home/foldsite/site/ s3://your-backup-bucket/foldsite/

Updating Foldsite

Update Process

# As foldsite user
cd ~/foldsite

# Pull latest code
git pull

# Activate venv
source venv/bin/activate

# Update dependencies
pip install -r requirements.txt

# Restart service
sudo systemctl restart foldsite

# Check logs
sudo journalctl -u foldsite -n 50

Zero-Downtime Updates

Use multiple Gunicorn workers and graceful reloading:

# Graceful reload (workers restart one by one)
sudo systemctl reload foldsite

# Or send HUP signal to Gunicorn
sudo pkill -HUP gunicorn

Security Hardening

Disable Directory Listing

Nginx automatically prevents this, but verify:

autoindex off;

Rate Limiting

Add to Nginx config:

limit_req_zone $binary_remote_addr zone=foldsite_limit:10m rate=10r/s;

server {
    location / {
        limit_req zone=foldsite_limit burst=20 nodelay;
        # ... rest of config
    }
}

Fail2ban

Protect against brute force:

sudo apt install fail2ban

# Create /etc/fail2ban/jail.local
[nginx-foldsite]
enabled = true
port = http,https
filter = nginx-foldsite
logpath = /var/log/nginx/foldsite-access.log
maxretry = 5
bantime = 3600

Security Headers

Already in Nginx config, but verify:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' https:; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline' https:;" always;

File Permissions

Ensure proper permissions:

# Content should be readable by foldsite user
chmod -R 755 ~/site/content
chmod -R 755 ~/site/templates
chmod -R 755 ~/site/styles

# Application should not be writable
chmod -R 555 ~/foldsite/src

Troubleshooting

Service Won't Start

# Check logs
sudo journalctl -u foldsite -xe

# Common issues:
# - Wrong Python path
# - Missing dependencies
# - Port already in use
# - Permission errors

502 Bad Gateway

Nginx can't reach Foldsite:

# Check if Foldsite is running
sudo systemctl status foldsite

# Check if port is listening
sudo netstat -tulpn | grep 8081

# Check Nginx error log
sudo tail /var/log/nginx/error.log

High Memory Usage

# Check process memory
ps aux | grep gunicorn

# Reduce workers or add swap
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Slow Response Times

# Check Nginx access logs for slow requests
sudo tail -f /var/log/nginx/foldsite-access.log

# Enable query logging in Foldsite
# Check for expensive template helpers
# Consider caching with Redis/Memcached

Platform-Specific Guides

DigitalOcean

# Create droplet (Ubuntu 22.04)
# Follow server setup steps above

# Use DigitalOcean firewall for security
# Enable backups in control panel

AWS EC2

# Launch Ubuntu instance
# Setup security groups (ports 22, 80, 443)
# Use Elastic IP for static IP
# Consider RDS for database if needed

Hetzner Cloud

# Create CX11 or larger instance
# Follow server setup
# Use Hetzner firewall
# Consider Hetzner volumes for storage

Next Steps

Your Foldsite is now production-ready! Monitor it regularly, keep it updated, and enjoy your self-hosted corner of the internet.