Problems deploying Pyramid with uWSGI on Nginx - python

I seem to be having some slight problems deploying a Pyramid web application. The problem seems to lie in my init script that I am using to start my web application on boot. For some reason, uWSGI will not work unless my socket is set to have a permission of "nobody.nobody" OR Nginx is started after my uwsgi init script. I'm changed my init script to reflect these changes, but it does not seem to be working. The init script (or the part that starts uwsgi) looks like so:
#!/sbin/runscript
args="--ini-paste /var/www/pyramid/app1/development.ini"
command="/var/www/pyramid/bin/uwsgi"
pidfile="/var/run/uwsgi.pid"
sock="/var/tmp/proxy/uwsgi.sock"
nobody="nobody.nobody"
start() {
ebegin "Starting app1"
chown $nobody $sock
start-stop-daemon --start --exec $command -- $args \
--pidfile $pidfile
chown $nobody $sock
einfo "app1 started"
eend $?
}
My Nginx configuration looks like so:
location / {
include uwsgi_params;
uwsgi_pass unix:///var/tmp/proxy/uwsgi.sock;
uwsgi_param SCRIPT_NAME "" ;
}
My ini file includes the following:
[uwsgi]
socket = /var/tmp/proxy/uwsgi.sock
pidfile = /var/run/uwsgi.pid
master = true
processes = 1
home = /var/www/pyramid
daemonize = /var/log/uwsgi.log
virtualenv = /var/www/pyramid/
pythonpath = /var/www/pyramid/bin
What happens is that Nginx will start, and then uwsgi will start. Performing a "ls -la" in /var/tmp/proxy reveals that the permissions of uwsgi.sock is set to "root root" instead of "nobody nobody". However, restarting Nginx will fix the problem, regardless of what the socket's permissions are (but Nginx has to be started first).
Thus, the ways I can get this to work is:
start uwsgi
start nginx
restart nginx
or
start nginx
start uwsgi
restart nginx
I'm at a complete loss as to why this isn't working. If anyone has any advice I'd greatly appreciate it!

You can use the following settings to change the permission of its socket in your ini file:
chmod-socket = 777 # socket permission
gid = www-data # socket group
uid = www-data # socket user

Another thing to consider is whether you actually want uWSGI to run as root. If you pass --uid and --gid arguments to uwsgi, uwsgi will masquerade as a different (preferably non-root) user.
For example, nginx usually runs as the www-data user and www-data group. So if you set up your wsgi app to run with "--gid www-data" and then add at least group-write permissions to your socket file with "--chmod-socket 020", then nginx will be able to write to the socket and you'll be in business.
See my blog post on the subject: http://blog.jackdesert.com/common-hurdles-to-deploying-uwsgi-apps-part-1

Related

chown(): Operation not permitted occurred due to chown-soket of uwsgi【nginx】

I tried to run a django program using nginx and uwsgi, but the following error occurs in nginx.
connect() to unix:/var/www/html/view/dbproject/dbproject.sock failed (13: Permission denied) while connecting to upstream
I thought this error was probably because the owner of dbproject.sock, which is created when uwsgi is started, is username:username and not username:www-data.
Therefore, I added chown-soket = %(username):www-data in the uwsgi initialization file uwsgi.ini, but when I restart uwsgi, chown(): Operation not permitted is written in the uwsgi log.
How can I make the socket owner %(username):www-data?
Thank you.
uwsgi.ini
[uwsgi]
# path to your project
chdir = /var/www/html/view/dbproject
username = myusername
# path to wsgi.py in project
module = dbproject.wsgi:application
master = true
pidfile = /var/www/html/view/dbproject/django.uwsgi.pid
socket = /var/www/html/view/dbproject/dbproject.sock
# http = 127.0.0.1:8000
# path to python virtualvenv
home = /var/www/html/view/myvenv
chown-socket = %(username):www-data
chmod-socket = 660
enable-threads = true
processes = 5
thunder-lock = true
max-requests = 5000
# clear environment on exit
vacuum = true
daemonize = /var/www/html/view/dbproject/django.uwsgi.log
# Django settings
env DJANGO_SETTINGS_MODULE = dbproject.settings
The problem has been resolved.
I used root permission to start uwsgi.
I was using the Python virtual environment. However, the user when entering the virtual environment was not root. So all Python commands used in this situation are uid=username, gid=username. In other words, the following uwsgi command and the chown command executed by uwsgi will also be executed by username.
uwsgi --ini uwsgi.ini
However, as far as I know, the chown command causes a permission error if used by anyone other than root. Therefore, I think that the chown-socket in the uwsgi initialization file, which was executed by username, was causing permission errors.
So my operation is as follows
sudo -s # root permission
source myvenv/bin/acitvate # load python venv by root
uwsgi --ini uwsgi.ini # excute uwsgi by root
I am concerned that uwsgi will not work without root because of the problem if it is a public system, but if you have a better solution than mine, please point it out.

