(DJANGO - NginX + Unicorn) Deployment not properly working - django

I'm trying to put my django app online on a VPS. I tried following several different tutorials but I could not get it to work...
WHAT I'VE ACHIEVED ALREADY :
I got DJANGO's DevServ running on my VPS and I was able to browse my app using the VPS' IP address (the static files didn't correctly show up, error 404 104, and I only saw the HTML content without background/css or anything else).
I got NGINX running on my VPS and I was able to browse to its' default homepage (gunicorn was running at the time but the requests didn't get properly forwarded from NGINX to GUNICORN I believe).
I got GUNICORN running my app on my VPS with the command below.
Here's how I launch GUNICORN :
gunicorn MySite.wsgi:application
[2017-03-12 08:54:47 +0000] [1054] [INFO] Starting gunicorn 19.7.0
[2017-03-12 08:54:47 +0000] [1054] [INFO] Listening at: http://127.0.0.1:8000 (1054)
[2017-03-12 08:54:47 +0000] [1054] [INFO] Using worker: sync
[2017-03-12 08:54:47 +0000] [1059] [INFO] Booting worker with pid: 1059
And here is my NGINX configuration file which I named to match my domain name without the ".eu" (even though right now I'm trying to get it to work with the actual IP address, could this be the issue ?). I placed it in "/etc/nginx/sites-available" and made a symlink to the file in "/etc/nginx/sites-enabled" just like the tutorials said to:
#IP has been added to ALLOWED_HOSTS in settings.py
server {
listen 80;
server_name xxx.xxx.xx.xx;
charset utf-8;
access_log /var/log/nginx/MySite.access.log;
error_log /var/log/nginx/MySite.error.log;
#/static/ location as per my configuration and after running "manage.py collectstatic"
location /static/ {
alias /home/EveSite/static/;
}
# Forward HTTP requests to GUNICORN
location / {
proxy_pass http://127.0.0.1:8000;
}
}
I'm also having trouble linking my domain name to my VPS' IP but I will leave that for another question.
According to the tutorials I read, everything should be working now but I can only see NGINX's default homepage, no sign of my Django app altho GUNICORN says it is running.
Is there anything I am doing wrong here ? I know I'm probably missing something obvious.

Related

Django Deployment with nginx - gunicorn from another server

I'm trying to deploy my Django Project through different application server : Apache2, Nginx/gunicorn, ...
It works fine with Apache2 or Nginx, but I would like to dissociate these application server with my Django Projet. I would like to get an environment like this :
Server 1 (172.30.10.92) : Django Project & wsgi
Server 2 (172.30.10.93) : Nginx/gunicorn
Why ? Because later I will have some Django applications, but I would like to use just one application server.
I think I'm making a mistake with my configuration files syntax.
I have in /etc/nginx/sites-available/DatasystemsCORE.conf :
server {
listen 8000;
server_name 172.30.10.92;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root http://172.30.10.92:/var/www/html/;
}
location / {
include proxy_params;
proxy_pass http://172.30.10.92/unix:/var/www/html/DatasystemsCORE/dscore.sock;
}
}
server_name : Is it IP adress from Django server or nginx server ? I think it's the first one but I'm not sure.
proxy_pass : I think there is an issue in my path
Then, I'm executing this command :
gunicorn --daemon --workers 3 --bind 172.30.10.92/unix:/var/www/html/DatasystemsCORE/dscore.sock 172.30.10.92:/var/www/html/DatasystemsCORE/DatasystemsCORE.wsgi
One more time, I thing there is a syntax problem because I'm getting 502 Bad Request
How I can add IP address from a distant Django server there ?
Thank you !
I found How to solve my issue and I made a tutorial (based on my case) in order to help everyone who would like to make the same thing.
My file is there : Download tutorial file
But this is the same tutorial written in English.
My Django IP server : 172.30.10.92
My Nginx IP server : 172.30.10.93
1- Install and Configure wsgi (located on Django server)
WSGI is a file created with your Django project.
The file is located in /path/to/your/project/Myproject/wsgi.py
We have to edit this file like this :
import os
from django.core.wsgi import get_wsgi_application
import sys sys.path.append('/var/www/html/Myproject')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Myproject.settings")
application = get_wsgi_application()
2- Install and Configure gunicorn/supervisor (located on Django server)
In order to install gunicorn/supervisor, you have to execute in your shell :
pip install gunicorn
pip install supervisor
Then, you have to create a new file in /etc/supervisor/conf.d/Myproject.conf which looks like this :
[program:Myproject]
command = /home/valentin/.virtualenvs/MyprojectEnv/bin/gunicorn Myproject.wsgi:application --name "Myproject" --workers=4 --bind=0.0.0.0:8080 -- user="valentin" --group="valentin" ; Command to start app
user = username #You have to replace by your username
stdout_logfile = /var/log/supervisor/supervisor.log
redirect_stderr = true
log
environment=LANG=fr_FR.UTF-8,LC_ALL=fr_FR.UTF-8
I specified port 8080 which is the communication port between my application server and my web server.
3- Edit hosts file on nginx server (located on nginx server)
You have to edit your hosts file located to /etc/hosts and add a new entry to your Django server :
127.0.0.1 localhost
127.0.1.1 valentin
172.30.10.92 Myproject
# The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
4- New config file in nginx repository (located on nginx server)
This new file should be placed in /etc/nginx/sites-available/Myproject.conf
server {
listen 8080;
server_name Myproject;
root /var/www/html/Myproject/;
location /static/ {
root /var/www/html/;
}
location / {
include proxy_params;
proxy_pass http://172.30.10.92:8080;
}
}
The IP address corresponds to my Django server address. I specified the listen port (8080), the path to my Django project & static directory.
Then, you have to create a symbolic link to sites-enabled.
After ths operation, restart nginx service :
sudo service nginx restart
5- Allow nginx IP address in Django (located on Django server)
You have to edit your settings.py file in order to allow nginx IP address in ALLOWED_HOSTS :
ALLOWED_HOSTS = ['localhost', '172.30.10.93', '127.0.0.1', '[::1]']
6- Finally execute gunicorn (located on Django server)
Finally, you have to start gunicorn. You should be inside your Django root project and execute :
gunicorn Myproject.wsgi:application --bind 172.30.10.92:8080
Now, in your browser, try to connect to your nginx server with the port :
http://172.30.10.93:8080
It works !
PS : This tutorial works for me, if it doesn't work for you, maybe I missed something, or maybe you didn't make exactly like me ;)
What you're trying to do doesn't make any sense. You can certainly use a single nginx on a separate server, but gunicorn is the application server and belongs with the application.
There is no "Django server" so your first question is irrelevant. gunicorn will need to serve on a port, not a socket, and the nginx proxy_pass will point to that port.

