Let's say you are an ordinary developer, not a wizard at administrating the Apache server. You are looking for a place to host your side project, a Flask application (Flask is a Python web framework). To have the most control at only a small price, you provision a cloud server at your friendly cloud hosting company (Dreamhost, in my case). Perhaps you were not satisfied with free hosting sites, because they give you so little computing power that you quickly max out your available database connections. And so you decide to run it on your own server.

Just to be clear, this article does not deal with production-caliber Flask applications. It describes a minimal, very basic deployment options for simple applications such as your side projects or hobby projects. It does not address, for example, Python virtualenv. Maybe in the future.

Your newly-provisioned Ubuntu virtual server is a stark Unix machine with "nothing" on it. You have to install and configure everything yourself.

You want Flask to run with Apache web server, so first you install Apache. It's probably just something like this

sudo apt-get install apache2

Perhaps it gave you some vague message that hinted at Apache server being already installed. Maybe your newly-provisioned Ubuntu virtual server has a little more than "nothing" on it. Either way, you go to the http://your_servers_ip_address URL, and see the Apache welcome page.

Along the yay-this-machine-has-a-thing-or-two-preinstalled lines, you discover that there is already Python on this machine. It is Python 2, to be sure, but you decide not to look the gift horse in the mouth and stick to it for now. Why push your luck by installing Python 3, when you just want to get a simplest prototype of a Flask app to work? It's not like your app does a whole lot more than "Hello World".

And now you are ready, with trepidation, to configure your Flask app for Apache. You heard that what enables it to run under Apache is some thingamabob called WSGI, but you are not sure what it is or which fork to eat it with. Various configuration guides tell you to install mod_wsgi module for Apache first. You do that... and you probably get a message that modern Apache servers come with mod_wsgi already preinstalled and you don't have to do anything. In any case, after your attempt, your Apache seems to be well-supplied with mod_wsgi.

Googling leads you to a few documents that talk about how to configure Flask for Apache with mod_wsgi. You set out to follow them, and then you realize that while they talk about Apache configuration files, they don't really say what those files are called and where they are located. Googling for this gives you self-contradictory information, and you get an impression that on different Unix distributions these files have different names and are located in different places.

Exploring /etc/apache2 on your server, you stumble upon a directory called sites-enabled, and notice that it has a file 000-default.conf. Ah, a .conf file! Might this be a configuration file you need? You open it, and notice that some lines in it suspiciously resemble those mentioned in the online articles. So you decide that as a first shot, you'll take a stab at this file.

And that turns out to be a good guess. You first go through this tutorial: mod_wsgi Quick Configuration Guide. It's the Hello World of the mod_wsgi configuration. It doesn't talk about Flask specifically, but that doesn't matter. It gives you the proverbial foot in the door. It sheds light on where to stuff various files of your Flask application, and what magical incantations to write in the .conf file so Apache would recognize them. I heartily recommend going through this tutorial if you are new to WSGI, at least up to "Delegation To Daemon Process" chapter.

After you have done so, you can start applying the directions in the article above to your Flask app.

First, where do we deploy it? While you can deploy it to the Apache web root directory, /var/www/html/, it is recommended to deploy it to a directory outside the web root. So let's pick a location outside the web root -- for example, /usr/local/www/. The directory where your application will reside will be /usr/local/www/your-app-name. That's the directory where you'll put the your-app-name.wsgi file.

Also let's say that the name of the file of your actual Flask application (it's probably small enough to be just one file, right? If not, that's OK. Mine spans several files and two directories) is your-app-name.py . Mine is called, predictably, flask_app.py. So, the your-app-name.wsgi file will contain this line:

from your-app-name import app as application

e.g.

from flask_app import app as application

Now a question arises, where will we put the flask_app.py (or in your case, your-app-name.py) itself? While you can probably put it in the same directory as your-app-name.wsgi, maybe for the sake of neatness you want to introduce additional directory structure here. Perhaps you would like to create a directory /usr/local/www/your-app-name/web and put the your-app-name.py file in it. So now it is one directory below the .wsgi file. I did it that way. Why? Because it conceptually "isolates" the Flask app files, separating them from the your-app-name.wsgi file. The latter is required specifically for running your app on an Apache server. But your Flask app could run on other servers in other environments, including shared hosting environments such as PythonAnywhere, and they have their own your-app-name.wsgi files. In a sense, the your-app-name.wsgi file is separate from your application.

And if you put the your-app-name.py file in the /usr/local/www/your-app-name/web directory, you will need to add additional directories to your path, so that the your-app-name.wsgi file would know where to find your app. So your-app-name.wsgi now may look like this:

Now that we have "deployed" (for certain values of "deployed" -- we are not referring to automated deployments here) our Flask app, we need to tell Apache where to look for it. We'll do that in the aforementioned 000-default.conf file (this is specific to Apache on Ubuntu; Apache configuration files may be called something different on other Linux distributions). Under the

DocumentRoot /var/www/html

line, it has some commented-out code and explanations, and under that you can add a line for your Flask app configuration.

You probably want your Flask app URL to be something like your-domain-name.com/your-app-name ? Then let's add a line like this:

(Googling the topic of setting directory access might lead you to articles that show outdated Apache directives. But this Stack Overflow article will set you straight.)

To summarize, this article described how to set up a Flask application to run under Apache web server in a simplest possible configuration (without taking into account things like Python virtual environments).

Dealing with static files

Suppose you don't use the templating engine (Jinja), provided by Flask, because you want to create your own frontend app with HTML, CSS and Javascript (possibly with some Javascript framework). You only want to use Flask for the backend. Flask lets you do that, but the default way might prove non-ideal. By default, you would put all your frontend files -- all the HTML, CSS, and Javascript files -- in a static directory at the same path as the flask application file (flask_app.py in my case). At least that's what the Flask documentation says in its static files page.

But that means the user would have to access your frontend by putting "static" in the URL, like this:

sc.com/static/index.html

That would be awkward. We want to make it so that sc.com/sc would go directly to our website, without any need for a long URL. Turns out there is some magic that lets you do it. In your main application file (in my case flask_app.py) you need to instantiate the Flask application like this:

app = Flask(__name__, static_url_path='')

It tells flask that the path to the static files should be an empty string, in other words that the static files "appear" to be at the same URL as the application module URL. So now, even though your static files will still be in the "static" directory, the URL for serving them will be the same as your application root URL, i. e. sc.com/sc.

And, assuming that the main HTML file of your application is index.html, you probably want to configure the application in such a way that the URL sc.com/sc would lead the user to sc.com/sc/index.html, instead of the user having to type in the latter manually. To achieve this, you can create this route in flask_app.py:/

@app.route('/')
def root():
return app.send_static_file('index.html')

So now, when the user enters sc.com/sc in the browser URL bar, they will get the index.html page, but the browser's URL won't change.