Back to home

Deploying Python Applications with Nginx and systemd: A Production-Ready Approach

Deploying Python Applications with Nginx and systemd

When deploying a backend application (FastAPI, Flask, Django, or any Python service) to a cloud server like AWS EC2, simply running:

python app.py

is not enough.

In real-world production environments, we need:

  • ✔ Reliability
  • ✔ Auto-restart on crash
  • ✔ Proper web server handling
  • ✔ Secure HTTPS
  • ✔ Clean configuration

This is where Nginx and systemd come into play.

In this article, we’ll walk through:

  • What Nginx does
  • What systemd does
  • Why you should use both together
  • Best configuration practices
  • Reload vs restart explained

What is systemd (systemctl)?

systemd is the service manager in modern Linux systems. It allows you to run your backend application as a background service.

Instead of running:

python app.py

You create a service file:

[Unit]
    Description=ABC
    After=network.target

    [Service]
    User=ec2-user
    WorkingDirectory=/var/www/ABC
    ExecStart=/home/ec2-user/.local/bin/uv run python app.py
    Restart=always
    Environment="PATH=/home/ec2-user/.local/bin:/usr/bin"

    [Install]
    WantedBy=multi-user.target
    

Benefits of systemd:

  • ✅ Auto-start on server boot
  • ✅ Restart on crash
  • ✅ No terminal needed
  • ✅ Production standard

Common commands:

systemctl start ABC.service
    systemctl stop ABC.service
    systemctl restart ABC.service
    systemctl status ABC.service

What is Nginx?

Nginx is a high-performance web server and reverse proxy.

It handles:

  • HTTP/HTTPS traffic
  • Static files (HTML, CSS, images)
  • Routing to backend services

Python servers alone are not designed for:

  • ❌ SSL handling
  • ❌ Heavy traffic
  • ❌ Static file performance

Nginx solves all these problems.


Production Architecture

User Browser
    ↓
    Nginx
    ↓
    Python App (systemd service)

Flow:

  1. User makes request
  2. Nginx receives it
  3. Static files served directly
  4. API forwarded to backend

Why use sites-available instead of nginx.conf?

Many beginners put everything in:

/etc/nginx/nginx.conf

This works but is not scalable.

Best practice:

/etc/nginx/
    ├── nginx.conf
    ├── sites-available/
    │   └── ABC
    └── sites-enabled/
        └── ABC

nginx.conf should contain only global settings:

http {
        include /etc/nginx/mime.types;
        include /etc/nginx/sites-enabled/*;
    }

Actual site config goes in:

/etc/nginx/sites-available/ABC
  • ✔ Clean
  • ✔ Organized
  • ✔ Scalable

Understanding Nginx proxy_pass

One of the most powerful features of Nginx is its ability to act as a reverse proxy using the proxy_pass directive.

Trailing Slash Behavior

With trailing slash

proxy_pass http://localhost:8080/;

Request:

/images/pic.png

Forwarded as:

http://localhost:8080/pic.png

👉 The /images/ part is replaced.

Without trailing slash

proxy_pass http://localhost:8080;

Forwarded as:

http://localhost:8080/images/pic.png

👉 The full URI is preserved.

Rule of Thumb

proxy_pass format Backend receives
with slash / Replaces location path
without slash Keeps full URI

Basic Reverse Proxy Configuration

server {
        listen 80;
        server_name your_domain.com www.your_domain.com;

        location / {
            proxy_pass http://localhost:8080;
            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;
        }
    }

Why These Headers Matter

  • ✔ Correct client info
  • ✔ Proper logging
  • ✔ Secure application logic

Reload vs Restart

Reload

systemctl reload nginx
  • ✔ Applies config changes
  • ✔ No downtime
  • ✔ Best for updates

Restart

systemctl restart nginx
  • ⛔ Stops service
  • ⛔ Starts again
  • ⛔ Brief downtime

Use only if reload fails.


Typical Production Workflow

git pull origin main
    systemctl restart ABC.service

Nginx config update:

nginx -t
    systemctl reload nginx

Conclusion

For deploying Python applications on Linux:

  • ✔ Use systemd for backend services
  • ✔ Use Nginx as reverse proxy
  • ✔ Use sites-available structure

This avoids:

  • ❌ Downtime
  • ❌ Security risks
  • ❌ Messy configs

And prepares your app for real-world scale.

Happy deploying 🚀