Configuring a Systemd Service for a Flask Python Application in Production

Deploying a Flask application in a production environment necessitates a rigorous configuration to ensure both reliability and security. This guide elucidates the process of configuring a Flask application as a systemd service on a Linux server, utilizing Gunicorn as the production WSGI server, and establishing the necessary network configurations for external access.

Step 1: Environment Preparation and Installation

Begin by ensuring that your Flask application is properly deployed and that a virtual environment is established.

  1. Create a Virtual Environment:
    python3 -m venv /path/to/your/venv
    
  2. Activate the Virtual Environment:
    source /path/to/your/venv/bin/activate
    
  3. Install Flask and Gunicorn:
    pip install flask gunicorn
    

Step 2: Create and Configure the Systemd Service File

To deploy the Flask application as a service, a systemd service file must be created and appropriately configured:

  1. Create the Service File:
    sudo nano /etc/systemd/system/flask_app.service
    
  2. Define the Service Configuration:
    [Unit]
    Description=Flask Application
    After=network.target
    
    [Service]
    User=myuser
    WorkingDirectory=/path/to/your/flask_app
    ExecStart=/home/sergio/venv/bin/gunicorn -b 0.0.0.0:5000 api:app
    Restart=always
    Environment="PATH=/home/sergio/venv/bin"
    
    [Install]
    WantedBy=multi-user.target
    
    • Replace /home/sergio/venv with the appropriate path to your virtual environment.
    • Replace /path/to/your/flask_app with the correct path to your Flask application directory.
    • Replace api:app with the appropriate filename (api.py) and the Flask instance (app).
    • Replace myuser with the intended user account that should execute the service.

Step 3: Reload Systemd and Initiate the Service

  1. Reload the systemd daemon to incorporate the new service file:
    sudo systemctl daemon-reload
    
  2. Enable the Service to start automatically upon system boot:
    sudo systemctl enable flask_app.service
    
  3. Start the Flask Service:
    sudo systemctl start flask_app.service
    
  4. Verify Service Status to ensure proper operation:
    sudo systemctl status flask_app.service
    

Step 4: Configure Network Access

By default, Flask operates on port 5000. It is imperative to ensure that this port is open for external access.

Using UFW (Uncomplicated Firewall)

If ufw is used, execute the following command to open port 5000:

sudo ufw allow 5000

Using iptables

For iptables, allow incoming traffic on port 5000 using:

sudo iptables -A INPUT -p tcp --dport 5000 -j ACCEPT

Cloud Provider Security Groups

If your server is hosted by a cloud provider (e.g., AWS, Google Cloud, Azure), ensure that the security group or firewall settings permit incoming connections on port 5000.

Step 5: Add HTTPS Support

To add HTTPS support to your Flask application, you can use a reverse proxy server such as Nginx. Nginx will handle incoming HTTPS requests and forward them to your Flask application running Gunicorn.

Step 5.1: Install Nginx

First, install Nginx on your server:

sudo apt update
sudo apt install nginx

Step 5.2: Obtain an SSL Certificate

Use Let’s Encrypt to obtain a free SSL certificate. Install Certbot to manage the SSL certificates:

sudo apt install certbot python3-certbot-nginx

Step 5.3: Configure Nginx

Create an Nginx configuration file for your Flask application:

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

Add the following configuration to the file:

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

    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }
}
  • Replace your_domain.com and www.your_domain.com with your actual domain name.

Enable the configuration by creating a symbolic link to the sites-enabled directory:

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

Test the Nginx configuration:

sudo nginx -t

Reload Nginx to apply the changes:

sudo systemctl reload nginx

Step 5.4: Obtain SSL Certificate with Certbot

Run the following command to obtain and configure the SSL certificate:

sudo certbot --nginx -d your_domain.com -d www.your_domain.com

Follow the prompts to complete the certificate installation.

Step 5.5: Update Nginx Configuration for HTTPS

After obtaining the SSL certificate, Nginx will automatically update the configuration to redirect HTTP to HTTPS. The updated configuration will look like this: sudo nano /etc/nginx/sites-enabled/mywebsite

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name chat.abatecdigital.es;

    # SSL configuration
    ssl_certificate /etc/letsencrypt/live/chat.abatecdigital.es/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.abatecdigital.es/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Serve your website from /var/www/mysite at the root "/"
    root /home/sergio/mdrag/web_example;
    index index.html index.htm;

    # Location block for your main website at "/"
    location / {
        try_files $uri $uri/ =404;
    }

    # Location block for Streamlit app at "/app"
    location /app/ {
        proxy_pass http://127.0.0.1:8501/;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        rewrite ^/app/(.*) /$1 break;
    }

    # Location block for Streamlit app at "/app"
    location /api/ {
        proxy_pass http://127.0.0.1:5000/;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        rewrite ^/app/(.*) /$1 break;
    }
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name chat.abatecdigital.es;

    # Redirect all HTTP requests to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

Reload Nginx to apply the HTTPS configuration:

sudo systemctl reload nginx

Summary

This guide has provided a comprehensive overview of:

  1. Setting up a virtual environment for a Flask application.
  2. Creating a systemd service file to deploy the Flask application using Gunicorn in a production environment.
  3. Configuring network access to enable external connectivity via port 5000.
  4. Adding HTTPS support using Nginx as a reverse proxy and Let’s Encrypt for SSL certificates.

Using a production-ready WSGI server such as Gunicorn and configuring it with systemd ensures the Flask application remains reliable, restarts automatically in the event of a failure, and starts on system boot. For enhanced performance and security, the addition of Nginx as a reverse proxy with HTTPS ensures secure communication between clients and the server.