Set up a WSGI server
Flask comes with a built-in webserver, but which is only supposed to be used during development. Once you move your application into a production environment, you are strongly advised to use a production WSGI server. Here, we will use uwsgi as the WSGI server running on an nginx web server to host our app.
Install and setup nginx
At this point, your app should be deployed onto a dedicated machine (preferably Linux) as the configuration must match its setup. Execute these steps on the server machine before proceeding:
Deploy your application project onto the server machine (e.g. git clone)
Create a virtual environment for your application
This enables you to set up the configuration of your web server.
Hint
For actual production use, it is recommended to host from a Linux machine. For installation and usage on Windows, please follow the instructions on http://nginx.org/en/docs/windows.html
Let’s start by adding the uWSGI package to our requirements.txt file:
flask
uwsgi
Then we need to install and configure nginx on the server machine.
- Linux
$ sudo add-apt-repository ppa:nginx/stable $ sudo apt-get update && sudo apt-get upgrade $ sudo apt-get install nginx
macOS (Homebrew must be installed)
$ brew install nginx
An nginx server is able to host multiple applications while each must use a different port. In order to define the port an applications uses (among other settings), your application requires a configuration file for nginx.
But before creating it, we must tell nginx to use such config files, since by default it only knows about its default config.
Linux
On Linux, the default config should be removed, because future application should each be defined in a separate config file:
$ sudo rm /etc/nginx/sites-enabled/default
This default configuration extends the base configuration found at /etc/nginx/nginx.conf.
If you open it, you should find the line:
include /etc/nginx/sites-enabled/*;
which tells nginx to add all configurations files found within this directory. Don’t change it.
In case that line is not present, add it, save the file and restart nginx:
$ nginx /etc/init.d/nginx restart
macOS
On macOS, create a new directory, that will hold this application’s config file:
- macOS only:
$ mkdir /usr/local/etc/nginx/init.d
Open nginx’s default config and include your new config folder:
$ nano /usr/local/etc/nginx/nginx.conf
Go to the bottom of the file and add
include /usr/local/etc/nginx/init.d/*.conf;
before the last closing curly bracket, then save and close the file.
Restart the nginx server to apply your changes:
$ nginx -c /usr/local/etc/nginx/nginx.confor restart as brew service via
$ brew services start nginx
Hint
On macOS, Nginx uses the port 8080 as default. This might conflict with applications already running on that same port (e.g. some Java application). In order to change the default port, you need to adapt the default config.
$ nano /usr/local/etc/nginx/nginx.conf
Find the uncommented line
server {
listen 8080;
and change the port to your desired default port, then save and exit the file. Now, restart the nginx server with
$ brew services start nginx
Add a configuration to your application
Now create a nginx config file within your application’s root directory e.g. nginx.conf.
Insert the following content:
1server { 2 listen 1050; 3 server_name localhost; 4 charset utf-8; 5 client_max_body_size 75M; 6 location / { try_files @uri @mywebapp; } 7 location @mywebapp { 8 include uwsgi_params; 9 uwsgi_pass unix:/path/to/my/application/uwsgi.sock; 10 } 11}
Adapt the application name (here: mywebapp) in line 6 and 7 with a descriptive name. Also put in the path where your socket file should reside (e.g. put it to your project root directory).
The socket (line 9) is a service file that acts as the server’s endpoint for the network traffic of your Python application and is created when your application is launched on the server machine (i.e. when nginx is launched). Please note, that you need a valid path from your server machine.
The listen parameter (line 2) defines the port your application will use. It is recommended to use a free port anywhere within the range between 1024 and 32767. You can check all used ports by running these commands:
$ tail /etc/service
$ netstat -an | grep LISTEN
You can also check this list of common default ports.
It is recommended to use a separate launcher to run the app over the WSGI server. Create a new Python file
in the project’s root directory e.g. wsgi-runner.py and insert this content:
from mywebapp.mywebapp import app as application
if __name__ == "__main__":
application.run()
Adapt the module path where your Flask app instance is created (here: mywebapp.mywebapp).
Next up, create a uwsgi config file within your application’s root directory e.g. uwsgi.ini
and put in the following content:
1[uwsgi]
2# application's base folder
3base = /path/to/my/application/root/directory
4# change current directory to application base
5chdir = %(base)
6# python's module to import
7app = wsgi-runner
8module = %(app)
9# python interpreter root path (outside of bin/)
10home = /path/to/my/python/interpreter/or/venv
11pythonpath = %(base)
12# socket file's location
13socket = %(base)/%n.sock
14# permissions to socket file
15chmod-socket = 666
16# the variable that holds a flask application inside the module imported at line 6
17callable = application
18# location of log files
19logto = %(base)/log/uwsgi/%n.log
Adapt the base (line 3) and home (line 10) variables to your deployed application. Also adapt app runner script (line 7) to your launcher.
Now, once again deploy your current project state onto the server machine.
On the server machine, create the log directory structure defined in logto (line 22) including an empty uwsgi.log file.
To make nginx host our application, we need to supply the nginx.conf to your nginx configuration directory.
Since the config file is part of the project (hence, it might be changed in the future) the server machine should
stay within the project structure, we create a symlink for it:
macOS:
$ ln -s /path/to/my/application/nginx.conf /usr/local/etc/nginx/init.d/mywebapp.conf
Linux:
$ ln -s /path/to/my/application/nginx.conf /etc/nginx/sites-enabled/mywebapp.conf
Now, you are ready to launch the uWSGI server for your application on the server machine. First make sure, you activate your project’s virtual environment, then type:
(venv) $ uwsgi --ini /absolute/path/to/my/application/uwsgi.ini
This launches the uWSGI server using your project’s configuration. Now open a browser on your local
machine and type your server machines IP, colon and the port specified in nginx.conf (e.g. 10.180.2.75:1050)
into the address bar, which will open the index page of your application.
Manually start application on remote server (Linux)
Starting the uWSGI process commonly needs the command window to remain open. If it is closed, the application is also terminated.
To prevent that, the process must be detached from the shell instance. On Linux, you can achieve this by creating separate session via screen, which is not terminated when the console is closed.
Check, if your server already features screen by typing
$ screen -h
If that command is not available, install screen via
$ sudo apt-get install screen
Now open a new screen via
$ screen
A new screen is opened. Now you can start the uWSGI server (first activate the virtual environment):
(venv) $ uwsgi --ini /absolute/path/to/my/application/uwsgi.ini
To switch back to the original window, type Ctrl + A followed by a simple d (for detach). This does not close
the screen, which continues in the background, even after closing your terminal window.
Running screen -ls will list you all available screens. Each screen name starts with session ID (e.g. 32196).
To enter a specific screen (let’s say 32196.pts-10) , type
$ screen -r 32196
to resume a detached session. To kill a window, enter it, then type Ctrl + a followed by simple k, then confirm
with y. Alternatively, you may send a quit command while outside the screen (let’s say 32196.pts-10 again):
$ screen -XS 32196 quit
Automatically start application on system startup
macOS:
Copy the *.plist file into /Library/LaunchDaemons to start nginx as a brew service on startup:
$ sudo cp /usr/local/opt/nginx/*.plist /Library/LaunchDaemons
Linux:
coming later