# Installing Flask on Ubuntu 24.04

Flask is a lightweight, open-source Python web framework for building web applications and APIs, offering routing, request handling, and Jinja2 templating out of the box while staying easy to extend. This guide installs Flask on Ubuntu 24.04 inside a Python virtual environment, builds a basic Flask application, and runs it in production behind Gunicorn and Nginx with HTTPS enabled via Let's Encrypt. By the end, you'll have a Flask application served over HTTPS through Nginx and managed as a systemd service, following Python web framework deployment practices documented in [**Vultr Docs**](https://docs.vultr.com/how-to-install-flask-on-ubuntu-24-04).

* * *

## 1\. Set Up the Flask Project Environment

Python and Pip come pre-installed on Ubuntu, and Flask works with any active Python version. Set up an isolated virtual environment before installing Flask.

**1\. Update the server's package index:**

```console
sudo apt update
```

**2\. Check the installed Python version:**

```console
python3 --version
```

If Python isn't installed, install it:

```console
sudo apt install python3 python3-pip -y
```

**3\. Check the installed Pip version:**

```console
pip --version
```

Output:

```plaintext
pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)
```

**4\. Install the** `venv` **Python virtual environment module:**

```console
sudo apt install python3-venv -y
```

**5\. Create a new directory for the Flask project:**

```console
mkdir flask_project
```

**6\. Switch to the Flask project directory:**

```console
cd flask_project
```

**7\. Create a new** `flaskenv` **virtual environment:**

```console
python3 -m venv flaskenv
```

This creates an isolated `flaskenv` environment for managing Python packages.

**8\. Activate the** `flaskenv` **virtual environment:**

```console
source flaskenv/bin/activate
```

Your shell prompt should change to reflect the active environment:

```console
(flaskenv) example_user@server:/flask_project$ 
```

## 2\. Install Flask on Ubuntu 24.04

**1\. Install Flask using Pip:**

```console
pip install flask
```

Output:

```plaintext
Collecting flask
  Downloading flask-3.1.0-py3-none-any.whl.metadata (2.7 kB)
Collecting Werkzeug>=3.1 (from flask)..........
  Downloading werkzeug-3.1.3-py3-none-any.whl.metadata (3.7 kB)
  Downloading MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.0 kB)........
Installing collected packages: MarkupSafe, itsdangerous, click, blinker, Werkzeug, Jinja2, flask
Successfully installed Jinja2-3.1.4 MarkupSafe-3.0.2 Werkzeug-3.1.3 blinker-1.9.0 click-8.1.7 flask-3.1.0 itsdangerous-2.2.0
```

To install Flask globally without a virtual environment, use this instead:

```console
pip install flask --user
```

**2\. Check the installed Flask version:**

```console
flask --version
```

Output:

```plaintext
Python 3.12.3
Flask 3.1.0
Werkzeug 3.1.3
```

## 3\. Create a Basic Flask Application

**1\. Create a new** `flask_app.py` **file using a text editor such as** `nano`**:**

```console
nano flask_app.py
```

**2\. Add the following contents to the file:**

```python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
```

Save and close the file. This application listens on port `5000` across all server interfaces (`0.0.0.0`) and returns "Hello World!" when accessed.

**3\. Allow connections to TCP port** `5000` **through the firewall:**

```console
sudo ufw allow 5000/tcp
```

**4\. Reload UFW to apply the changes:**

```console
sudo ufw reload
```

**5\. Run the application:**

```console
python3 flask_app.py
```

Output:

```plaintext
 * Serving Flask app 'flask_app'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://YOUR_SERVER_IP:5000
Press CTRL+C to quit
```

**6.** Access port `5000` using your server's IP address in a web browser:

```plaintext
http://SERVER-IP:5000
```

## 4\. Set Up Gunicorn as a System Service to Serve Flask Applications

Gunicorn is a Python WSGI server used to run Flask, Django, and FastAPI applications in production.

**1\. Install Gunicorn using Pip:**

```console
pip install gunicorn
```

Output:

```plaintext
Collecting gunicorn
  Downloading gunicorn-23.0.0-py3-none-any.whl.metadata (4.4 kB)
Collecting packaging (from gunicorn)
  Downloading packaging-24.2-py3-none-any.whl.metadata (3.2 kB)
Downloading gunicorn-23.0.0-py3-none-any.whl (85 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 85.0/85.0 kB 7.7 MB/s eta 0:00:00
Downloading packaging-24.2-py3-none-any.whl (65 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 65.5/65.5 kB 27.9 MB/s eta 0:00:00
Installing collected packages: packaging, gunicorn
Successfully installed gunicorn-23.0.0 packaging-24.2
```

**2\. Print your working directory and note the Flask project path:**

```console
pwd
```

Output should look similar to:

```plaintext
/home/linuxuser/flask_project
```

**3\. Create a new** `gunicorn_conf.py` **file:**

```console
sudo nano gunicorn_conf.py
```

**4.** Add the following configuration, replacing `/home/linuxuser/flask_project` with your actual project path:

```ini
from multiprocessing import cpu_count

# Socket Path
bind = 'unix:/home/linuxuser/flask_project/gunicorn.sock'

# Worker Options
workers = cpu_count() + 1
worker_class = 'uvicorn.workers.UvicornWorker'

# Logging Options
loglevel = 'debug'
accesslog = '/home/linuxuser/flask_project/access_log'
errorlog =  '/home/linuxuser/flask_project/error_log'
```

Save and close the file. This sets up a UNIX socket, dynamically allocates workers based on CPU cores, and logs debug-level messages.

**5\. Create a new** `flask_app.service` **systemd service file:**

```console
sudo nano /etc/systemd/system/flask_app.service
```

**6.** Add the following, replacing `linuxuser` with your actual user and `/home/linuxuser/flask_project` with your project path:

```ini
[Unit]
Description=Gunicorn instance to serve Flask application
After=network.target

[Service]
User=linuxuser
Group=www-data
WorkingDirectory=/home/linuxuser/flask_project
Environment="PATH=/home/linuxuser/flask_project/flaskenv/bin"
ExecStart=/home/linuxuser/flask_project/flaskenv/bin/gunicorn --workers 3 --bind unix:/home/linuxuser/flask_project/flask_app.sock flask_app:app

[Install]
WantedBy=multi-user.target
```

Save and close the file.

**7\. Reload the systemd daemon:**

```console
sudo systemctl daemon-reload
```

**8\. Enable the** `flask_app` **service to start at boot:**

```console
sudo systemctl enable flask_app
```

**9\. Start the** `flask_app` **service:**

```console
sudo systemctl start flask_app
```

**10\. Check the service status:**

```console
sudo systemctl status flask_app
```

Output:

```plaintext
● flask_app.service - Gunicorn instance to serve Flask application
     Loaded: loaded (/etc/systemd/system/flask_app.service; enabled; preset: enabled)
     Active: active (running) since Wed 2024-12-04 09:35:59 UTC; 17s ago
   Main PID: 15711 (gunicorn)................
```

**11.** Alternatively, run the Flask application directly with Gunicorn:

```console
gunicorn --bind 0.0.0.0:5000 flask_app:app
```

## 5\. Configure Nginx as a Reverse Proxy to Secure the Flask Application

**1\. Deactivate the** `flaskenv` **virtual environment:**

```console
deactivate
```

**2\. Install Nginx:**

```console
sudo apt install nginx -y
```

**3\. Create a new** `flask_app` **Nginx virtual host configuration:**

```console
sudo nano /etc/nginx/sites-available/flask_app
```

**4.** Add the following, replacing `flask.example.com` with your domain and `/home/linuxuser/flask_project` with your project path:

```nginx
server {
    listen 80;
    server_name flask.example.com;

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/linuxuser/flask_project/flask_app.sock;
    }
}
```

Save and close the file.

**5\. Link the configuration to** `sites-enabled` **to enable it:**

```console
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled
```

**6\. Test the Nginx configuration:**

```console
sudo nginx -t
```

Output:

```plaintext
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

**7\. Restart Nginx to apply the changes:**

```console
sudo systemctl restart nginx
```

**8\. Check the firewall status:**

```console
sudo ufw status
```

**9\. Remove the earlier port** `5000` **firewall rule:**

```console
sudo ufw delete allow 5000/tcp
```

**10\. Allow the** `Nginx Full` **profile to enable HTTP and HTTPS:**

```console
sudo ufw allow 'Nginx Full'
```

**11\. Reload UFW to apply the changes:**

```console
sudo ufw reload
```

**12.** Set your user's home directory permissions to `755` so Nginx can read it. Replace `linuxuser` with your actual user:

```console
sudo chmod 755 /home/linuxuser/
```

### Generate Trusted SSL Certificates

The Flask app currently serves plain HTTP, which is insecure. Use Let's Encrypt to generate a trusted SSL certificate.

**1\. Install the Certbot Let's Encrypt client via Snap:**

```console
sudo snap install --classic certbot
```

**2.** Generate a certificate for your domain, replacing `flask.example.com` and `user@example.com` with your actual domain and email:

```console
sudo certbot --nginx -d flask.example.com -m user@example.com --agree-tos
```

**3\. Verify that Certbot auto-renews the certificate:**

```console
sudo certbot renew --dry-run
```

Output should look similar to:

```plaintext
Account registered.
Simulating renewal of an existing certificate for flask.example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/flask.example.com\/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

**4\. Restart Nginx to apply the SSL configuration:**

```console
sudo systemctl restart nginx
```

**5.** Access your domain in a browser and confirm the Flask application loads over HTTPS:

```plaintext
https://flask.example.com
```

## 6\. Uninstall Flask on Ubuntu 24.04

**1\. Deactivate the virtual environment:**

```console
deactivate
```

**2\. Delete the Flask project directory:**

```console
rm -rf ~/flask_project
```

**3\. Uninstall Flask if it was installed globally:**

```console
pip uninstall Flask
```

## 7\. Troubleshooting

*   Check the Gunicorn logs for detailed errors:
    
    ```console
    journalctl -u flask_app.service -f
    ```
    
*   On a **502 Bad Gateway** error:
    
    *   Verify the Flask service is running:
        
        ```console
        sudo systemctl status flask_app
        ```
        
    *   Verify your user's home directory has at least `0755` permissions:
        
        ```console
        sudo chmod 755 /home/linuxuser/
        ```
        
    *   Check the Nginx error logs:
        
        ```console
        sudo tail -f /var/log/nginx/error.log
        ```
        
*   If the application doesn't return the expected output, double-check your configuration and restart the app.
    

## Next Steps

*   Swap the sample route for your real application logic and add additional endpoints.
    
*   Add monitoring and error tracking (e.g., Sentry, Prometheus) for production visibility.
    
*   Automate certificate renewal checks and set up log rotation for Gunicorn and Nginx.
    
*   Explore Flask extensions (Flask-SQLAlchemy, Flask-Migrate, Flask-Login) to expand functionality.
    

For the full guide with additional tips, visit the original article on [**Vultr Docs**](https://docs.vultr.com/how-to-install-flask-on-ubuntu-24-04).