my nginx cannot load uwsgi on Ubuntu 16.04

trying to run django app "mysite" through uwsgi with nginx on Ubuntu 16.04, but when I start uwsgi and check in my browser, it just hangs.
i set django upstream socket to on port 8002 and nginx to listen on 8003. In the browser i visit 192.168.0.17:8003 prior to running uwsgi and it throws 502 which is expected, so I start uwsgi with
uwsgi --http :8002 --module mysite.wsgi --logto /tmp/uwsgi.log --master
and 8003 now hangs when I reload in the browser. I looked through /var/log/nginx/error.log but it's blank (so is access.log).
Here is nginx config, which is symlinked to /etc/nginx/sites-enabled:
sudo nano /etc/nginx/sites-available/mysite_nginx.conf
# mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
# server unix:///path/to/your/mysite/mysite.sock; # for a file socket
server 127.0.0.1:8002; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on
listen 8003;
# the domain name it will serve for
server_name 192.168.0.17; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias /home/myusername/uwsgi-tutorial/mysite/media; # your Django project's media files - amend as required
}
location /static {
alias /home/myusername/uwsgi-tutorial/mysite/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/myusername/uwsgi-tutorial/mysite/uwsgi_params; # the uwsgi_params file you installed
}
}
I know that Django is running because in my app's settings.py I have ALLOWED_HOSTS = ['192.168.0.17','localhost','127.0.0.1'] and when I visit port 8002 in the browser I get the django "Congratulations!" page. And when I remove 192.168.0.17 from ALLOWED_HOSTS, django still runs on that machine from localhost or 127.0.0.1, so this seems that it must be something to do with how ngnix and uwsgi are talking to each other.
Any ideas??
It turns out systemd does not like lines in config files to be too long. I removed a couple long comments in /etc/systemd/system/uwsgi.service, restarted uwgsi service and all is well.
I found this out by running sudo journalctl -u uwsgi and finding the following error:
[/etc/systemd/system/uwsgi.service:5] Unbalanced quoting, ignoring: "/bin/bash -c 'mkdir -p /run/uwsgi; chown myusername:myusern
In researching Unbalanced quoting, found this git issue regarding maximum file line length.

502 Bad Gateway Using Nginx, Gunicorn and Flask

