Ravindra BagaleCourses & study guides

Chapter 10: Dynamic Website Hosting (PHP, Python, Node.js with MySQL)

10.6 Reverse proxy to the Python/Node app

In my sessions, students often ask: "Sir, my app runs on port 3000, why not just open 3000 in the security group?" Bagha — the reverse proxy gives you port 80/443, TLS, logging and protection, and keeps the app private on 127.0.0.1. That is how it is done in real companies.

Nginx reverse proxy (all OSes)

Save as /etc/nginx/conf.d/app.conf on AL2023/CentOS, or /etc/nginx/sites-available/app (plus symlink into sites-enabled and remove default) on Ubuntu. Use port 5000 for Flask or 3000 for Node.

server {
    listen 80;
    server_name YOUR_SERVER_NAME;          # public IP / domain  (Ubuntu: use "listen 80 default_server;" and "server_name _;")

    location / {
        proxy_pass http://127.0.0.1:3000;  # 5000 for Flask/Gunicorn
        proxy_http_version 1.1;
        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;
        proxy_set_header Upgrade           $http_upgrade;     # WebSocket support
        proxy_set_header Connection        "upgrade";
    }
}
sudo nginx -t && sudo service nginx reload
sudo setsebool -P httpd_can_network_connect 1     # CentOS Stream 9 only - otherwise 502 Bad Gateway

Apache reverse proxy

<VirtualHost *:80>
    ServerName mysite.local
    ProxyPreserveHost On
    ProxyPass        / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/
    ErrorLog  logs/app_error.log
    CustomLog logs/app_access.log combined
</VirtualHost>
  • AL2023 / CentOS: save as /etc/httpd/conf.d/app.conf (mod_proxy and mod_proxy_http are loaded by default), then sudo apachectl configtest && sudo service httpd reload. On CentOS also run sudo setsebool -P httpd_can_network_connect 1.
  • Ubuntu: save as /etc/apache2/sites-available/app.conf, change the log lines to ${APACHE_LOG_DIR}/app_error.log and ${APACHE_LOG_DIR}/app_access.log, then sudo a2enmod proxy proxy_http && sudo a2ensite app.conf && sudo a2dissite 000-default.conf && sudo service apache2 reload.

Ravindra Bagale's Tip

When you see 502 Bad Gateway, don't touch Nginx first. Run curl -I http://127.0.0.1:3000 (or 5000) on the server. If the app itself doesn't answer, the problem is the app — check pm2 logs or journalctl -u <service>. Fix the backend, and the 502 disappears automatically.