
Frappe Ops Deployment
- 23 installs
- 159 repo stars
- Updated July 8, 2026
- openaec-foundation/frappe_claude_skill_package
Helps with devops & ci/cd tasks.
About
frappe-ops-deployment is a Claude Code skill for devops & ci/cd. It helps solo builders move faster with AI-assisted development.
- frappe-ops-deployment
- DevOps & CI/CD
- AI-coding skill
Frappe Ops Deployment by the numbers
- 23 all-time installs (skills.sh)
- Ranked #896 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/frappe_claude_skill_package --skill frappe-ops-deploymentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 23 |
|---|---|
| repo stars | ★ 159 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/frappe_claude_skill_package ↗ |
What it does
Helps with devops & ci/cd tasks.
Files
Production Deployment
Deploy Frappe/ERPNext to production using either traditional (bench + Nginx + Supervisor) or Docker (frappe_docker + Compose). Frappe officially recommends Docker for new deployments.
Quick Reference
# Traditional production setup (one command)
sudo bench setup production [frappe-user]
# What it configures:
# 1. Supervisor — process management (gunicorn, workers, Redis, socketio)
# 2. Nginx — reverse proxy, static files, websocket proxy
# 3. Sudoers — allows frappe-user to restart services
# Individual setup commands
bench setup supervisor # Generate supervisor config
bench setup nginx # Generate nginx config
bench setup sudoers $(whoami) # Allow service restarts without password
# Symlink configs into system directories
sudo ln -s $(pwd)/config/supervisor.conf /etc/supervisor/conf.d/frappe-bench.conf
sudo ln -s $(pwd)/config/nginx.conf /etc/nginx/conf.d/frappe-bench.conf
# SSL setup
sudo -H bench setup lets-encrypt [site-name]
sudo -H bench setup lets-encrypt [site-name] --custom-domain [domain]
# DNS multitenancy (multiple sites on port 80/443)
bench config dns_multitenant on
bench setup nginx
sudo service nginx reload---
Deployment Decision Tree
Which deployment method?
|
+-- New server, minimal ops experience?
| +-- Docker (frappe_docker) — recommended by Frappe
|
+-- Existing server with bench already installed?
| +-- Traditional (bench setup production)
|
+-- Need custom Frappe apps or complex build?
| +-- Docker with custom image build
|
+-- Cloud hosting (AWS/GCP/Azure)?
| +-- Docker on VM or Kubernetes
| +-- OR Frappe Cloud (managed)
|
+-- Single site or multi-site?
| +-- Single site: standard setup
| +-- Multi-site: DNS multitenancy required---
Traditional Deployment
Process Architecture
Internet → Nginx (port 80/443)
|
+-- Static files served directly
+-- /api, /app → Gunicorn (port 8000)
+-- /socket.io → Node.js socketio (port 9000)
Supervisor manages:
- frappe-bench-web (gunicorn)
- frappe-bench-socketio (node)
- frappe-bench-worker-short
- frappe-bench-worker-default
- frappe-bench-worker-long
- frappe-bench-redis-cache
- frappe-bench-redis-queue
- frappe-bench-schedule (scheduler)Step-by-Step Setup
# 1. Install bench (as non-root user)
sudo pip3 install frappe-bench
bench init frappe-bench --frappe-branch version-15
cd frappe-bench
# 2. Create site
bench new-site mysite.example.com
bench --site mysite.example.com install-app erpnext
# 3. Production setup (configures nginx + supervisor + sudoers)
sudo bench setup production $(whoami)
# 4. Verify processes are running
sudo supervisorctl status
# 5. Verify nginx config
sudo nginx -t && sudo systemctl reload nginxNginx Configuration
bench setup nginx generates config/nginx.conf with:
- Server block per site (DNS multitenancy)
- Proxy to gunicorn on port 8000
- WebSocket proxy to socketio on port 9000
- Static file serving from
sites/directory - Client max body size (default varies by version)
ALWAYS disable default nginx site to avoid port 80 conflicts:
sudo rm /etc/nginx/sites-enabled/default
# OR disable: sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bakSupervisor Configuration
bench setup supervisor generates config/supervisor.conf with:
--skip-redisflag to skip Redis if managed externally
For CentOS/RHEL: use .ini extension instead of .conf for supervisor configs.
---
SSL / HTTPS
Let's Encrypt (Recommended)
# Automated setup with cron renewal
sudo -H bench setup lets-encrypt mysite.example.com
# For custom domain (site name differs from domain)
sudo -H bench setup lets-encrypt mysite.example.com --custom-domain www.example.com
# Manual renewal
sudo bench renew-lets-encryptPrerequisites:
- DNS multitenancy enabled (
bench config dns_multitenant on) - Domain resolves to server IP
- Port 80 open for ACME challenge
- Root/sudo access
Certificate locations: /etc/letsencrypt/live/example.com/
fullchain.pem— certificate + chainprivkey.pem— private key
Certificates expire every 90 days. The setup command adds a monthly cron for renewal.
Custom SSL Certificate
# 1. Place certificate files
sudo mkdir -p /etc/nginx/conf.d/ssl
sudo cp certificate.crt /etc/nginx/conf.d/ssl/
sudo cp private.key /etc/nginx/conf.d/ssl/
sudo chmod 600 /etc/nginx/conf.d/ssl/private.key
# 2. Configure site
bench set-config ssl_certificate "/etc/nginx/conf.d/ssl/certificate.crt"
bench set-config ssl_certificate_key "/etc/nginx/conf.d/ssl/private.key"
# 3. Regenerate and reload
bench setup nginx
sudo systemctl reload nginxAll HTTP traffic is automatically redirected to HTTPS after SSL is configured.
---
DNS Multitenancy (Multi-Site)
# Enable DNS-based site routing
bench config dns_multitenant on
# Create sites with domain names
bench new-site site1.example.com
bench new-site site2.example.com
# Regenerate nginx (creates server blocks per site)
bench setup nginx
sudo systemctl reload nginxALWAYS use the actual domain as the site name. Nginx routes requests to the correct site based on the Host header.
---
Docker Deployment
Architecture (frappe_docker)
Docker Compose Services:
- configurator — initializes DB/Redis config (runs once)
- backend — Frappe/ERPNext application server (gunicorn)
- frontend — Nginx reverse proxy
- websocket — Node.js Socket.IO server
- queue-short — RQ worker for short jobs
- queue-long — RQ worker for long jobs
- (external) — MariaDB/PostgreSQL + Redis (separate containers or managed)
Shared Volume:
- sites:/home/frappe/frappe-bench/sites (persistent data)Production Docker Compose
# Clone frappe_docker
git clone https://github.com/frappe/frappe_docker.git
cd frappe_docker
# Use compose.yaml for production
# Key environment variables:
# DB_HOST, DB_PORT — database connection
# REDIS_CACHE, REDIS_QUEUE — Redis endpoints
# FRAPPE_SITE_NAME_HEADER — for multi-site routing
# PROXY_READ_TIMEOUT — upstream timeout
# CLIENT_MAX_BODY_SIZE — upload limit (default 50m)
docker compose -f compose.yaml up -dCustom Image Build
# Build custom image with your apps
export APPS_JSON='[
{"url":"https://github.com/frappe/erpnext","branch":"version-15"},
{"url":"https://github.com/your-org/custom-app","branch":"main"}
]'
docker build \
--build-arg APPS_JSON_BASE64=$(echo $APPS_JSON | base64 -w 0) \
--tag your-registry/custom-erpnext:latest \
images/custom/---
Security Hardening
Firewall (UFW)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
# NEVER expose ports 8000, 9000, 6379, 3306 to the internetFail2Ban
sudo apt install fail2ban
sudo systemctl enable fail2ban
# /etc/fail2ban/jail.local
# [sshd]
# enabled = true
# maxretry = 5
# bantime = 3600Redis Authentication
# Secure Redis for multi-bench environments
bench create-rq-users --set-admin-password
# Generates unique passwords per bench for Redis authAdditional Hardening
- ALWAYS disable root SSH login (
PermitRootLogin noin/etc/ssh/sshd_config) - ALWAYS use SSH key authentication, disable password auth
- NEVER run bench as root — create a dedicated
frappeuser - ALWAYS keep system packages updated (
sudo apt update && sudo apt upgrade) - ALWAYS set
ALLOW_CORSonly to trusted domains insite_config.json
---
Zero-Downtime Updates
# Traditional deployment
bench update --pull --patch --build --requirements
# Supervisor auto-restarts workers after update
# Docker deployment
# 1. Pull new image
docker compose pull
# 2. Recreate containers (rolling)
docker compose up -d --no-deps backend websocket queue-short queue-long
# 3. Run migrations
docker compose exec backend bench --site mysite.example.com migrate---
Version Differences
| Feature | v14 | v15 | v16 |
|---|---|---|---|
| Docker recommended | No | Official recommendation | Yes |
create-rq-users | No | Yes | Yes |
| ARM64 Docker images | No | Yes | Yes |
| Site-level logs | v13+ | Yes | Yes |
extend_doctype_class | No | No | Yes |
---
Reference Files
| File | Contents |
|---|---|
| examples.md | Complete deployment scripts and configs |
| anti-patterns.md | Common deployment mistakes |
| workflows.md | Step-by-step deployment workflows |
Related Skills
frappe-ops-backup— Backup and disaster recoveryfrappe-ops-performance— Performance tuningfrappe-ops-bench— Bench CLI referencefrappe-ops-upgrades— Version upgrade procedures
Deployment Anti-Patterns
1. Running bench as root
# WRONG — creates permission issues, security risk
sudo bench init frappe-bench
sudo bench new-site mysite.com
# CORRECT — ALWAYS use a dedicated non-root user
sudo adduser frappe
su - frappe
bench init frappe-benchWhy: Running as root means all files are owned by root. Supervisor/gunicorn workers running as root is a critical security vulnerability.
2. Exposing internal ports to the internet
# WRONG — Redis, MariaDB, gunicorn directly accessible
sudo ufw allow 3306/tcp # MariaDB
sudo ufw allow 6379/tcp # Redis
sudo ufw allow 8000/tcp # Gunicorn
# CORRECT — only expose HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow sshWhy: Redis has no authentication by default. MariaDB exposed = database breach. Gunicorn should ALWAYS be behind Nginx.
3. Forgetting to disable default nginx site
# WRONG — default nginx config conflicts with Frappe on port 80
bench setup nginx
sudo systemctl reload nginx
# ERROR: port 80 already in use
# CORRECT — disable default site first
sudo rm /etc/nginx/sites-enabled/default
sudo rm -f /etc/nginx/conf.d/default.conf
bench setup nginx
sudo systemctl reload nginx4. Editing generated nginx/supervisor configs directly
# WRONG — editing config/nginx.conf manually
# These changes are OVERWRITTEN by next bench setup nginx
# CORRECT — use bench config or site_config.json
bench set-config ssl_certificate "/path/to/cert.pem"
bench set-config ssl_certificate_key "/path/to/key.pem"
bench setup nginx # Regenerates with your settings5. Skipping DNS multitenancy for multi-site
# WRONG — creating multiple sites without DNS multitenancy
bench new-site site1.com
bench new-site site2.com
# Both sites unreachable — nginx doesn't know which to serve
# CORRECT — enable DNS multitenancy BEFORE creating sites
bench config dns_multitenant on
bench new-site site1.com
bench new-site site2.com
bench setup nginx
sudo systemctl reload nginx6. No SSL in production
# WRONG — serving ERPNext over plain HTTP
# All passwords, session tokens, and business data transmitted in cleartext
# CORRECT — ALWAYS enable SSL
sudo -H bench setup lets-encrypt mysite.com
# Free, automatic renewal, no excuse to skip7. Running bench update without --backup
# WRONG — updating without safety net
bench update
# CORRECT — ALWAYS backup before update
bench backup --with-files
bench update --pull --patch --build --requirements8. Docker: Using bind mounts instead of named volumes
# WRONG — data loss if container path changes
volumes:
- ./sites:/home/frappe/frappe-bench/sites
# CORRECT — named volumes persist independently
volumes:
sites:
driver: local9. Not setting MariaDB character set
# WRONG — default character set causes emoji/unicode issues
# MariaDB installed with default latin1
# CORRECT — ALWAYS configure utf8mb4
# /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
[mysql]
default-character-set = utf8mb410. Ignoring Redis security in multi-bench setups
# WRONG — multiple benches sharing Redis without auth
# One bench can read/write another bench's cache
# CORRECT — create RQ users with authentication
bench create-rq-users --set-admin-password
# Each bench gets unique Redis credentialsDeployment Examples
Complete Traditional Production Setup Script
#!/bin/bash
# production-setup.sh — Full Frappe/ERPNext production deployment
# Run as non-root user with sudo privileges
set -e
FRAPPE_USER=$(whoami)
BENCH_DIR="$HOME/frappe-bench"
SITE_NAME="erp.example.com"
FRAPPE_BRANCH="version-15"
ERPNEXT_BRANCH="version-15"
# 1. System dependencies (Ubuntu 22.04)
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-dev python3-pip python3-venv \
redis-server mariadb-server mariadb-client \
nginx supervisor curl git \
libffi-dev libssl-dev libjpeg-dev \
xvfb libfontconfig wkhtmltopdf
# 2. Node.js 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
sudo npm install -g yarn
# 3. MariaDB configuration
sudo mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_db_root_password';"
sudo mysql -e "FLUSH PRIVILEGES;"
# 4. Install bench
sudo pip3 install frappe-bench
# 5. Initialize bench
bench init $BENCH_DIR --frappe-branch $FRAPPE_BRANCH
cd $BENCH_DIR
# 6. Create site
bench new-site $SITE_NAME \
--db-root-password your_db_root_password \
--admin-password your_admin_password
# 7. Install ERPNext
bench get-app erpnext --branch $ERPNEXT_BRANCH
bench --site $SITE_NAME install-app erpnext
# 8. Production setup
sudo bench setup production $FRAPPE_USER
# 9. SSL
bench config dns_multitenant on
bench setup nginx
sudo systemctl reload nginx
sudo -H bench setup lets-encrypt $SITE_NAME
# 10. Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
echo "Deployment complete: https://$SITE_NAME"Docker Production Compose (Complete)
# docker-compose.yml — Production Frappe/ERPNext
version: "3.8"
services:
configurator:
image: frappe/erpnext:v15
command: >
bash -c "
bench set-config -g db_host db;
bench set-config -g db_port 3306;
bench set-config -g redis_cache redis://redis-cache:6379;
bench set-config -g redis_queue redis://redis-queue:6379;
"
volumes:
- sites:/home/frappe/frappe-bench/sites
backend:
image: frappe/erpnext:v15
volumes:
- sites:/home/frappe/frappe-bench/sites
depends_on:
configurator:
condition: service_completed_successfully
frontend:
image: frappe/erpnext:v15
command: nginx-entrypoint.sh
environment:
BACKEND: backend:8000
SOCKETIO: websocket:9000
FRAPPE_SITE_NAME_HEADER: $$host
UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
PROXY_READ_TIMEOUT: 120
CLIENT_MAX_BODY_SIZE: 50m
volumes:
- sites:/home/frappe/frappe-bench/sites
ports:
- "8080:8080"
depends_on:
- backend
- websocket
websocket:
image: frappe/erpnext:v15
command: ["node", "/home/frappe/frappe-bench/apps/frappe/socketio.js"]
volumes:
- sites:/home/frappe/frappe-bench/sites
depends_on:
- backend
queue-short:
image: frappe/erpnext:v15
command: bench worker --queue short,default
volumes:
- sites:/home/frappe/frappe-bench/sites
depends_on:
- backend
queue-long:
image: frappe/erpnext:v15
command: bench worker --queue long
volumes:
- sites:/home/frappe/frappe-bench/sites
depends_on:
- backend
scheduler:
image: frappe/erpnext:v15
command: bench schedule
volumes:
- sites:/home/frappe/frappe-bench/sites
depends_on:
- backend
db:
image: mariadb:10.11
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- db-data:/var/lib/mysql
redis-cache:
image: redis:7-alpine
redis-queue:
image: redis:7-alpine
volumes:
sites:
db-data:Nginx Reverse Proxy with External SSL (Traefik)
# docker-compose.override.yml — Add Traefik for SSL termination
services:
frontend:
ports: [] # Remove direct port mapping
labels:
- "traefik.enable=true"
- "traefik.http.routers.erpnext.rule=Host(`erp.example.com`)"
- "traefik.http.routers.erpnext.entrypoints=websecure"
- "traefik.http.routers.erpnext.tls.certresolver=letsencrypt"
- "traefik.http.services.erpnext.loadbalancer.server.port=8080"
traefik:
image: traefik:v2.10
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=admin@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt:/letsencrypt
volumes:
letsencrypt:Multi-Site Nginx Config (Generated by bench)
# This is auto-generated by bench setup nginx
# NEVER edit directly — changes are overwritten
upstream frappe-bench-frappe {
server 127.0.0.1:8000 fail_timeout=0;
}
upstream frappe-bench-socketio-server {
server 127.0.0.1:9000 fail_timeout=0;
}
server {
listen 80;
server_name site1.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name site1.example.com;
ssl_certificate /etc/letsencrypt/live/site1.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/site1.example.com/privkey.pem;
# Proxy to gunicorn
location / {
proxy_pass http://frappe-bench-frappe;
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 proxy
location /socket.io {
proxy_pass http://frappe-bench-socketio-server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Static files
location /assets {
alias /home/frappe/frappe-bench/sites/assets;
expires 1y;
add_header Cache-Control "public";
}
}Supervisor Config (Generated by bench)
; Auto-generated by bench setup supervisor
[program:frappe-bench-frappe-web]
command=/home/frappe/frappe-bench/env/bin/gunicorn -b 127.0.0.1:8000 -w 4 --timeout 120 frappe.app:application
priority=4
autostart=true
autorestart=true
user=frappe
directory=/home/frappe/frappe-bench/sites
[program:frappe-bench-frappe-worker-short]
command=bench worker --queue short
priority=4
autostart=true
autorestart=true
user=frappe
directory=/home/frappe/frappe-bench
[program:frappe-bench-frappe-worker-default]
command=bench worker --queue default
priority=4
autostart=true
autorestart=true
user=frappe
directory=/home/frappe/frappe-bench
[program:frappe-bench-frappe-worker-long]
command=bench worker --queue long
priority=4
autostart=true
autorestart=true
user=frappe
directory=/home/frappe/frappe-bench
[program:frappe-bench-frappe-schedule]
command=bench schedule
priority=3
autostart=true
autorestart=true
user=frappe
directory=/home/frappe/frappe-bench
[program:frappe-bench-node-socketio]
command=node /home/frappe/frappe-bench/apps/frappe/socketio.js
priority=4
autostart=true
autorestart=true
user=frappe
directory=/home/frappe/frappe-bench
[program:frappe-bench-redis-cache]
command=redis-server /home/frappe/frappe-bench/config/redis_cache.conf
priority=1
autostart=true
autorestart=true
user=frappe
[program:frappe-bench-redis-queue]
command=redis-server /home/frappe/frappe-bench/config/redis_queue.conf
priority=1
autostart=true
autorestart=true
user=frappe
[group:frappe-bench-web]
programs=frappe-bench-frappe-web,frappe-bench-node-socketio
[group:frappe-bench-workers]
programs=frappe-bench-frappe-worker-short,frappe-bench-frappe-worker-default,frappe-bench-frappe-worker-long,frappe-bench-frappe-schedule
[group:frappe-bench-redis]
programs=frappe-bench-redis-cache,frappe-bench-redis-queueDeployment Workflows
Workflow 1: Fresh Traditional Production Deployment
1. Provision server (Ubuntu 22.04 LTS recommended)
|
2. Create frappe user (NEVER use root)
$ sudo adduser frappe
$ sudo usermod -aG sudo frappe
|
3. Install system dependencies
$ sudo apt install python3-dev python3-pip redis-server
$ sudo apt install mariadb-server nginx supervisor
$ sudo apt install nodejs npm (v18.x)
$ sudo npm install -g yarn
|
4. Configure MariaDB
$ sudo mysql_secure_installation
Set character-set-server=utf8mb4
|
5. Install bench as frappe user
$ sudo pip3 install frappe-bench
$ bench init frappe-bench --frappe-branch version-15
|
6. Create site and install apps
$ bench new-site erp.example.com
$ bench get-app erpnext --branch version-15
$ bench --site erp.example.com install-app erpnext
|
7. Setup production
$ sudo bench setup production frappe
|
8. Verify
$ sudo supervisorctl status (all RUNNING)
$ sudo nginx -t (syntax ok)
|
9. Enable DNS multitenancy (if multi-site)
$ bench config dns_multitenant on
$ bench setup nginx
|
10. Enable SSL
$ sudo -H bench setup lets-encrypt erp.example.com
|
11. Harden security
$ sudo ufw enable (allow 22, 80, 443 only)
$ Disable root SSH login
$ Install fail2banWorkflow 2: Docker Production Deployment
1. Provision server with Docker + Docker Compose v2
|
2. Clone frappe_docker
$ git clone https://github.com/frappe/frappe_docker.git
$ cd frappe_docker
|
3. Configure environment
$ cp example.env .env
Edit .env: DB_ROOT_PASSWORD, SITE_NAME, etc.
|
4. Start services
$ docker compose -f compose.yaml up -d
|
5. Create site
$ docker compose exec backend \
bench new-site erp.example.com \
--db-root-password $DB_ROOT_PASSWORD \
--admin-password $ADMIN_PASSWORD
|
6. Install apps
$ docker compose exec backend \
bench --site erp.example.com install-app erpnext
|
7. Add reverse proxy (Traefik or external Nginx)
Use compose override for SSL termination
|
8. Verify
$ docker compose ps (all healthy)
$ curl -I https://erp.example.comWorkflow 3: Adding a New Site (Multi-Tenancy)
Prerequisites: DNS multitenancy enabled, production running
1. Point DNS A record to server IP
site2.example.com -> 203.0.113.10
|
2. Create site
$ bench new-site site2.example.com \
--db-root-password $DB_ROOT_PASSWORD \
--admin-password $ADMIN_PASSWORD
|
3. Install apps
$ bench --site site2.example.com install-app erpnext
|
4. Regenerate nginx config
$ bench setup nginx
$ sudo systemctl reload nginx
|
5. Setup SSL for new site
$ sudo -H bench setup lets-encrypt site2.example.com
|
6. Verify
$ curl -I https://site2.example.comWorkflow 4: Zero-Downtime Update (Traditional)
1. Backup current state
$ bench backup --with-files
|
2. Put site in maintenance mode (optional, for major updates)
$ bench --site mysite.com set-maintenance-mode on
|
3. Pull updates
$ bench update --pull --patch --build --requirements
|
4. Verify processes restarted
$ sudo supervisorctl status
|
5. Disable maintenance mode
$ bench --site mysite.com set-maintenance-mode off
|
6. Smoke test
Visit https://mysite.com and verify key functionsWorkflow 5: Zero-Downtime Update (Docker)
1. Backup
$ docker compose exec backend bench backup --with-files
|
2. Pull new images
$ docker compose pull
|
3. Recreate services (rolling)
$ docker compose up -d --no-deps backend websocket queue-short queue-long
|
4. Run migrations
$ docker compose exec backend bench --site mysite.com migrate
|
5. Rebuild frontend if needed
$ docker compose up -d --no-deps --build frontend
|
6. Verify
$ docker compose ps
$ curl -I https://mysite.com