How to reflect python changes in django, uwsgi and nginx setup

Hi I have deployed Django using UWSGI and Nginx using following tutorial http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
Everything is running fine. I face a challenge while updating python code. I don't know the efficient way to deploy new changes.
after hit and trial, I used following commands to deploy
git pull; sudo service uwsgi stop; sudo service nginx restart; sudo service uwsgi restart; /usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals
this command works fine. But I face following problems
Usagi runs in the foreground. Every time I make changes, a new UWSGI instance start running.
Due to multiple UWSGI instances, My AWS server get crashed, due to memory exhaustion.
I want to know what commands should I run to reflect changes in python code.
PS: in my previous APACHE Django setup, I only used to restart apache, is it possible to reflect changes by only restarting nginx.
Try this:
git pull
python manage.py migrate # to run any migrations
sudo service uwsgi restart
Press Ctrl + Z and then bg + enter
This should run the process in the background.
Please let me know if this works.
Please have a look at this for running uwsgi in background. create an .ini file /etc/uwsgi/sites/projectname.ini. The script would look like this(for ubuntu 16.04):
[uwsgi]
project = projectname
base = projectpath
chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application
master = true
processes = 5
socket = %(base)/%(project)/%(project).sock
chmod-socket = 666
vacuum = true
(For ubuntu 16.04):
then create the following systemd script at /etc/systemd/system/uwsgi.service:
[Unit]
Description=uWSGI Emperor service
After=syslog.target
[Service]
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
Refresh the state of the systemd init system with this new uWSGI service on board
sudo systemctl daemon-reload
In order to start the script you'll need to run the following:
sudo systemctl start uwsgi
In order to start uWSGI on reboot, you will also need:
sudo systemctl enable uwsgi
You can use the following to check its status:
systemctl status uwsgi
(For ubuntu 14.04):
Create an upstart script for uWSGI:
sudo nano /etc/init/uwsgi.conf
Then add following lines in the above created file:
description "uWSGI application server in Emperor mode"
start on runlevel [2345]
stop on runlevel [!2345]
setuid user
setgid www-data
exec /usr/local/bin/uwsgi --emperor /etc/uwsgi/sites

Cant get permissions right to run uWSGI Emperor

