RBCloud & DevOpsTHE PRACTICAL LEARNING LIBRARY
By Ravindra BagaleResources

CHAPTER 24 / 60

Flask, Gunicorn, Express and reverse proxies

Apply the same web-server pattern to Python and Node.js applications.

Concept + practical labBy Ravindra Bagale · ~5 min read · lab time additional

Why and what

Nginx accepts public HTTP/TLS traffic and forwards application requests to a local process. Gunicorn is a Python WSGI server; Flask's development server is not the intended production process manager. Express runs inside Node.js and needs a managed lifecycle. A reverse proxy does not automatically make application code secure or highly available.

Flask lab on Ubuntu

bash
sudo apt install -y python3-venv
mkdir -p ~/academy/flask-demo
cd ~/academy/flask-demo
python3 -m venv .venv
. .venv/bin/activate
pip install flask gunicorn
cat > app.py <<'PY'
from flask import Flask
app = Flask(__name__)
@app.get('/')
def home():
    return {'message': 'Flask behind Nginx'}
PY
gunicorn --bind 127.0.0.1:8000 app:app

In another terminal run curl http://127.0.0.1:8000/. Pin reviewed dependency versions in a lock/requirements workflow for repeatability. On AL2023 install the corresponding Python/pip packages available in the selected repository and create the same venv.

Express equivalent

Using a supported Node.js LTS installation, create a separate project:

bash
mkdir -p ~/academy/express-demo
cd ~/academy/express-demo
npm init -y
npm install express
cat > app.js <<'JS'
const express = require('express');
const app = express();
app.get('/', (_req, res) => res.json({message:'Express behind Nginx'}));
app.listen(3000, '127.0.0.1');
JS
node app.js

Reverse-proxy block

nginx
location / {
    proxy_pass http://127.0.0.1:8000;
    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;
}

Use 3000 for Express. Configure application proxy trust only for known proxies; trusting arbitrary forwarded headers can let clients spoof scheme/IP information.

Service operation

Create a dedicated OS user and a systemd unit with WorkingDirectory, absolute ExecStart path, limited permissions and Restart=on-failure. Keep secrets outside the repository. Test syntax/reload Nginx, then test a reboot to prove the service starts without your SSH session.

Troubleshooting

A 502 may mean the app died or listens on a different port. Python import failures often mean wrong working directory/venv. Node failures may be dependency or syntax errors. Read application journal output before changing security groups.

Official references

Flask deployment Express production practices

Ravindra’s Tip

Browser में page दिखा इसलिए backend healthy है ऐसा मत मानो। API response और application logs भी check करो।

Interview and revision check

Why keep Gunicorn or Node behind a managed service?

A systemd-managed process can restart, log and survive SSH disconnects/reboots. An interactive shell process does not provide the same lifecycle.

Ravindra Bagale · Cloud & DevOps Academy · Handbook and project downloads