Krishnan's Personal Website


Home | About | Blog | Connect with me


Deploying and Hosting Flask Application on Ubuntu Server with Apache



Published On: Oct 04 2025
Written By: Krishnan Sethuraman
Category: Infrastructure


hosting flask application on ubuntu with apache

 

I recently started building AI applications for my startup and had to host a Flask application on my Ubuntu 18.04 server (yes I need to upgrade). This was my first Python application so I had to do a little bit of digging around to find out what was the best way to deploy and host a Flask application. 

Unfortunately a Flask application cannot be deployed and hosted like a Laravel application. An Apache module called WSGI is required. 

Flask does not have a strict folder structure like Laravel. This is both a positive and negative aspect. For the experienced developers it is convenient as they can design their own folder structure. But for the new ones like me it can be very confusing. 

So I have developed my own folder structure for my applications. I have committed this scaffolding to a Github repo. 

The entry point for my application is run.py. I have provided the run.py content below. 

# run.py

from app import create_app

app = create_app()

if __name__ == "__main__":
    app.run(port=5001, debug=True)

Each feature will act as an independent module. So feature1 will have its own folder and inside it will be its own routes.py and models.py files. The library or helper functions will be inside the utils folder. This will keep the source code a bit more manageable. Though I am not a big fan of this and might move towards Django, but for now it makes things manageable. 

diagram for file structure

As we will be using wsgi to host our application we must create a wsgi.py file on our Linux server with the following contents. The run.py is the entry point on localhost whereas wsgi.py is for the production environment. 

# wsgi.py

import sys
import os

from app import create_app   # adjust if your factory is different

sys.path.insert(0, os.path.dirname(__file__))

application = create_app()

 

Deploying the source code

I used Jenkins to deploy the aplication. However I was unable to automate the build process. So for now I have  restricted to checking out the source code from the master branch and then deploying it to the server with scp. The Jenkins does nothing more (I will figure out to automate this fully). I have provided my Jenkinsfile below. 

//Jenkinsfile

pipeline {
    agent any
    environment {
        REMOTE_HOST = credentials('SERVER_IP')
        REMOTE_USER = credentials('SERVER_JENKINS_USER')
        REMOTE_PASSWORD = credentials('SERVER_JENKINS_PASSWORD')
        REMOTE_DESTINATION = credentials('APPLICATION_PATH')
    }

    stages {

        stage('Deploy Files') {
            steps {
                script {
                    sh "sshpass -p ${REMOTE_PASSWORD} scp -r ${WORKSPACE}/* ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DESTINATION}"
                }
            }
        }


        stage('Clean Workspace') {
            steps {
                cleanWs()
            }
        }
    }
}

 

Hosting

I use Apache as my preferred web server as I understand Apache better than nginx. 

The first step is to deploy the source code from the repository to the server which we have achieved above. Once the latest source code is deployed the next step is to login into the server and run the following commands. 

 

Initial Setup

The first step would be to ensure all all prerequisites are met on the server. You can refer the following steps to setup the same. We have to enable certain modules in Apache. 

$ sudo apt update
$ sudo apt install python3-pip python3-venv libapache2-mod-wsgi-py3 -y
$ sudo a2enmod wsgi
$ sudo systemctl restart apache2
$ sudo a2enmod proxy
$ sudo a2enmod proxy_http
$ sudo systemctl restart apache2

 

Building the Flask application

With the code deployed and server configured we run the following commands to complete the build. Before doing so just ensure that the requirements.txt has gunicorn added to it. Gunicorn is mandatory to host Flask application on Ubuntu. It's the easiest, reliable and robust way to host a Flask application in production. 

$ cd /var/www/flask-application
$ python3.11 -m venv venv
$ source venv/bin/activate
$ pip install --upgrade pip
$ pip install -r requirements.txt

The Flask application is now ready to be fired up. 

 

Use systemd to run the application

The popular opinion here is to use something like supervisor to run the application. But I always prefer the build systemd in Linux. 

So I created systemd service to run the application forever. 

# /etc/systemd/system/flask-app.service

Add the following content to the flask-app.service and save it. 

[Unit]
Description=Gunicorn instance to serve flask API
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/flask-application
Environment="PATH=/var/www/flask-application/venv/bin"
ExecStart=/var/www/flask-application/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 wsgi:application

[Install]
WantedBy=multi-user.target

Now enable the systemd service. 

# systemctl daemon-reload
# systemctl start flask-app
# systemctl enable flask-app

By now we should have the Flask application up and running. We can test the same by checking the status of the systemd service. 

# systemctl status flask-app

Please note that for every deployment restarting the systemd service is mandatory. Else the systemd service will not recognize the new code changes. Running pip install is not mandatory unless there are new packages  aka modules added to the requirements.txt file. 

# systemctl restart flask-app

 

Configuring Apache virtual host

Once the  Flask application is up and running the next step is to create a virtual host in Apache so that we can access are application at a domain name like flask-app.example.com

# cp 000-default.conf flask-app.example.com.conf

In side the file add the following content and save and close the file. 

<VirtualHost *:80>
    ServerName flask-app.example.com

    # Ensure Apache proxies requests
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8000/
    ProxyPassReverse / http://127.0.0.1:8000/

    ErrorLog ${APACHE_LOG_DIR}/flask-app_error.log
    CustomLog ${APACHE_LOG_DIR}/flask-app_access.log combined
</VirtualHost>

Finally enable the new virtual host and restart Apache server. 

# a2ensite flask-app.example.com.conf
# systemctl restart apache2

You should now be able to open up your flask application at flask-app.example.com, assuming the DNS record has been created. 

 

Related Articles

 

Krishnan Sethuraman
Krishnan Sethuraman

Founder & CTO of Geedesk. Passionate about building software from scratch, launching SaaS products, and helping teams deliver enterprise-grade solutions.

Like what you are reading?

Discover more similar articles sent to your email

Subscribe to my newsletter