I couldn't find a good tutorial for setting up flask to work with gunicorn and nginx, so I decided to write some extremely simple steps to get your flask app to run on a (sub)domain. This tutorial won't go over advanced settings or running gunicorn as a daemon.
Gunicorn is a HTTP server, inspired by Ruby's Unicorn that works with different python web frameworks, and most importantly, is the simplest web server to get started using.
You should be using virtualenv
for your dependencies, but it's okay if you're not.
Let's first install gunicorn:
pip install gunicorn
(You may need to run the above command with sudo
, if you don't use virtualenv
.)
Let's see if gunicorn works with our flask setup. cd
into the directory containing your app, run:
gunicorn file:app -b 0.0.0.0:8000
This makes the server publicly available on all public IPs.
I have my files hosted on DigitalOcean (ref link), so I have a public IP for my server. Visiting http://my-public-ip:8000
should serve up your app correctly.
Nginx is a high performance server and reverse proxy. Reverse proxying means that when a visitor hits a website, nginx will retrieve webpages and other resources from multiple servers, and present it as if it came from the server itself. This allows you to have multiple, distributed servers to handle more visitors.
sudo apt-get install nginx
The nginx
service should automatically start. If it doesn't:
sudo service nginx start
When you visit http://your-public-ip
, you should now see the default nginx configuration (If you see this page, the nginx web server is successfully installed and working. Further configuration is required.)
Let's do some configuring.
cd
into /etc/nginx/sites-available
. You should see a file named default
. I modified my default
file to return 404
for all websites, instead of displaying the default nginx config.
contents of default
(optional):
server {
return 404;
}
Create a new file with the name of your (sub)domain that you want to host your project on: e.g. /etc/nginx/sites-available/hackit.edward.io
.
Here's the contents of a basic config for our Flask app. This should be in /etc/nginx/sites-available/my-domain.com
(my-domain.com
is a file, not a folder):
server {
listen 80;
server_name hackit.edward.io;
root /my/project/folder;
access_log /my/project/folder/access.log;
error_log /my/project/folder/error.log;
location / {
proxy_pass http://127.0.0.1:8000;
}
}
Make sure to modify the server_name
to point your own domain, and your root to your project and logs to wherever you want your logs to be stored.
Let's test our config to see if it has valid syntax: sudo nginx -t
. Hopefully the test should be successful.
Now we need to symlink our configuration file:
ln -s /etc/nginx/sites-available/my-domain.com /etc/nginx/sites-enabled/my-domain.com`
Now we need to reload nginx to make our new configuration active:
sudo service nginx reload
Try accessing your domain specified at server_name
. You should see your Flask app appear, congratulations! You've reached the end of the tutorial.
Some problems I've personally ran into while setting up my flask app with nginx and gunicorn: hopefully this will help you.
The gunicorn
command must be running at all times. You can keep it running by using nohup
:
nohup gunicorn myfile:app -b 0.0.0.0:8000
This allows gunicorn to run in the background, even if you exit your terminal session. However, if you reboot your server or if gunicorn runs into a problem, your web app may stop working.
The best way to run gunicorn is to run it as a daemon. I'll write a blog post about this in the future.
Nginx and apache2 cannot run at the same time on the same port. If you have trouble starting up nginx, make sure you don't have anything else binding to the 80
port.
Is the default nginx page not showing up?
Your domains might not be setup correctly. Check your NS records. Make sure your CNAME or A records for your domains are pointing to the right server.
Thanks to Brandon Wu for helping me with setup.