Introduction
Wagtail is a powerful, open-source content management system built on Django. It combines an intuitive admin interface with the flexibility of a full Python web framework, making it ideal for building complex websites and applications.
Why Choose Wagtail?
- Built on Django – leverage Python's powerful ecosystem
- Intuitive StreamField for flexible content modeling
- Powerful image and document management
- Built-in search functionality
- Excellent developer experience with clean APIs
- Active community and extensive documentation
Prerequisites
Before beginning this deployment, ensure you have:
- A RamNode VPS with Ubuntu 22.04 or 24.04 LTS
- Root or sudo access to your server
- A registered domain name pointed to your server's IP address
- Basic familiarity with Linux command line and SSH
Recommended Server Specifications
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 1 GB | 2+ GB |
| CPU | 1 vCPU | 2+ vCPUs |
| Storage | 20 GB SSD | 40+ GB SSD |
Initial Server Setup
Update the System
Start by connecting to your RamNode VPS via SSH and updating all system packages:
sudo apt update && sudo apt upgrade -yCreate a Dedicated User
Create a non-root user to run your Wagtail application (security best practice):
sudo adduser wagtail
sudo usermod -aG sudo wagtailConfigure the Firewall
Enable UFW and allow SSH, HTTP, and HTTPS traffic:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enableInstall Dependencies
Install Python and Development Tools
Install Python 3, pip, and essential development libraries:
sudo apt install -y python3 python3-pip python3-venv python3-dev \
build-essential libpq-dev libjpeg-dev zlib1g-dev libwebp-devInstall PostgreSQL
PostgreSQL is the recommended database for production Wagtail deployments:
sudo apt install -y postgresql postgresql-contribInstall Nginx
Nginx will serve as our reverse proxy and handle static files:
sudo apt install -y nginxDatabase Configuration
Switch to the postgres user and create a database and user for Wagtail:
sudo -u postgres psqlRun the following SQL commands in the PostgreSQL prompt:
CREATE DATABASE wagtail_db;
CREATE USER wagtail_user WITH PASSWORD 'your_secure_password';
ALTER ROLE wagtail_user SET client_encoding TO 'utf8';
ALTER ROLE wagtail_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE wagtail_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE wagtail_db TO wagtail_user;
\q⚠️ Important: Replace 'your_secure_password' with a strong, unique password and store it securely.
Install Wagtail
Create Project Directory and Virtual Environment
Set up the project directory structure and Python virtual environment:
sudo mkdir -p /var/www/wagtail
sudo chown wagtail:wagtail /var/www/wagtail
cd /var/www/wagtail
python3 -m venv venv
source venv/bin/activateInstall Wagtail and Dependencies
Install Wagtail along with production dependencies:
pip install --upgrade pip
pip install wagtail gunicorn psycopg2-binary pillowCreate the Wagtail Project
Generate a new Wagtail project:
wagtail start mysite .Production Configuration
Configure Production Settings
Create a production settings file at mysite/settings/production.py:
from .base import *
import os
DEBUG = False
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'wagtail_db',
'USER': 'wagtail_user',
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': 'localhost',
'PORT': '5432',
}
}
STATIC_ROOT = '/var/www/wagtail/static'
MEDIA_ROOT = '/var/www/wagtail/media'
CSRF_TRUSTED_ORIGINS = ['https://yourdomain.com']
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = TrueCreate Environment File
Create /var/www/wagtail/.env to store sensitive configuration:
DJANGO_SETTINGS_MODULE=mysite.settings.production
DJANGO_SECRET_KEY=your-secret-key-here
DB_PASSWORD=your_secure_passwordGenerate a secure secret key using:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"Initialize the Database
Run migrations and create a superuser:
source /var/www/wagtail/.env
python manage.py migrate
python manage.py createsuperuser
python manage.py collectstatic --noinputGunicorn Configuration
Create Gunicorn Socket File
Create /etc/systemd/system/gunicorn.socket:
[Unit]
Description=Gunicorn socket for Wagtail
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.targetCreate Gunicorn Service File
Create /etc/systemd/system/gunicorn.service:
[Unit]
Description=Gunicorn daemon for Wagtail
Requires=gunicorn.socket
After=network.target
[Service]
User=wagtail
Group=www-data
WorkingDirectory=/var/www/wagtail
EnvironmentFile=/var/www/wagtail/.env
ExecStart=/var/www/wagtail/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
mysite.wsgi:application
[Install]
WantedBy=multi-user.targetEnable and Start Gunicorn
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
sudo systemctl status gunicorn.socketNginx Configuration
Create /etc/nginx/sites-available/wagtail:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
alias /var/www/wagtail/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
location /media/ {
alias /var/www/wagtail/media/;
expires 7d;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
proxy_connect_timeout 300s;
proxy_read_timeout 300s;
}
client_max_body_size 100M;
}Enable the configuration and test Nginx:
sudo ln -s /etc/nginx/sites-available/wagtail /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginxSSL/TLS Configuration
Install Certbot
Install Certbot for Let's Encrypt SSL certificates:
sudo apt install -y certbot python3-certbot-nginxObtain SSL Certificate
Run Certbot to obtain and configure SSL:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.comFollow the prompts to complete certificate installation. Certbot will automatically configure Nginx for HTTPS.
Verify Automatic Renewal
sudo certbot renew --dry-runMaintenance & Updates
Updating Wagtail
To update Wagtail and its dependencies:
cd /var/www/wagtail
source venv/bin/activate
pip install --upgrade wagtail
python manage.py migrate
python manage.py collectstatic --noinput
sudo systemctl restart gunicornBackup Strategy
Implement regular backups of your database and media files:
# Database backup
pg_dump -U wagtail_user wagtail_db > backup_$(date +%Y%m%d).sql
# Media files backup
tar -czf media_backup_$(date +%Y%m%d).tar.gz /var/www/wagtail/media/Log Monitoring
# Gunicorn logs
sudo journalctl -u gunicorn
# Nginx logs
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.logSecurity Best Practices
- Keep your system and all packages updated regularly
- Use strong, unique passwords for all accounts
- Configure fail2ban to protect against brute force attacks
- Disable root SSH login and use key-based authentication
- Regularly audit user access and permissions
- Enable automatic security updates for Ubuntu
Troubleshooting
| Issue | Solution |
|---|---|
| 502 Bad Gateway | Check if Gunicorn is running: sudo systemctl status gunicorn |
| Static files not loading | Run collectstatic and verify Nginx static path |
| Database connection error | Verify PostgreSQL is running and credentials are correct |
| Permission denied errors | Check ownership: chown -R wagtail:www-data /var/www/wagtail |
🎉 Congratulations!
Your Wagtail CMS is now deployed on your RamNode VPS with a production-ready configuration! You can access the admin panel at https://yourdomain.com/admin/ using the superuser credentials you created.
For additional resources, refer to the official Wagtail documentation and the Django documentation.
