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. |
|
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
- Local Development - Development workflow
- Docker Deployment - Container deployment
- Support - Get help
Your Foldsite is now production-ready! Monitor it regularly, keep it updated, and enjoy your self-hosted corner of the internet.