
How to Deploy Python WSGI Apps with CherryPy Behind Nginx on Ubuntu 24.04
CherryPy is a lightweight Python web framework that can serve any WSGI application. By putting CherryPy behind Nginx, you get the performance, security, and manageability benefits of a full-featured HTTP server. In this guide, you’ll learn how to:
- Install system dependencies (Python, pip, CherryPy, Nginx)
- Create a simple WSGI app served by CherryPy
- Configure CherryPy to run as a background service with Systemd
- Set up Nginx to reverse-proxy HTTP requests to CherryPy
- (Optional) Secure your site with Let’s Encrypt SSL certificates
By the end, your Python app will be running on http://your-domain.com
(or https://…
) with Nginx handling client traffic and CherryPy serving WSGI.
🧰 Prerequisites
- Ubuntu 24.04 (or similar Linux) server with SSH access
- A user with
sudo
privileges - A registered domain name pointing to your server’s public IP
- Basic familiarity with the command line
Before you begin, update your package lists:
bashCopyEditsudo apt update && sudo apt upgrade -y
1. Install System Dependencies
1.1. Install Python 3 and pip
Ubuntu 24.04 comes with Python 3.10 by default, but let’s ensure it’s installed and then install pip
:
bashCopyEditsudo apt install -y python3 python3-venv python3-pip
Verify versions:
bashCopyEditpython3 --version # e.g., Python 3.10.x
pip3 --version # e.g., pip 23.x.x
1.2. Create a Dedicated System User
It’s best practice to run your CherryPy app under a non-root user:
bashCopyEditsudo adduser --system --group --no-create-home cherrypy
This creates a system user cherrypy
(no interactive login).
1.3. Install CherryPy and Other Python Dependencies
Create a project directory—e.g., /opt/myapp
—and set permissions:
bashCopyEditsudo mkdir -p /opt/myapp
sudo chown cherrypy:cherrypy /opt/myapp
Now switch to that user’s context (for file ownership) or use a virtual environment:
bashCopyEditcd /opt/myapp
sudo -u cherrypy python3 -m venv venv
sudo -u cherrypy bash -c "source venv/bin/activate && pip install cherrypy"
If your WSGI app uses Flask, Django, or other libraries, install them inside the same venv
. For example, to install Flask:
bashCopyEditsudo -u cherrypy bash -c "source venv/bin/activate && pip install flask"
2. Create a Simple WSGI Application
We’ll build a minimal “Hello, World” WSGI app. Create a file /opt/myapp/app.py
owned by cherrypy
:
bashCopyEditsudo -u cherrypy tee /opt/myapp/app.py > /dev/null << 'EOF'
import cherrypy
class HelloApp:
@cherrypy.expose
def index(self):
return "Hello from CherryPy WSGI!"
def start_app():
# Mount the WSGI app at "/"
cherrypy.tree.graft(HelloApp(), "/")
# Unsubscribe the default HTTP server (CherryPy’s own) since we'll rely on Nginx
cherrypy.server.unsubscribe()
# Configure CherryPy’s WSGI server to listen on localhost:8000
cherrypy.config.update({
'server.socket_host': '127.0.0.1',
'server.socket_port': 8000,
'engine.autoreload.on': False
})
cherrypy.engine.start()
cherrypy.engine.block()
if __name__ == "__main__":
start_app()
EOF
Explanation:
- We define
HelloApp
with a singleindex()
method exposed at/
. - We call
cherrypy.tree.graft(...)
, which allows CherryPy to serve this as a WSGI app. - We unsubscribe CherryPy’s built-in HTTP server so that this process only listens on
127.0.0.1:8000
. Nginx will proxy incoming traffic to that port. engine.autoreload.on=False
disables live‐reload—important in production.
3. Configure CherryPy as a Systemd Service
We want CherryPy to start on boot and run in the background. Create a Systemd service file at /etc/systemd/system/cherrypy.service
:
bashCopyEditsudo tee /etc/systemd/system/cherrypy.service > /dev/null << 'EOF'
[Unit]
Description=CherryPy WSGI Application
After=network.target
[Service]
Type=simple
User=cherrypy
Group=cherrypy
WorkingDirectory=/opt/myapp
Environment="PATH=/opt/myapp/venv/bin"
ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
- User/Group: Runs under
cherrypy:cherrypy
. - WorkingDirectory:
/opt/myapp
. - Environment: Ensures the virtual environment’s
python
andpip
are used. - ExecStart: Launches our
app.py
.
Reload Systemd, enable, and start:
bashCopyEditsudo systemctl daemon-reload
sudo systemctl enable cherrypy
sudo systemctl start cherrypy
Check status:
bashCopyEditsudo systemctl status cherrypy
You should see CherryPy listening on 127.0.0.1:8000
. Verify with:
bashCopyEditsudo ss -tlnp | grep 8000
4. Install and Configure Nginx as a Reverse Proxy
4.1. Install Nginx
If not already installed:
bashCopyEditsudo apt install -y nginx
sudo systemctl enable --now nginx
Verify:
bashCopyEditsudo systemctl status nginx
4.2. Create an Nginx Site Configuration
Create /etc/nginx/sites-available/myapp
(replace myapp
with your app’s name):
bashCopyEditsudo tee /etc/nginx/sites-available/myapp > /dev/null << 'EOF'
server {
listen 80;
server_name your-domain.com www.your-domain.com;
# Increase client body size if you expect large POSTs
client_max_body_size 20M;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
access_log /var/log/nginx/myapp_access.log;
error_log /var/log/nginx/myapp_error.log;
}
EOF
Replace your-domain.com
with your actual domain. The proxy_set_header
directives ensure the correct client IP and host headers are passed to CherryPy.
4.3. Enable the Nginx Site & Test
bashCopyEditsudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
4.4. Test in a Browser
Navigate to http://your-domain.com/
. You should see:
csharpCopyEditHello from CherryPy WSGI!
If you see that, Nginx is successfully proxying requests to CherryPy.
5. (Optional) Secure with Let’s Encrypt SSL
To serve your app over HTTPS, use Certbot to obtain a free certificate:
5.1. Install Certbot
bashCopyEditsudo apt install -y certbot python3-certbot-nginx
5.2. Run Certbot
bashCopyEditsudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp \
--email [email protected] \
-d your-domain.com -d www.your-domain.com
Certbot will:
- Obtain certificates for
your-domain.com
andwww.your-domain.com
- Edit your Nginx config to listen on port 443
- Redirect HTTP → HTTPS automatically
After it finishes, visit https://your-domain.com
to verify.
6. Common Tips & Troubleshooting
- Logs
- CherryPy logs to
stdout
/stderr
, view withjournalctl -u cherrypy -f
. - Nginx logs are in
/var/log/nginx/myapp_access.log
andmyapp_error.log
.
- CherryPy logs to
- Firewall
- Ensure ports 80 and 443 are open: bashCopyEdit
sudo ufw allow 'Nginx Full'
- If using
iptables
directly, open TCP 80 and 443.
- Ensure ports 80 and 443 are open: bashCopyEdit
- Scaling
- For higher load, consider running multiple CherryPy workers (e.g., via
multiprocessing
or spawning multiple Systemd services on different ports) and adjust Nginx’supstream
block accordingly.
- For higher load, consider running multiple CherryPy workers (e.g., via
- Environment Variables
- If your WSGI app needs environment variables (e.g.,
DATABASE_URL
), you can add them under[Service]
in the Systemd file: iniCopyEditEnvironment="DATABASE_URL=postgres://user:pass@localhost/dbname"
- Then reload Systemd (
sudo systemctl daemon-reload && sudo systemctl restart cherrypy
).
- If your WSGI app needs environment variables (e.g.,
- Updating Your App
- Pull new code into
/opt/myapp
(e.g., viagit pull
). - Install any new dependencies inside
venv
(sudo -u cherrypy bash -c "source /opt/myapp/venv/bin/activate && pip install -r requirements.txt"
). - Restart CherryPy: bashCopyEdit
sudo systemctl restart cherrypy
- Pull new code into
🚀 Final Thoughts
By combining CherryPy as a pure‐Python WSGI server with Nginx as a reverse proxy (and SSL terminator), you get a robust, production‐ready deployment. CherryPy handles your Python application logic, while Nginx takes care of TLS, static content (if any), and client‐facing HTTP optimizations.
🌿 Hosting Solutions from Greenhost
At Greenhost, we provide reliable, developer-friendly hosting solutions tailored to modern web applications, including:
- WordPress Hosting – Optimized, secure, and ready for PHP‐based sites
- Email Hosting – Business‐grade email with high uptime
- Shared Web Hosting – Affordable plans that support Python, PHP, and more
- Website Builder – Launch a professional website without writing code
Whether you need a CherryPy-backed Python environment, a LAMP/LEMP stack, or a containerized platform, Greenhost has you covered with fast, secure, and eco-friendly infrastructure. Deploy with confidence on our scalable servers.