I'm learning to deploy my Flask app onto an Ubuntu AWS EC2 instance and am following the Digital Ocean tutorial. I'm and am encountering one final issue: I'm got my Gunicorn booted up and working using this command: gunicorn --workers 3 --bind unix:project.sock -m 007 wsgi:app to create 3 worker threads and a socket called project.sock.
[2018-02-23 17:14:49 +0000] [INFO] Booting worker with pid: X
[2018-02-23 17:14:49 +0000] [INFO] Booting worker with pid: X
[2018-02-23 17:14:49 +0000] [INFO] Booting worker with pid: X
Connection initialized.
Connection initialized.
Connection initialized.
But I'm encountering errors when attempting to have Nginx connect to my project.sock from Gunicorn- a 502 Bad Gateway error.
Here's my /etc/nginx/sites-available/project configurations:
server {
listen 80;
server_name MY_SERVER_DNS;
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/flaskapp_dev/my_project/project.sock;
}
}
A check of the Nginx error logs shows that it's getting a Permission denied error attempting to connect to my project.sock:
2018/02/23 17:26:46 [crit] 10822#10822: *4 connect() to unix:/home/ubuntu/myproject/myproject/myproject.sock failed
(13: Permission denied) while connecting to upstream,
client: CLIENT_IP, server: MY_SERVER_DNS,
request: "GET / HTTP/1.1",
upstream: "http://unix:/home/ubuntu/myproject/myproject/project.sock:/", host: "MY_SERVER_DNS"
I know there's been plenty of SO posts on this question, but I'm noticing that most of them revolve around uwsgi, which I'm not using here. I suspect that it's obviously a permission issue, so I tried chmod 711 /home/ubuntu/myproject/project and restarting nginx, but that results in the same 502 Bad Gateway error.
The closest SO post to my issue appears to be this one, but it has no answers or comments.
This is just a permissions issue. Nginx that's running under one user cannot get access to unix socket that's owned by another user. I recommend to run nginx server and gunicorn under the same user so unix socket created by gunicron will be accessed by nginx without any problems. chmod 777 is a temporal solution that can show that there is only permission issue if after executing this command the described problem has gone, but it's better to initially run nginx and gunicorn under the same user. Also it's better to specify full path to unix socket to avoid "no such file or directory" possible issue: gunicorn --workers 3 --bind <full_path_to_unix_socket_to_be_created>

Invalid address when startup gunicorn

I encounterd an error when bound gunicorn listen address to my nginx server,here is the thing:
1.gunicorn_wsgi.py
import multiprocessing
bind="192.168.239.145:8080"(my nginx server ip address)
workers = multiprocessing.cpu_count() 2 + 1
2.nginx.conf
http{
upstream realservers{
server 192.168.239.146:8080;(my django and gunicorn address)
}
servr{
listen 80;
server_name example.com
location / {
proxy_pass http://realservers
}
}
}
when i ran gunicorn -c gunicorn-wsgi.py myproject.wsgi,error occur:
[2015-03-30 04:56:05 -0700] [38656] [INFO] Starting gunicorn 19.3.0
[2015-03-30 04:56:05 -0700] [38656] [ERROR] Invalid address: ('192.168.239.145', 8080)
I noticed that gunicorn has mentioned that if you are running nginx on a different host than gunicorn you need to tell gunicorn to trust the the x-forward-* headers sent by nginx.
If you are running Nginx on a different host than Gunicorn you need to
tell Gunicorn to trust the X-Forwarded-* headers sent by Nginx. By
default, Gunicorn will only trust these headers if the connection
comes from localhost. This is to prevent a malicious client from
forging these headers:
gunicorn -w 3 --forwarded-allow-ips="10.170.3.217,10.170.3.220" test:app
I followed what it said ,but still same error. And I change the address to 127.0.0.1 and 0.0.0.0 ,they work fine,but is not secure,How to configure it ,please help me !
It's obviously not your problem, but it is confusing that you're calling your configuration file "gunicon_wsgi.py". It's not your WSGI file. Call it "gunicorn_conf.py" or something similar.
Your problem is however that you have misunderstood what it means to bind to an IP address. You can't bind your gunicorn server to an IP address on a different machine; that makes no sense at all. And it's not "insecure" to bind to 0.0.0.0.

Can't reach Django default app via Gunicorn on AWS EC2 instance

