Skip to content
Back to the blog

Host a Flask app on a VPS with Gunicorn and Nginx

Deploy a Python Flask application on a Linux VPS with a virtual environment, Gunicorn, systemd and Nginx, including secrets, HTTPS and backups.

  • Flask hosting
  • Flask VPS
  • Python
  • Gunicorn

If an AI coding tool produced a Flask app, getting a response from flask run on your laptop does not make it ready for public traffic. Flask is a WSGI application: production needs a WSGI server, an HTTP proxy and a secure configuration. The VPS is self-managed: it gives you operating-system access to build that stack and makes you responsible for updates, security, backups and recovery.

This walkthrough uses Debian or Ubuntu, Gunicorn and Nginx. Names such as hello, app and create_app are placeholders; replace them with your repository’s actual modules and objects. Do not run Flask’s development server or debugger in production.

1. Identify the application you need to run

Inspect the repository for requirements.txt or pyproject.toml, its entry module and, if present, an application factory such as create_app(). Record the required Python version and external services: database, object storage, jobs, email or APIs. Check whether the project also has a separate Node frontend; Gunicorn runs the Flask backend and does not build that frontend for you.

Test routes, forms, uploads and external calls locally. Review AI-generated code for debug=True, credentials committed to Git and configuration that only works with localhost. If your app uses a different dependency or service layout, adapt the steps below before deployment.

2. Prepare a VPS and a service account

Choose a Hostbrid VPS with Debian or Ubuntu compatible with your Python version. Connect over SSH, apply system updates and expose only the ports you need. Create a dedicated service account instead of running the application as root:

sudo apt update
sudo apt install git python3-venv nginx
sudo adduser --system --group --home /srv/flaskapp flaskapp

Clone the repository into /srv/flaskapp/current. For a private repository, use a read-only deploy key and protect its private key. Create a virtual environment and install the versions pinned by the project:

sudo -u flaskapp python3 -m venv /srv/flaskapp/venv
sudo -u flaskapp /srv/flaskapp/venv/bin/pip install -r /srv/flaskapp/current/requirements.txt

Declare gunicorn as a production dependency. Do not install application packages into the operating system’s global Python.

3. Set production configuration

Keep production variables outside Git in a restricted file such as /etc/flaskapp.env. Flask does not automatically turn every environment variable into an application setting: your code must read them. Generate a unique SECRET_KEY, configure database credentials and API keys, and avoid reusing development values. Never put secrets in browser JavaScript, HTML, images or logs.

Disable debug mode and restrict which host names the app accepts. If you use Flask 3.1 or later, review TRUSTED_HOSTS; on earlier versions, check the equivalent protections available to your version. The setting names and loading method depend on your application code.

Back up data before changing it. If the application uses SQLite, confirm where the database file lives and which user can write it. For higher traffic or multiple processes, assess a suitable database and document how to restore it. Keep user uploads separate from the code and define how they are retained and backed up.

4. Run Flask with Gunicorn and systemd

Test the import path first. Gunicorn uses module:object: a direct Flask instance could be hello:app, while a Flask factory could be hello:create_app(). Replace the example with your application’s real entry point:

cd /srv/flaskapp/current
sudo -u flaskapp /srv/flaskapp/venv/bin/gunicorn --bind 127.0.0.1:8000 'hello:create_app()'

After it works, use systemd to start the process on boot and restart it after a failure. Save this unit as /etc/systemd/system/flaskapp.service:

[Unit]
Description=Flask application
After=network.target

[Service]
User=flaskapp
Group=flaskapp
WorkingDirectory=/srv/flaskapp/current
EnvironmentFile=/etc/flaskapp.env
ExecStart=/srv/flaskapp/venv/bin/gunicorn --bind 127.0.0.1:8000 'hello:create_app()'
Restart=on-failure

[Install]
WantedBy=multi-user.target

Change the WSGI module and ensure systemd can read the environment file without exposing it to other users. Then run sudo systemctl daemon-reload, sudo systemctl enable --now flaskapp, and inspect sudo systemctl status flaskapp and journalctl -u flaskapp. Keep Gunicorn bound to 127.0.0.1; do not expose it directly to the internet when Nginx is in front.

5. Put Nginx, your domain and HTTPS in place

This starter Nginx block forwards requests to Gunicorn. Replace the domain and confirm the app listens on the configured port:

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

    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;
    }
}

Save it in your distribution’s site configuration directory, enable it, run sudo nginx -t and reload Nginx. Point the domain to the VPS, allow the required web traffic and issue a TLS certificate using a method supported by your system. Redirect HTTP to HTTPS before accepting credentials or sensitive data.

If Flask needs to know the original scheme or address, configure ProxyFix only when requests really pass through the proxy you control, and set the correct proxy count. Trusting forwarded headers without limiting that chain can let a client spoof values.

6. Test the live path and plan operations

From outside the VPS, test the homepage, deep routes, forms, sign-in, static files and uploads. Restart the service and verify it returns. Review logs for errors and accidental secret exposure. Confirm database and upload backups can be restored. If the app needs background jobs, configure and monitor those processes separately.

This path is for a Flask application you want to administer on Linux. Hostbrid provides a VPS with root access; you install and maintain Python, Flask, Gunicorn, Nginx, HTTPS, the firewall and backups. Compare VPS options and current prices against the app’s measured CPU, memory and disk use.

Implementation references: Flask’s official guidance for production deployment, Gunicorn, Nginx and ProxyFix.

Manage your sites, servers and email.

Forgot your password?

Free, and it takes a minute.

At least 8 characters. Not all digits, not a common one.

We'll email you to confirm the account.