Skip to main content

Python deployment with uwsgi

On this site, you will find a step-by-step guide on deploying a Python Application using uWSGI with NGINX.

Creating a Python Site#

Create a Python Site with the right Python Version and ensure the App Port is correct.

Creating a uWSGI Config#

For running a Python Application in production, we use The uWSGI Project, which ensures that our Application is available after a reboot.

  1. Log in via SSH with the Root User and go to the uwsgi apps directory:
cd /etc/uwsgi/apps-enabled/
  1. Create a configuration file like domain.uwsgi.ini and modify the example configuration below to your needs:
uWSGI Configuration

Change the values of socket, wsgi-file, uid, and gid.
You may want to look at the official uWSGI Documentation for further settings.

On the Django Documentation, you find helpful information about deploying Django Applications via uWSGI.

[uwsgi]plugins       = python3master        = trueprotocol      = uwsgisocket        = 127.0.0.1:8080wsgi-file     = /home/site-user/htdocs/python-project/wsgi.py
# In case you're using virtualenv uncomment this:#virtualenv = /home/site-user/htdocs/python-project
# Needed for OAuth/OpenIDbuffer-size   = 8192
# Reload when consuming too much of memoryreload-on-rss = 250
# Increase number of workers for heavily loaded sitesworkers       = 4
# Enable threads for Sentry error submissionenable-threads = true
# Child processes do not need file descriptorsclose-on-exec = true
# Avoid default 0000 umaskumask = 0022
# Run as weblate useruid = site-usergid = site-user
# Enable harakiri mode (kill requests after some time)# harakiri = 3600# harakiri-verbose = true
# Enable uWSGI stats server# stats = :1717# stats-http = true
# Do not log some errors caused by client disconnectsignore-sigpipe = trueignore-write-errors = truedisable-write-exception = true

Vhost Change#

  1. Go to the Vhost of your site.

Below you see the default vhost. It's forwarding all requests via reverse proxy to the App Port.
It's useful for development where you use the built-in server, provided by most the Python Applications.

server {  listen 80;  listen [::]:80;  listen 443 ssl http2;  listen [::]:443 ssl http2;  {{ssl_certificate_key}}  {{ssl_certificate}}  server_name www.domain.com;  {{root}}
  {{nginx_access_log}}  {{nginx_error_log}}
  if ($scheme != "https") {    rewrite ^ https://$host$uri permanent;  }
  location ~ /.well-known {    auth_basic off;    allow all;  }
  {{settings}}
  index index.html;
  location /uwsgi {    include uwsgi_params;    uwsgi_read_timeout 3600;    #uwsgi_pass unix:///run/uwsgi/app/weblate/socket;    uwsgi_pass 127.0.0.1:{{app_port}};  }
  location / {    proxy_pass http://127.0.0.1:{{app_port}}/;    proxy_http_version 1.1;    proxy_set_header X-Forwarded-Host $host;    proxy_set_header X-Forwarded-Server $host;    proxy_set_header X-Real-IP $remote_addr;    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    proxy_set_header X-Forwarded-Proto $scheme;    proxy_set_header Host $http_host;    proxy_set_header Upgrade $http_upgrade;    proxy_set_header Connection "Upgrade";    proxy_pass_request_headers on;    proxy_max_temp_file_size 0;    proxy_connect_timeout 900;    proxy_send_timeout 900;    proxy_read_timeout 900;    proxy_buffer_size 128k;    proxy_buffers 4 256k;    proxy_busy_buffers_size 256k;    proxy_temp_file_write_size 256k;  }
  location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf)$ {    add_header Access-Control-Allow-Origin "*";    expires max;    access_log on;  }
  if (-f $request_filename) {    break;  }}
  1. Replace the default vhost with the following one, replacing the location / to forward all requests to the uWSGI Service.
server_name

Replace the server_name with your domain.

server {  listen 80;  listen [::]:80;  listen 443 ssl http2;  listen [::]:443 ssl http2;  {{ssl_certificate_key}}  {{ssl_certificate}}  server_name www.domain.com;  {{root}}
  {{nginx_access_log}}  {{nginx_error_log}}
  if ($scheme != "https") {    rewrite ^ https://$host$uri permanent;  }
  location ~ /.well-known {    auth_basic off;    allow all;  }
  {{settings}}
  index index.html;
  location / {    include uwsgi_params;    uwsgi_read_timeout 3600;    #uwsgi_pass unix:///run/uwsgi/app/weblate/socket;    uwsgi_pass 127.0.0.1:{{app_port}};  }
  #location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf)$ {  #  add_header Access-Control-Allow-Origin "*";  #  expires max;  #  access_log on;  #}
  if (-f $request_filename) {    break;  }}

Restart uwsgi Service#

Restart the uwsgi service via systemctl to apply our configuration.

systemctl restart uwsgi

Service Check#

To check if uwsgi is listening on our requested port e.g., 8080, we use netstat:

netstat -tulpn |grep uwsgi

If everything is correct, you should see an output like this:

tcp 16 0 127.0.0.1:8080 0.0.0.0:* LISTEN 8872/uwsgi

Reboot your instance to confirm that your application is working as expected.

Logs#

For troubleshooting, you can check the uwsgi logs, located in /var/log/uwsgi/app/.