July 3, 2013

Beginner

How To Deploy a Flask Application on an Ubuntu VPS

What the Red Means

The lines that the user needs to enter or customize will be in red in this tutorial!

The rest should mostly be copy-and-pastable.

Introduction


Flask is a micro-framework written in Python and based on the Werkzeug and Jinja2 template engine for developing web applications. It is intended for developing web apps quickly.

Setup


You need to have Apache already installed and running on your VPS. If this is not the case, follow Step One of our article on installing a LAMP stack on Ubuntu.

Step One— Install and Enable mod_wsgi


WSGI (Web Server Gateway Interface) is an interface between web servers and web apps for python. Mod_wsgi is an Apache HTTP server mod that enables Apache to serve Flask applications.

Open terminal and type the following command to install mod_wsgi:
sudo apt-get install libapache2-mod-wsgi 

To enable mod_wsgi, run the following command:
sudo a2enmod wsgi 

Step Two – Creating a Flask App


In this step, we will create a flask app. We will place our app in the /var/www directory.

Use the following command to move to the /var/www directory:
cd /var/www 

Create the application directory structure using mkdir as shown. Replace "FlaskApp" with the name you would like to give your application. Create the initial directory FlaskApp by giving following command:
sudo mkdir FlaskApp

Move inside this directory using the following command:
cd FlaskApp

Create another directory FlaskApp by giving following command:
sudo mkdir FlaskApp

Then, move inside this directory and create two subdirectories named static and templates using the following commands:
cd FlaskApp
sudo mkdir static templates

Your directory structure should now look like this:
|----FlaskApp
|---------FlaskApp
|--------------static
|--------------templates

Now, create the __init__.py file that will contain the flask application logic.
sudo nano __init__.py 

Add following logic to the file:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello, I love Digital Ocean!"
if __name__ == "__main__":
    app.run()

Save and close the file.

Step Two – Install Flask


Setting up a virtual environment will keep the application and its dependencies isolated from the main system. Changes to it will not affect the cloud server's system configurations.

In this step, we will create a virtual environment for our flask application.

We will use pip to install virtualenv and Flask. If pip is not installed, install it on Ubuntu through apt-get.
sudo apt-get install python-pip 

If virtualenv is not installed, use pip to install it using following command:
sudo pip install virtualenv 

Give the following command (where venv is the name you would like to give your temporary environment):
sudo virtualenv venv

Now, install Flask in that environment by activating the virtual environment with the following command:
source venv/bin/activate 

Give this command to install Flask inside:
sudo pip install Flask 

Next, run the following command to test if the installation is successful and the app is running:
sudo python __init__.py 

It should display “Running on http://localhost:5000/” or "Running on http://127.0.0.1:5000/". If you see this message, you have successfully configured the app.

To deactivate the environment, give the following command:
deactivate

Step Three – Configure and Enable a New Virtual Host


Issue the following command in your terminal:
sudo nano /etc/apache2/sites-available/FlaskApp

Add the following lines of code to the file to configure the virtual host. Be sure to change the ServerName to your domain or cloud server's IP address:
<VirtualHost *:80>
		ServerName mywebsite.com
		ServerAdmin [email protected]
		WSGIScriptAlias / /var/www/FlaskApp/flaskapp.wsgi
		<Directory /var/www/FlaskApp/FlaskApp/>
			Order allow,deny
			Allow from all
		</Directory>
		Alias /static /var/www/FlaskApp/FlaskApp/static
		<Directory /var/www/FlaskApp/FlaskApp/static/>
			Order allow,deny
			Allow from all
		</Directory>
		ErrorLog ${APACHE_LOG_DIR}/error.log
		LogLevel warn
		CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Save and close the file.

Enable the virtual host with the following command:
sudo a2ensite FlaskApp

Step Four – Create the .wsgi File


Apache uses the .wsgi file to serve the Flask app. Move to the /var/www/FlaskApp directory and create a file named flaskapp.wsgi with following commands:
cd /var/www/FlaskApp
sudo nano flaskapp.wsgi 

Add the following lines of code to the flaskapp.wsgi file:
#!/usr/bin/python
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/FlaskApp/")