I'm having a hell of a time trying to get Ubuntu + uWSGI + nginx running as my web server.
Below are my configs, and the information that is in my emperor.log file:
nginx config:
server {
listen 80;
server_name localhost;
charset utf-8;
client_max_body_size 5M;
location / { try_files $uri #cc; }
location #cc {
include uwsgi_params;
uwsgi_pass unix:/tmp/cc/cc_uwsgi.sock;
}
}
uwsgi config:
[uwsgi]
base = /srv/www/cc
app = hello
module = %(app)
socket = /tmp/cc/%n.sock
chmod-socket = 664
uid = www-data
gid = www-data
callable = app
logto = /var/log/uwsgi/%n.log
emperor config:
#/etc/init/uwsgi.conf
description "uWSGI"
start on runlevel [2345]
stop on runlevel [06]
respawn
env UWSGI=/home/ccadmin/.local/bin/uwsgi
env LOGTO=/var/log/uwsgi/emperor.log
exec $UWSGI --master --emperor /etc/uwsgi/vassals --die-on-term --uid www-data --gid www-data --logto $LOGTO
However with this configuration my emperor.log file says:
execvp(): Permission denied [core/emperor.c line 1481]
[emperor] binary path: /home/ccadmin/.local/bin/uwsgi
[emperor] is the uwsgi binary in your system PATH ?
TIME STAMP - [emperor] curse the uwsgi instance cc_uwsgi.ini (pid: ####)
TIME STAMP - [emperor] removed uwsgi instance cc_uwsgi.ini
If I change the --uid and --gid to root, then it all works fine. It must be some simple permission thing, but being new to linux, I'm finding it very hard to pinpoint.
Also strange that it is asking me about the uwsgi binary in my system path... is it supposed to be there? Because i have added /home/ccadmin/.local/bin to my system path in /etc/environment. Should it not be there? or should it go all the way to the binary? (ie, adding /home/ccadmin/.local/bin/uwsgi insetad of just to /bin)
Did a couple things to make this work:
sudo chown -R ccadmin:www-data /home/ccadmin/
sudo chmod -R 774 /home/ccadmin/
Now the emperor has access to the uwsgi binary and all is good!
I am curious if the above is a security problem, though, not knowing much about linux.

Nginx Django and Gunicorn. Gunicorn sock file is missing?

I have an ansible provisioned VM based on this one https://github.com/jcalazan/ansible-django-stack but for some reason trying to start Gunicorn gives the following error:
Can't connect to /path/to/my/gunicorn.sock
and in nginx log file:
connect() to unix:/path/to/my/gunicorn.sock failed (2: No such file or directory) while connecting to upstream
And actually the socket file is missing in the specified directory. I have checked the permissions of the directory and they are fine.
Here is my gunicorn_start script:
NAME="{{ application_name }}"
DJANGODIR={{ application_path }}
SOCKFILE={{ virtualenv_path }}/run/gunicorn.sock
USER={{ gunicorn_user }}
GROUP={{ gunicorn_group }}
NUM_WORKERS={{ gunicorn_num_workers }}
# Set this to 0 for unlimited requests. During development, you might want to
# set this to 1 to automatically restart the process on each request (i.e. your
# code will be reloaded on every request).
MAX_REQUESTS={{ gunicorn_max_requests }}
echo "Starting $NAME as `whoami`"
# Activate the virtual environment.
cd $DJANGODIR
. ../../bin/activate
# Set additional environment variables.
. ../../bin/postactivate
# Create the run directory if it doesn't exist.
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR
# Programs meant to be run under supervisor should not daemonize themselves
# (do not use --daemon).
exec gunicorn \
--name $NAME \
--workers $NUM_WORKERS \
--max-requests $MAX_REQUESTS \
--user $USER --group $GROUP \
--log-level debug \
--bind unix:$SOCKFILE \
{{ application_name }}.wsgi
Can anyone suggest what else could cause the missing socket file?
Thanks
Well, since I don't have enough rep to comment, I'll mention here that there is not a lot of specificity suggested by the missing socket, but I can tell you a bit about how I started in your shoes and got things to work.
The long and short of it is that gunicorn has encountered a problem when run by upstart and either never got up and running or shut down. Here are some steps that may help you get more info to track down your issue:
In my case, when this happened, gunicorn never got around to doing any error logging, so I had to look elsewhere. Try ps auxf | grep gunicorn to see if you have any workers going. I didn't.
Looking in the syslog for complaints from upstart, grep init: /var/log/syslog, showed me that my gunicorn service had been stopped because it was respawning too fast, though I doubt that'll be your problem since you don't have a respawn in your conf. Regardless, you might find something there.
After seeing gunicorn was failing to run or log errors, I decided to try running it from the command line. Go to the directory where your manage.py lives and run the expanded version of your upstart command against your gunicorn instance. Something like (Replace all of the vars with the appropriate litterals instead of the garbage I use.):
/path/to/your/virtualenv/bin/gunicorn --name myapp --workers 4 --max-requests 10 --user appuser --group webusers --log-level debug --error-logfile /somewhere/I/can/find/error.log --bind unix:/tmp/myapp.socket myapp.wsgi
If you're lucky, you may get a python traceback or find something in your gunicorn error log after running the command manually. Some things that can go wrong:
django errors (maybe problems loading your settings module?). Make sure your wsgi.py is referencing the appropriate settings module on the server.
whitespace issues in your upstart script. I had a tab hiding among spaces that munged things up.
user/permission issues. Finally, I was able to run gunicorn as root on the command line but not as a non-root user via the upstart config.
Hope that helps. It's been a couple of long days tracking this stuff down.
I encountered the same problem after following Michal Karzynski's great guide 'Setting up Django with Nginx, Gunicorn, virtualenv, supervisor and PostgreSQL'.
And this is how I solved it.
I had this variable in the bash script used to start gunicorn via Supervisor (myapp/bin/gunicorn_start):
SOCKFILE={{ myapp absolute path }}/run/gunicorn.sock
Which, when you run the bash script for the first time, creates a 'run' folder and a sock file using root privileges. So I sudo deleted the run folder, and then recreated it without sudo privileges and voila! Now if you rerun Gunicorn or Supervisor you won't have the annoying missing sock file error message anymore!
TL;DR
Sudo delete run folder.
Recreate it without sudo privileges.
Run Gunicorn again.
????
Profit
The error could also arise when you haven't pip installed a requirement. In my case, looking at the gunicorn error logs, I found that there was a missing module. Usually happens when you forget to pip install new requirements.
Well, I worked on this issue for more than a week and finally was able to figure it out.
Please follow links from digital ocean , but they did not pinpoint important issues one which includes
no live upstreams while connecting to upstream
*4 connect() to unix:/myproject.sock failed (13: Permission denied) while connecting to upstream
gunicorn OSError: [Errno 1] Operation not permitted
*1 connect() to unix:/tmp/myproject.sock failed (2: No such file or directory)
etc.
These issues are basically permission issue for connection between Nginx and Gunicorn.
To make things simple, I recommend to give same nginx permission to every file/project/python program you create.
To solve all the issue follow this approach:
First thing is :
Log in to the system as a root user
Create /home/nginx directory.
After doing this, follow as per the website until Create an Upstart Script.
Run chown -R nginx:nginx /home/nginx
For upstart script, do the following change in the last line :
exec gunicorn --workers 3 --bind unix:myproject.sock -u nginx -g nginx wsgi
DONT ADD -m permission as it messes up the socket. From the documentation of Gunicorn, when -m is default, python will figure out the best permission
Start the upstart script
Now just go to /etc/nginx/nginx.conf file.
Go to the server module and append:
location / {
include proxy_params;
proxy_pass http<>:<>//unix:/home/nginx/myproject.sock;
}
REMOVE <>
Do not follow the digitalocean aricle from here on
Now restart nginx server and you are good to go.
I had the same problem and found out that I had set the DJANGO_SETTINGS_MODULE to production settings in the the gunicorn script and the wsgi settings were using dev.
I pointed the DJANGO_SETTINGS_MODULE to dev and everything worked.

Can I use the uwsgi protocol to call http?

Here's a data flow:
http <--> nginx <--> uWSGI <--> python webapp
I guess there's http2uwsgi transfer in nginx, and uwsgi2http in uWSGI.
What if I want to directly call uWSGI to test an API in a webapp?
actually i'm using pyramid. just config [uwsgi] in .ini and run uWSGI. but i want to test if uWSGI hold webapp function normally, the uWSGI socket is not directly reachable by http.
Try using uwsgi_curl
$ pip install uwsgi-tools
$ uwsgi_curl 10.0.0.1:3030 /path
or if you need to do some more requests try uwsgi_proxy from the same package
$ uwsgi_proxy 10.0.0.1:3030
Proxying remote uWSGI server 10.0.0.1:3030 "" to local HTTP server 127.0.0.1:3030...
so you can browse it locally at http://127.0.0.1:3030/.
If your application allows only certain Host header, you can specify host name as well
$ uwsgi_curl 10.0.0.1:3030 host.name/path
$ uwsgi_proxy 10.0.0.1:3030 -n host.name
If application has static files, you can redirect such requests to your front server using -s argument. You can also specify different local port if needed.
From your question I'm assuming, you want to directly run your WSGI-compliant app with uWSGI and open an HTTP-Socket. You can do so by configuring your uwsgi.ini (or whatever the filename is) with
http=127.0.0.1:8080
uwsgi will now open an HTTP-socket that listen on port 8080 for incoming connections from localhost (see documentation: http://uwsgi-docs.readthedocs.org/en/latest/HTTP.html)
Alternatively you can directly start your process from the command-line with the http-parameter:
$ uwsgi --http=127.0.0.1:8080 --module=yourapp:wsgi_entry_point
If you use unix-sockets to configure uwsgi nginx is able to communicate with that socket via the uwsgi-protocol (http://uwsgi-docs.readthedocs.org/en/latest/Protocol.html).
Keep in mind, that if you usually serve static content (css, javascript, images) through nginx you will need to set that up, too, if you run uwsgi directly. But if you only want to test a REST-API this should work out for you.
First, consider those questions:
On which port is uWSGI running?
Is uWSGI running on your or on a remote machine?
If it's running on a remote machine, is the port accessible from your computer? (iptables rules might forbid external access)
If you made sure you have access, you can just call http://hostname:port/path/to/uWSGI for direct API access.
I know this is an old question but I just needed this and found out that this docker+nginx solution works for me the best
cat > /tmp/nginx.conf << EOF
events {}
http {
server {
listen 8000;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3031;
}
}
}
EOF
docker run -it --network=host --rm --name uswgi-proxy -v /tmp/nginx.conf:/etc/nginx/nginx.conf:ro nginx

Categories

Resources