Scale up as you grow — whether you're running one virtual machine or ten thousand.

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Thanks for your complete and step by step tutorial :) If it is possible write a tutorial about what uWSGi or Enginx is and how they work?
Thanks :)
I understand if I have firstsite running on python2 and secondsite on python3 hence I need a different virtualenv for each site.
If I have two django apps using python2, do I still need to have ONE virtualenv per app?
Do you have an example for ubuntu 14.04 where instead of systemd, you have a script for upstart?
And only the firstsite works for me.
In my case firstsite is djangoonpy2 and secondsite is djangoonpy3
Hi. I’ve got a problem with this manual:
uwsgi.log:
Set PythonHome to /hedgehog/.virtualenv/hedgehog ImportError: No module named site
My settings:
/etc/uwsgi/sites/hedgehog.ini
[uwsgi]
project = hedgehog
username = hedgehog
base = /var/www/%(username)/code
chdir = /var/www/hedgehog/code
home = /%(username)/.virtualenv/%(username)
module = %(username).wsgi:application
master = true
processes = 5
uid = %(username)
socket = /run/uwsgi/%(project).sock
chown-socket = %(username):nginx
chmod-socket = 660
vacuum = true
logto = /var/www/%(username)/log/uwsgi.log
/etc/systemd/system/uwsgi.service
[Unit]
Description=uWSGI Emperor service
[Service]
ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown hedgehog:nginx /run/uwsgi'
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
[Install]
WantedBy=multi-user.target
The app is in /var/www/hedgehog/code.
Seems that uwsgi somehow doesn’t use the virtualenv. I’ve tried adding this to the ini file:
plugins = python
virtualenv = %(home)
It didn’t help.
An something more:
[rreimche@rreimche-web sites]$ sudo -u hedgehog -H bash -l
[sudo] password for rreimche:
[hedgehog@rreimche-web sites]$ python
Python 2.7.5 (default, Jun 24 2015, 00:41:19)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import site
>>> exit()
Could you please help me?
It’s really annoying that we get this 502 bad gateway issue because uwsgi is not created the socket file.
@jellingwood Please clarify what the correct permissions should be for this not to occur…
I followed this tutorial and getting error like :
nginx/1.6.3
Operating Environment and tools: Rhel 7.2 Django uwsgi nginx
my firstsite.ini
[uwsgi]
project = firstsite
username = ec2-user
base = /home/%(username)
chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application
master = true
processes = 5
uid = %(username)
socket = /run/uwsgi/%(project).sock
chown-socket = %(username):nginx
chmod-socket = 660
vacuum = true
uwsgi.service:
[Unit]
Description=uWSGI Emperor service
[Service]
ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown ec2-user:nginx /run/uwsgi'
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
[Install]
WantedBy=multi-user.target
nginx.conf :
#inside http block after existing server block
server {
listen 80;
server_name 52.32.66.190;
location = favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/ec2-user/firstsite;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/firstsite.sock;
}
}
Good Article. How do we enable WebSocket(ws:// or wss://) communication with the same configuration?
This comment is probably as long as the tutorial itself. But if you’ve been struggling to get yours working, you may find some relief here. That is my hope anyway.
I am migrating my website Phrancko.com from AWS to DO. I was using Apache and mod_wsgi at AWS but thought it would be nice to used Nginx and uwsgi instead at DO. I chose the Centos operating system because that’s the one I was most familiar with.
So I found this page and thought, “Oh boy, this is going to lead me right through setting it all up.” Unfortunately it turns out this document written in 2015 has not kept up with more recent developments. It took me 14 days of beating my head against the wall but I finally found all the answers I needed, including many that some of the commenters to this article have also needed. (Yes, literally 14 long and very frustrating days to get here!) Along the way I read many forums, including the comments right here, where people asked how to solve the same problems I was hitting, but then got no answers. If they did get answers, they were often incomplete, or just plain wrong.
Going into this, I knew I wanted a couple of differences in my environment that are not described in this article:
That didn’t seem like too much to ask for enhancing the environment. But I never had heard of this little thing to tighten permissions called selinux and its companion setsebool that the article never mentions. They turned out to be the keys to the most difficult issues that this article does not address. I didn’t even know to search for selinux so it took a long time to find it and even longer to realize that was the problem.
So as a public service I am documenting all that I found that finally produced a working Django, nginx, uwsgi, letsencrypt enviroment and will answer the following questions, and perhaps a few more that the article leaves out:
Using pipenv
This article tells you to is set up a virtual environment with virtualenv and virtualenvwrapper. Ignore all that and the additions to .bashrc and instead set up your virtual environment with pipenv, which is more advanced and easier to use than any alternatives to date. There are many good intro articles and YouTube videos showing how to get started with pipenv so I won’t give a tutorial here. However, what you do need to know is that once you have done that you should cd to your pipenv intialized project and execute:
pipenv --venv
The output shows the path to your virtual environment. Copy that path and use that path as your home value, both when executing uwsgi from the command line and for the home setting in your /etc/uwsgi/sites/example.ini file.
Setting up the Django project
Simply follow the instructions here. If you run across advice that you can rename your top-level project directory so you don’t have the structure /home/user/example_project/example_project/… DON’T DO IT. This article’s uwsgi.ini file depends on that duplicate name. (I bet you can guess how I found that out.) You’ll probably want to change the SQLite database to a more substantial production one later. That is beyond the scope of this article and my comments.
Initializing uwsgi
Believe it or not, the ini files for uwsgi.service and for uwsgi/sites/example.ini work as presented, except for replacing the value for ‘home’ with you pipenv virtual environment path. I say believe it or not, because in my frustration I tried all kinds of changes to both of these files, but once I solved the mysterious problems, I took out my changes one by one until I got all the way back to what is described in the this article.
You may have to change the location of the uwsgi executable also. I discovered mine was in /usr/local/bin so I also changed this line in the uwsgi.service file:
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
The only other change you should make is to add the following line to the end of the example.ini file:
daemonize = /var/log/uwsgi/uwsgi.log
That provides a log to look at when things don’t work out as planned. (One of the frustrations I had with this article was that it gave no guidance about what to do when things didn’t just work as described. And especially it didn’t tell how to log what uwsgi was doing so you could find out if it was working or why it was failing.)
This may be the point where I discovered the error in that log that told me my virtual environment directory did not exist. It turns out that if permissions are not right for some of these things, instead of giving a permissions error, it says the directory or file does not exist. Nevertheless, here’s the magic incantation that solves that problem and the later nginx problem accessing static and media files. I’m not quite sure when I discovered it but you should do it now rather than wait for some strange error. After much searching and much advice about changing the ownership and rwx permissions on my directory structure, all of which was necessary, but did not fix the problem, I found this advice buried in a forum somewhere. Just execute:
setsebool -P httpd_read_user_content 1
You don’t have to understand it, just do it and it solves a lot of issues. It allows processes to access files and directories in your user directories, which are prevented by a system “policy” if you haven’t done it.
Also, make sure you don’t miss these two commands in the article:
sudo usermod -a -G user nginx
chmod 710 /home/user
Install nginx
I installed letsencrypt (aka certbot) right after I installed nginx. I think I did things in the wrong order and I had to doctor the resulting nginx.conf file to move the certbot installed lines into the right place. I think if you set up nginx exactly as the article describes to run your website as a non-secured site on port 80, and THEN install letsencrypt that may not be necessary. But I’ll describe what I think did in case the same thing happens to you.
Install letsencrypt / certbot
Here’s the easy, peasy way. Just go here, click “Get certbot instructions,” and specify your server as nginx and your operating system (mine is Centos 8) and follow the instructions from there:
After you do that, check your nginx.conf and see if the certbot installed lines are working for your website or not. If they are in the wrong place in the file, you may have to move them to the right place to go with your host names. And you may have to remove ‘listen 80’ from that area as well. Anyway, mine now has the following structure which works:
server {
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
server_name example.com www.example.com;
. . .
And don’t forget to do the final step to keep the certificate updated:
echo "0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
This will call python from the root user. If root doesn’t know where python is, you may have to put a directory in front of python command. Mine looks like this:
0 0,12 * * * root /home/my-user/.local/bin/python -c 'import random; . . .
Finish installing nginx
Complete the rest of the instructions up to, but not including the systemctl enable commands. If you have executed the setsebool command above, then you should not have any trouble browsing to a static file in your project. If you didn’t do it before then do it now.
If it doesn’t work to browse to static files, you may have hit a problem I did not get. You can look for nginx errors here:
/var/log/nginx/error.log
And look for uwsgi errors here (assuming you added the daemonize statement to your wsgi project ini file.
/var/log/uwsgi/uwsgi.log
By the way, if you look at the top of your nginx.conf file you’ll see ‘user nginx;’ which tells you nginx runs as the user nginx, not www-data. Apparently nginx used to run as www-data or in other environments it still does. So if you spend any time searching forums for nginx help, you’ll see lots of people saying the nginx user is www-data. It isn’t. And you don’t need to create a www-data user and change it to that. (I know! I did that too during my head-to-wall banging period.)
If you browse to your website now, you will most likely get the dreaded ‘502 Bad Gateway’ error.
Check the logs. Fix whatever is required, if anything, to get uwsgi running without errors first. Make sure it produces the socket file and sets its ownership and permissions correctly.
Then see what errors occur in the nginx error.log file. If you’re lucky, it’s just the old socket permission denied error. Now we will fix that and you are done.
The solution I finally found was described as succinctly as possible here: https://axilleas.me/en/blog/2013/selinux-policy-for-nginx-and-gitlab-unix-socket-in-fedora-19/
You can read it all for a better understanding, or you can just ‘sudo su’ to become the root user and execute these commands:
yum install -y policycoreutils-{python,devel}
grep nginx /var/log/audit/audit.log | audit2allow -M nginx
semodule -i nginx.pp
usermod -a -G git nginx
chmod g+rx /home/git/
If you browse to your website now, you should be delighted to see the rocket ship default page of Django. I’m breaking out a bottle of champagne tonight to celebrate the success at the end of 14 long, frustrating days.
By the way, DO documentation has a lot about selinux, including a two part tutorial. But since I had never heard of it before, I did not find those until after all of this and then I specifically searched for selinux. There is no mention in those articles of the “502 Bad Gateway” error, or the socket permissions error, so searching DO documents for those things did not lead me to them.
I hope this helps it go better for you all.
Frank Jernigan
I made in a local VM to test. I do everything. The last step that I did is:
sudo systemctl start nginx
sudo systemctl start uwsgi
In the browser I try to access the URL: http://localhost/ or http://localhost/fistsite
I try too this link under, but result in a external site: www.firstsite.com
But everything that I try (localhost/anything) result in this:
502 Bad Gateway nginx/1.20.1
What is the link to test at localhost? Or, how I do a local test at localhost?