I've been struggling with this problem for two days without success. I've created an instance of the default Django (1.6.1) app called "testdj", installed it on an Amazon AWS EC2 t1.micro instance running Ubuntu Server 13.10, and I'm trying to reach the default Django "It worked!" page via Gunicorn (v. 18). When I start gunicorn from the command line:
gunicorn testdj.wsgi:application --bind [ec2-public-dns]:8001
I can see the page when I enter this URL:
http://[ec2-public-dns]:8001
However, if I use a "start-gunicorn" bash script I created after reading Karzynski's blogpost "Setting Up Django with Nginx, Gunicorn, virtualenv, supervisor, and PostgreSQL", I always get an error. When I enter this URL...
http://[ec2-public-dns]
... I get this error:
Error 502 - Bad Request
The server could not resolve your request for uri: http://[ec2-public-dns]
Here is the start-gunicorn script:
#!/bin/bash
NAME="testdj"
DJANGODIR=/usr/share/nginx/html/testdj
SOCKFILE=/usr/share/nginx/html/testdj/run/gunicorn.sock
USER=testdj
GROUP=testdj
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE=testdj.settings
DJANGO_WSGI_MODULE=testdj.wsgi
WORKON_HOME=/home/testdj/venv
source `which virtualenvwrapper.sh`
workon $NAME
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGO_DIR:$PYTHONPATH
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \
--user=$USER --group=$GROUP \
--access-logfile /tmp/gunicorn-access.log \
--error-logfile /tmp/gunicorn-error.log \
--log-level=debug \
--bind=unix:$SOCKFILE
As you can see, I've created a special account on my server called "testdj" to run the app under. I'm running my Django app in a virtual environment. I haven't changed the Django wsgi.py file at all. As I eventually want to use nginx as my reverse proxy, I've installed nginx and put the Django app in nginx's default root directory /usr/share/nginx/html. User/group www-data owns /usr/share/nginx and everything below except that user/group "testdj" owns /usr/share/nginx/html/testdj and everything below it. /usr/share/nginx/html/testdj and all its subdirectories have perms 775 and I've added www-data to the testdj group.
I do have nginx installed but I don't have the nginx service running. I did try starting it up and enabling an nginx virtual server using the following configuration file but the error still occurred.
upstream testdj_app_server {
server unix:/usr/share/nginx/html/testdj/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name ec2-[my-public-dns-ip].us-west-2.compute.amazonaws.com;
client_max_body_size 4G;
access_log /var/log/nginx/testdj-access.log;
error_log /var/log/nginx/testdj-error.log;
location /static/ {
alias /usr/share/nginx/html/testdj/static/;
}
location /media/ {
alias /usr/share/nginx/html/testdj/media/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
# This must match "upstream" directive above
proxy_pass http://testdj_app_server;
break;
}
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /usr/share/nginx/html/testdj/static/;
}
}
The problem seems to be with gunicorn because if I replace the "--bind=unix:$SOCKFILE" in my start-gunicorn script with "--bind --[ec2-public-dns]:8000", I can see the Django default page. However, I don't want to bind to my public DNS name on port 8000, I want to run on port 80 and use nginx as my front end reverse proxy.
I initially had AWS inbound security group rules that limited access to the site to HTTP on ports 80, 8000, and 8001 to my laptop but even if I delete these rules and leave the site wide open, I still get the 502 error message.
My gunicorn access log doesn't show any activity and the only thing I see in the gunicorn error log is gunicorn starting up. When I access the default Django page, there are no errors in the error log:
2014-02-03 18:41:01 [19023] [INFO] Starting gunicorn 18.0
2014-02-03 18:41:01 [19023] [DEBUG] Arbiter booted
2014-02-03 18:41:01 [19023] [INFO] Listening at: unix:/usr/share/nginx/html/testdj/run/gunicorn.sock (19023)
2014-02-03 18:41:01 [19023] [INFO] Using worker: sync
2014-02-03 18:41:01 [19068] [INFO] Booting worker with pid: 19068
2014-02-03 18:41:01 [19069] [INFO] Booting worker with pid: 19069
2014-02-03 18:41:01 [19070] [INFO] Booting worker with pid: 19070
Does anyone know what's happening here? It doesn't look like I'm even getting to gunicorn. I apologize for the long post but there seems to be a lot of "moving parts" to this problem. I'd be very grateful for any help as I've tried many different things but all to no avail. I've also looked at other questions here where other people had similar problems but I didn't see anything pertinent to this problem. Thanks!
I repeated my configuration process line-for-line on my Linode server and had no problems at all. I have to assume that this problem has something to do with the way AWS EC2 instances are configured, probably with respect to security.
I was running into the same problem today. Daniel Roseman explained it to me in the comments here:
port 8000 is not open to the outside by default; you'd either need to
fiddle with your load balancer/firewall settings to open it, or run
gunicorn on port 80 (which will mean killing nginx and starting
gunicorn as the superuser). Much easier to just get the nginx settings
right; there is a perfectly usable configuration on the gunicorn
deploy docs page.
It seems it's possible to run Gunicorn directly, but EC2 isn't set up to do so by default.