keepcalculator

06 Numbers and Powers

Deploy a Pyramid WSGI App on a VPS

Card No. 06·64074 · Updated · Standard formula, shown below

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

  1. Connect to your server via SSH: ssh user@your_server_ip. Update the system: sudo apt update && sudo apt upgrade -y.
  2. 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.
  3. 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.
  4. 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.
  5. Set permissions: sudo chown -R pyramid:pyramid /opt/pyramid_app.
  6. 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 your setup.py or pyproject.toml lists all dependencies). If you have a requirements.txt, use ./venv/bin/pip install -r requirements.txt.
  7. Test the app locally with the development server: sudo -u pyramid ./venv/bin/pserve development.ini --reload (or however you run it). Visit http://your_server_ip:6543 to confirm it works. Stop it with Ctrl+C.
  8. Create a Gunicorn systemd service so the app starts on boot and restarts if it crashes. Create the file /etc/systemd/system/pyramid.service with 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:application assumes your Pyramid app exposes a WSGI callable named application in a wsgi.py file. If you use a paste config, you can use --paste production.ini instead. Adjust workers (typically 2-4 per CPU core).

  9. Enable and start the service: sudo systemctl enable pyramid && sudo systemctl start pyramid. Check status with sudo systemctl status pyramid.
  10. Configure Nginx as a reverse proxy. Create /etc/nginx/sites-available/pyramid with:
    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.com and 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.

  11. Set up HTTPS with Let’s Encrypt (recommended): sudo apt install certbot python3-certbot-nginx, then run sudo certbot --nginx -d yourdomain.com. Follow the prompts. Certbot will auto-configure HTTPS and set up renewal.
  12. Configure your Pyramid app for production: in production.ini (or your config), set debugtoolbar = false, debug = false, and use a proper secret key. Also set pyramid.reload_templates = false.
  13. Restart the service to apply changes: sudo systemctl restart pyramid.
  14. Verify everything: visit https://yourdomain.com in a browser. Check logs if needed: sudo journalctl -u pyramid -f and sudo tail -f /var/log/nginx/error.log.

Common Mistakes

  • Forgetting to set debug = false in 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 htop and 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 add chmod 755 /opt/pyramid_app and chmod 666 pyramid.sock (or better, set Group=www-data in the systemd service).
  • App loads but static files 404: Check the alias path 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 50 to 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-prefix is set correctly (if using --proxy-prefix or wsgi.url_scheme).
  • Database connection errors: Ensure your database is running and accessible. If using PostgreSQL, check pg_hba.conf allows connections from localhost.
  • Port already in use: If Gunicorn or Nginx fails to bind, check with sudo ss -tlnp and 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

The whole Numbers and Powers drawer →