This guide walks you through deploying a Pyramid web application (a Python WSGI framework) on a virtual private server (VPS). You’ll end up with a production-ready setup using Gunicorn as the WSGI server and Nginx as a reverse proxy, which handles static files and HTTPS. You’ll need a VPS with a Linux distribution (Ubuntu 22.04 or similar), SSH access, and a domain name pointing to the server’s IP address.
What You’ll Need
- A VPS running Ubuntu 22.04 or Debian 11/12 (any modern Linux works, but commands below assume apt).
- Root or sudo access to the server.
- Your Pyramid app code, preferably in a Git repository.
- A domain name (or subdomain) with an A record pointing to your server’s public IP.
- SSH client (like Terminal on macOS/Linux or PuTTY on Windows).
Step-by-Step
- Connect to your server via SSH:
ssh user@your_server_ip. Update the system:sudo apt update && sudo apt upgrade -y. - Install required packages:
sudo apt install -y python3-venv python3-pip nginx git. This gives you Python’s virtual environment support, pip, Nginx, and Git. - Create a dedicated user (optional but recommended) to run the app:
sudo adduser --system --group pyramid. This user will own the app files and run Gunicorn. - Clone your app into
/opt/pyramid_app:sudo git clone https://github.com/yourusername/yourpyramidapp.git /opt/pyramid_app. Replace the URL with your repo. If your repo is private, you’ll need to copy files via SCP or use a deploy key. - Set permissions:
sudo chown -R pyramid:pyramid /opt/pyramid_app. - Create a virtual environment and install dependencies:
cd /opt/pyramid_app && sudo -u pyramid python3 -m venv venv && sudo -u pyramid ./venv/bin/pip install -e .(assuming yoursetup.pyorpyproject.tomllists all dependencies). If you have arequirements.txt, use./venv/bin/pip install -r requirements.txt. - Test the app locally with the development server:
sudo -u pyramid ./venv/bin/pserve development.ini --reload(or however you run it). Visithttp://your_server_ip:6543to confirm it works. Stop it with Ctrl+C. - Create a Gunicorn systemd service so the app starts on boot and restarts if it crashes. Create the file
/etc/systemd/system/pyramid.servicewith the following content (adjust paths and the WSGI entry point):[Unit] Description=Gunicorn instance to serve Pyramid app After=network.target [Service] User=pyramid Group=pyramid WorkingDirectory=/opt/pyramid_app Environment="PATH=/opt/pyramid_app/venv/bin" ExecStart=/opt/pyramid_app/venv/bin/gunicorn --workers 3 --bind unix:/opt/pyramid_app/pyramid.sock wsgi:application [Install] WantedBy=multi-user.target
The
wsgi:applicationassumes your Pyramid app exposes a WSGI callable namedapplicationin awsgi.pyfile. If you use apasteconfig, you can use--paste production.iniinstead. Adjust workers (typically 2-4 per CPU core). - Enable and start the service:
sudo systemctl enable pyramid && sudo systemctl start pyramid. Check status withsudo systemctl status pyramid. - Configure Nginx as a reverse proxy. Create
/etc/nginx/sites-available/pyramidwith:server { listen 80; server_name yourdomain.com; location / { include proxy_params; proxy_pass http://unix:/opt/pyramid_app/pyramid.sock; } location /static/ { alias /opt/pyramid_app/static/; expires 30d; } }Replace
yourdomain.comand the static path. If your app serves static files from a different location, adjust. Enable the site:sudo ln -s /etc/nginx/sites-available/pyramid /etc/nginx/sites-enabled/, then test config:sudo nginx -t, then reload:sudo systemctl reload nginx. - Set up HTTPS with Let’s Encrypt (recommended):
sudo apt install certbot python3-certbot-nginx, then runsudo certbot --nginx -d yourdomain.com. Follow the prompts. Certbot will auto-configure HTTPS and set up renewal. - Configure your Pyramid app for production: in
production.ini(or your config), setdebugtoolbar = false,debug = false, and use a proper secret key. Also setpyramid.reload_templates = false. - Restart the service to apply changes:
sudo systemctl restart pyramid. - Verify everything: visit
https://yourdomain.comin a browser. Check logs if needed:sudo journalctl -u pyramid -fandsudo tail -f /var/log/nginx/error.log.
Common Mistakes
- Forgetting to set
debug = falsein production, which exposes stack traces. - Using the development server (pserve) instead of Gunicorn – it’s not designed for production.
- Not setting the correct WSGI entry point. If you get a 502 Bad Gateway, it’s often because Gunicorn can’t find the app.
- Static files not loading because the Nginx location block doesn’t match the actual static directory.
- Running Gunicorn as root – use a dedicated user.
- Not opening the firewall ports (80 and 443) if you have ufw enabled:
sudo ufw allow 'Nginx Full'.
Tips
- Use a production.ini separate from development.ini – never deploy with the dev config.
- Set up automatic database migrations (e.g., Alembic) as part of your deployment script.
- Use environment variables for secrets (database URLs, session keys) rather than hardcoding them in your config.
- Monitor your app with something like
htopand check logs regularly. - Consider using a process manager like Supervisor if you prefer it over systemd.
- Set up a swap file if your VPS has limited RAM – Gunicorn workers can be memory-hungry.
Troubleshooting
- 502 Bad Gateway: Check Gunicorn is running (
sudo systemctl status pyramid). Look at the socket file:sudo ls -la /opt/pyramid_app/pyramid.sock. Ensure the Nginx user (www-data) has access to the socket – you may need to addchmod 755 /opt/pyramid_appandchmod 666 pyramid.sock(or better, setGroup=www-datain the systemd service). - App loads but static files 404: Check the
aliaspath in Nginx – it must point to the actual static directory. Also ensure the static files exist and have correct permissions. - Gunicorn fails to start: Run
sudo journalctl -u pyramid -n 50to see the error. Common issues: missing dependencies, wrong Python path, or syntax error in the WSGI script. - HTTPS not working: After Certbot, check that Nginx config has the SSL lines. If you get a redirect loop, make sure your app’s
proxy-prefixis set correctly (if using--proxy-prefixorwsgi.url_scheme). - Database connection errors: Ensure your database is running and accessible. If using PostgreSQL, check
pg_hba.confallows connections from localhost. - Port already in use: If Gunicorn or Nginx fails to bind, check with
sudo ss -tlnpand kill the conflicting process.
Frequently Asked Questions
Q: Can I use Apache instead of Nginx?
A: Yes. Apache with mod_wsgi or as a reverse proxy works similarly. The steps for Gunicorn and systemd remain the same; only the web server config changes.
Q: How do I update my app after deployment?
A: Pull the new code (sudo -u pyramid git pull), reinstall dependencies if needed (./venv/bin/pip install -e .), run migrations, then restart the service: sudo systemctl restart pyramid.
Q: What if my Pyramid app uses WebSockets or long-polling?
A: Gunicorn supports WebSockets with the gevent-websocket worker class. You’ll need to add --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker to the ExecStart line, and install the package.
Q: How many Gunicorn workers should I use?
A> A common formula is 2 * CPU cores + 1. Start with 3 on a 1-core VPS and adjust based on memory usage and load.
Q: Can I run multiple Pyramid apps on the same VPS?
A: Yes. Use different Unix sockets or ports for each Gunicorn instance, and create separate Nginx server blocks (or locations) for each domain.
Q: Do I need to use a virtual environment?
A: Yes, it’s best practice to isolate dependencies. It prevents conflicts with system Python packages and makes your app portable.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Increase Internal Memory Xiaomi Phones: How-To
- Nvidia Display Settings Are Not Available: Fixes
- Gmod Keeps Crashing? Fixes That Actually Work
- Net Code Analysis Workflow: A Reliable Setup Guide
- Satellite Internet Down: What to Do Now
- Audit an AI Agent’s Privacy Before Connecting Accounts