from FlaskApp import app as application
application.secret_key = 'Add your secret key'

Now your directory structure should look like this:
|--------FlaskApp
|----------------FlaskApp
|-----------------------static
|-----------------------templates
|-----------------------venv
|-----------------------__init__.py
|----------------flaskapp.wsgi

Step Five – Restart Apache


Restart Apache with the following command to apply the changes:
sudo service apache2 restart 

You may see a message similar to the following:
Could not reliably determine the VPS's fully qualified domain name, using 127.0.0.1 for ServerName 

This message is just a warning, and you will be able to access your virtual host without any further issues. To view your application, open your browser and navigate to the domain name or IP address that you entered in your virtual host configuration.

You have successfully deployed a flask application.

Article Submitted by: Kundan Singh

Share this Tutorial

Vote on Hacker News

Try this tutorial on an SSD cloud server.

Includes 512MB RAM, 20GB SSD Disk, and 1TB Transfer for $5/mo! Learn more

Create an account or login:

41 Comments

Write Tutorial
  • Gravatar apkech 9 months

    One can simply use tornado and will avoid apache and setting virtual hosts.

  • Gravatar garethprice 8 months

    I have followed this exactly, but instead of putting mywebsite.com i put flaskapp.myip in and tried going to http://flaskapp.myip. It came up with a "flaskapp.myip is unavailable or may not exist." error. What should I do?

  • Gravatar garethprice 8 months

    Okay, now I've got it to sort of work, but instead of it showing the "Hello I love Digital Ocean" message it just shows me a directory of my files... :/

  • Gravatar Kamal Nasser 8 months

    @garethprice: Disable Apache's default virtualhost:

    sudo a2dissite default
    Edit the virtualhost you created and set ServerName to e.g.
    		ServerName flaskapp.dev
    and restart Apache.
    sudo service apache2 restart
    Edit
    /etc/hosts
    on your computer and add this line to the bottom:
    1.2.3.4 flaskapp.dev
    Where 1.2.3.4 is your droplet's IP address. Save it and point your browser to http://flaskapp.dev - it should load your flask app properly.

  • Gravatar garethprice 8 months

    Thanks, Kamal. I'll give it a go. But what if I want others to be able to access it?

  • Gravatar Kamal Nasser 8 months

    @garethprice: I assumed you don't have a domain name since you set it to something.ip at first. If you own a domain name: - Follow this article to set up DNS records: https://www.digitalocean.com/community/articles/how-to-set-up-a-host-name-with-digitalocean - Set ServerName to your domain name and restart Apache

  • Gravatar garethprice 8 months

    Kamal, I set up a new droplet and followed this tutorial: https://www.digitalocean.com/community/articles/how-to-launch-your-site-on-a-new-ubuntu-12-04-server-with-lamp-sftp-and-dns I did what you suggested and all I get is my list of files still. I've copied exactly your FlaskApp demonstration. You can see them at: http://opendiscovery.co.uk/FlaskApp/... Sorry for being noobish.

  • Gravatar Kamal Nasser 8 months

    @garethprice: Try running the following commands:

    sudo a2dissite default
    sudo service apache2 restart
    Does that fix it?

  • Gravatar garethprice 8 months

    Yes, thank you! Last question: is there a way of getting the normal apache to load html/php files in the root dir, and wsgi to handle Flask in a subdir (as achieve through WSGIScriptAlias)?

  • Gravatar Kamal Nasser 8 months

    @garethprice: The recommended way of doing that is to have php/html in a separate directory and your flask app in another directory and not mixing both apps together. Create a separate virtualhost on a separate subdomain/domain for the php/html app.

  • Gravatar itsanjalirk 8 months

    Hi I have followed the exacts steps as recommended. All the print statements from apache to flaskapp.wsgi to __init__.py file gets printed. No error reported in apache-error log file From from FlaskApp import views also works fine as it prints the first line in views.py but when I type the url http://ip/hello in the browser and post I get 404. View.py #from FlaskApp import app app = Flask(__name__) @app.route("/hello") def hello(): return "Hello, World!" __init__.py from flask import Flask print "Importing 1" #app = Flask(__name__) app = Flask('FlaskApp') from FlaskApp import views Can you please guide on how to resolve

  • Gravatar Kamal Nasser 8 months

    @itsanjalirk: Please pastebin apache's config files.

  • Gravatar john 7 months

    Hi - What is the purpose of creating a FlaskApp directory inside another FlaskApp directory? Is it just for python package management? Couldn't you just have a main.py file inside one FlaskApp and then from main import app ?

  • Gravatar Kamal Nasser 7 months

    @john: It's so that you can create files such as .wsgi that do not belong to the app itself but are required to make it work. e.g. FlaskApp.wsgi is created in /var/www/FlaskApp

  • Gravatar ljernejcic 7 months

    I am getting an import error: ImportError: No module named flask Isn't the WSGI file supposed to activate the virtual environment we created or something?

  • Gravatar Kamal Nasser 7 months

    @ljernejcic:

    ImportError: No module named flask
    Flask isn't installed. Did you follow Step Two – Install Flask?

  • Gravatar newaccount 7 months

    Correct me if I'm wrong but you create a virtualenv and then promptly set up an app which doesn't use the virtualenv... right?

  • Gravatar brian.schiller 7 months

    This worked great for the simple Hello World example. I tried to adapt it to fit my own website, and it's no longer working. The browser says 500 Internal Error, which turns out to be an ImportError inside the apache logs. I think it's a different problem from ljernejcic because the ImportError is occurring on my own module. The apache error.log output is at http://pastebin.com/aRau7TwA. Thanks in advance for any ideas.

  • Gravatar Kamal Nasser 6 months

    @brian.schiller: That paste has been removed. Are you still experiencing this issue?

  • Gravatar ultrafaca 6 months

    I have used your above described configuration to set up my flask application and I'm experiencing following issue: Basic page (and every static page) is displayed with 404.html message. Only login page is displayed correctly. I did my site similarly as http://www.youtube.com/watch?v=jELLsj1KPNQ; tested on my own linux machine, with flask development server. It works. So, I have renamed main file (the one I called with application name to __init__.py, as described here. Structure looks like this: /myapp myappwhatever.wsgi /myapp __init__.py /templates --------- bunch of html files (with basic html ancestor and childs) /static --------- css module1.py module2.py module3.py And I made Apache2 and wsgi file according your description. And it does not work as supposed. Do you have any clue why? Thanks

  • Gravatar liweishow@gmailcom 6 months

    i think nginx + gunicorn very easy. i use flask deploy by them

  • Gravatar Kamal Nasser 6 months

    @ultrafaca: Are you still experiencing this issue? If so, what do you mean by 'does not work as supposed'?

  • Gravatar ultrafaca 6 months

    Hi Kamal. Still the same issue. My web page is pretty simple. I have links that are pointing to static pages and login page. After login additional links are displayed. My static pages are not displayed properly (they are all inside templates folder); my login link and additional links work fine. Just static pages part puzzles me. Thanks.

  • Gravatar dirk.swart 6 months

    Hi Kamal, I get: ======== It works! This is the default web page for this server. The web server software is running but no content has been added, yet. What step should I search for the problem at?

  • Gravatar Kamal Nasser 6 months

    @dirk.swart: Make sure you followed step 3 and replace mydomain.com with your domain name or your droplet's IP address.

  • Gravatar Kamal Nasser 6 months

    @ultrafaca: How are they not displayed properly? Does the content load? Make sure the paths to the CSS files are proper.

  • Gravatar dirk.swart 6 months

    @Kamal: Thanks for responding. I reran the commands and at command: sudo a2ensite FlaskApp and reloading apache I now get: * Reloading web server config apache2 /usr/sbin/apache2ctl: 87: ulimit: error setting limit (Operation not permitted) apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for Server Name httpd not running, trying to start (13)Permission denied: make_sock: could not bind to address 0.0.0.0:80 ....... etc I used my IP address in the file - Is there any special way I should enter it? With quotes? : instead of . separators?

  • Gravatar ultrafaca 6 months

    CSS is loaded. Homepage and other static pages are displayed in "sugar coated mode", which means following: Links and pictures are displayed, but content of the page is 404. That is done via decorator (in __init__.py) @app.errorhandler(404) def page_not_found(error): return flask.render_template('404.html'), 404 Now, the 404.html inherits from base.html basic html tags and CSS. In other module, I have following code: class Main(flask.views.MethodView): def get(self, page="index"): page+= ".html" if os.path.isfile("templates/" + page): return flask.render_template(page) else: flask.abort(404) I have checked whether the paths are correct via Python interactive mode and they are fine. Everything was working on flask development server. Have any idea where is the problem. Thanks

  • Gravatar Kamal Nasser 6 months

    @dirk.swart: Are you restarting apache as root? It seems like you're trying to restart it as an unprivileged user.

  • Gravatar dirk.swart 6 months

    @Kamal: I run: sudo service apache2 stop and then sudo service apache2 start. But things have got worse - service stopped overnight (don't know why) and now when I try to start it, it fails: * Starting web server apache2 apache2: Could not reliably determine the server's fully qualified domain name, Using 127.0.0.1 for ServerName Action 'start' failed. ??

  • Gravatar Kamal Nasser 6 months

    @dirk.swart: Check apache's error logs:

    tail /var/log/apache2/error.log
    What does that command output?

  • Gravatar pjvandehaar 6 months

    On Ubuntu 13.10 and Apache 2.4.6, my virtualhosts configuration in sites-available needed a ".conf" extension.

  • Gravatar jabba.laci 6 months

    How can you tell Apache to run this app. using the app.'s virtualenv? Because I have the impression that the setup described here uses the global python installation!

  • Gravatar Kamal Nasser 6 months

    @jabba.laci: I've never used mod_wsgi myself, but found this: https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/#using-a-virtualenv Please let me know if that helps.

  • Gravatar tonybrown67 5 months

    I am getting an import error: ImportError: No module named flask I followed the instructions to the letter

  • Gravatar Kamal Nasser 5 months

    @tonybrown67: Please see if the link I posted right above your comment helps.

  • Gravatar jc.espinoza27 3 months

    HI thanks for the great tutorial. I followed the setps and works great, my Flask app run in my server but when y update a file and upload through FTP the changues doesnt reflect on my browser. I had to reboot the server or apache to see my changues, and of course thats not a correct way to update the production server. Im need help cause i need a worflow to program my app in my computer and upload the changues to the production server without to touch or enter a any single line of code on my server. In know that i can use git to deploy my updates, but i have no idea to how to do that. Anyone can helpme?

  • Gravatar Kamal Nasser 3 months

    @jc.espinoza27: You will need to reload apache everytime you change a file. Unfortunately that's how it works.

    sudo service apache2 reload

  • Gravatar jc.espinoza27 3 months

    @Kamal In the site config file /etc/apache2/sites-aviable we can use the directive WSGIScriptReloading On for automatic reloading. Whenever something changes the .wsgi file, mod_wsgi will reload all the daemon processes. And i'm using Fabric and Dstribute to deploy my Flask app has packages

  • Gravatar Kamal Nasser 3 months

    @jc.espinoza27: Oh, I didn't know that. I stand corrected :)

  • Gravatar denisdpc about 1 month

    Hi. I'd like to deploy more than one flask app with the same IP. To do that, I created, inside the FlaskApp directory, the TestApp directory and did the same procedures showed in this tutorial for this new app. I created the TestApp: nano /etc/apache2/sites-available/TestApp Like this: ServerName mywebsite.com ServerAdmin [email protected] WSGIScriptAlias /testapp /var/www/FlaskApp/testapp.wsgi Order allow,deny Allow from all ErrorLog ${APACHE_LOG_DIR}/error.log LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined But when I try to access the app in address: http://my_ip/testapp, It can't be founded. If I replace the code above in /etc/apache2/sites-available/FlaskApp, I can run the TestApp using http://my_ip/testapp. So, I'd to know how could I run boths app's, ie, the FlaskApp and TestApp. Thanks.

Leave a Comment

Create an account or login:
Ajax-loader