Build a Web Application using Flask and Docker

By Anurag Singh

Updated on Aug 05, 2024

Build a Web Application using Flask and Docker

In this tutorial, we'll explain how to Build a web application using Flask and Docker on Ubuntu 24.04. We'll create a basic Flask application, containerize it with Docker.

Flask is a lightweight and flexible Python web framework that allows developers to build web applications quickly and efficiently. Known for its simplicity and ease of use, Flask provides the essential components needed for web development without imposing any dependencies or project structure, making it highly adaptable to various project requirements.

Deploying a Flask application on Docker offers several benefits. Docker ensures consistency across different environments by containerizing the application with all its dependencies, eliminating the "it works on my machine" problem.

This containerization simplifies the deployment process, as Docker containers can run on any system that supports Docker, ensuring the application behaves the same everywhere. Additionally, Docker facilitates scalability by allowing multiple instances of the Flask application to run concurrently, managed by tools like Docker Compose or Kubernetes.

This setup improves the application's ability to handle increased traffic and enhances its resilience and reliability. Docker also streamlines the development workflow by enabling developers to quickly spin up and tear down isolated environments, making it easier to test changes and maintain the application.

Prerequisites

  • A Ubuntu 24.04 installed dedicated server or KVM VPS
  • Basic understanding of Python and Flask and Liunx commands.
  • A root user access or normal user with adminitrative privileges


Build a web application using Flask and Docker

Step 1: Setting Up the Flask Application

Create a project directory:

mkdir flask_docker
cd flask_docker

Step 2: Virtual Environment

We need to install Python enviornment package to create virtual enviornment.

Note: Here we are installing 3.12 version because in our server Python 3.12 installed. This may be different for your server. Please check the version of the Python and use the same version here.

sudo apt install python3.12-venv -y

now let's set up a virtual environment and activate it:

python3 -m venv venv
source venv/bin/activate

Step 3: Install Flask:

Execute following command to install Flask in the virtual environment.

pip install Flask

Create a file named app.py in the project directory with the following content:

nano app.py

Add following code:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello, Flask!'

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

Save and exit the file.

Step 3: Configure Firewall

We need to add HTTP and HTTPS ports in the firewall.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

Step 4: Dockerizing the Flask Application

In the project directory, create a file named Dockerfile with the following content:

nano Dockerfile

Add following content:

# Use the official Python image from the Docker Hub
FROM python:3.12-slim

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt .

# Install the dependencies
RUN pip install -r requirements.txt

# Copy the rest of the application code
COPY . .

# Expose the port the app runs on
EXPOSE 5000

# Define the command to run the app
CMD ["python", "app.py"]

Save and exit the file.

Create a requirements.txt file. In the project directory, create a file named requirements.txt and add the package we have installed in the virtual environment:

pip freeze > requirements.txt

Next, we'll install Docker. Following commands are copied from official website:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

To install the latest version, run:

sudo apt-get install docker-ce -y

Build the Docker image:

Run the following command to build the Docker image:

docker build -t flask_app .

Step 5: Generate SSL Certificate

Before proceeding further, we need to generate standalone SSL certificate using Certbot. We need the certificate path to add in the docker compose file.

sudo apt install certbot -y

Run the following command to obtain an SSL certificate:

Note: Replace your_domain with your domain.

sudo certbot certonly --standalone -d your_domain

After your execute above command it will provide the SSL certificate installed path. Copy SSL certificate saved path, we need it for next step to add in the nginx.conf file. It looks like:

Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your_domain/privkey.pem

Step 5: Setting Up Docker Compose

First, create an Nginx configuration file. In the project directory, create a directory named nginx and a file named nginx.conf inside it with the following content:

mkdir nginx && nano nginx/nginx.conf

Add following content:

user  nginx;
worker_processes  auto;



error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {

    upstream flask_app {
        server web:5000;
    }
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush     on;
    tcp_nodelay    on;
    keepalive_timeout  65;
    types_hash_max_size 2048;

    include /etc/nginx/conf.d/*.conf;

    server {
        listen 80;
        server_name yourdomain.com;

        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen 443 ssl;
      server_name yourdomain.com;

        ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

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

Note: 

  • Replace ssl_certificate and ssl_certificate_key path with your domain SSL certificate path that you have copied from last step.
  • Replace yourdomain.com with your domain name.

Save and exit the file.

Next, install Docker Compose using following command:

Download the latest version of Docker Compose:

sudo curl -L "https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")')/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Apply executable permissions to the binary:

sudo chmod +x /usr/local/bin/docker-compose

Verify the installation:

docker-compose --version

Docker Compose helps manage multi-container Docker applications. We'll use it to simplify the management of our Flask application.

Create a docker-compose.yml file:

nano docker-compose.yml

In the project directory, create a file named docker-compose.yml with the following content:

version: '3.9'
services:
  web:
    build: .
    container_name: flask_app
    ports:
      - "5000:5000"
  nginx:
    image: nginx:latest
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - /etc/letsencrypt:/etc/letsencrypt
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - web

Save and exit the file.

Run the application using Docker Compose:

Run the following command to start the application:

docker-compose up -d

Open your browser and go to https://your_domain. You should see "Hello, Flask!".

Troubleshooting

If you will face any issue with the Docker container, check the logs. Execute following command to check the logs:

docker logs -f --until=2s [Docker container name]

Conclusion

In this tutorial, we seen how to built a web application using Flask and Docker. We containerized the Flask application, used Docker Compose for easier management, and set up Nginx as a load balancer to distribute traffic among multiple instances. This setup ensures that the application can handle increased traffic and is easier to manage and deploy.