Skip to content

Production setup using uWSGI and Nginx

VadeveSi edited this page Dec 29, 2020 · 11 revisions

Disclaimer

uWSGI is no longer supported by Etebase. This page is only here for legacy reasons.

uWSGI

It's not a good idea to just run the basic debug server and expose it to the outside world. Instead, a component stack should be built. The uWSGI docs state the following:

A web server faces the outside world. It can serve files (HTML, images, CSS, etc) directly from the file system. However, it can’t talk directly to Django applications; it needs something that will run the application, feed it requests from web clients (such as browsers) and return responses. A Web Server Gateway Interface - WSGI - does this job. WSGI is a Python standard. uWSGI is a WSGI implementation. In this tutorial we will set up uWSGI so that it creates a Unix socket, and serves responses to the web server via the uwsgi protocol. At the end, our complete stack of components will look like this:

the web client <-> the web server <-> the socket <-> uwsgi <-> Django

Note that different WSGI's exist and can be used, like for example Gunicorn. However, in this tutorial uWSGI is used.

Installing uWSGI

Installation of uWSGI is easily done via pip. Root needs access to uWSGI later, so install it as superuser.

sudo pip3 install uwsgi

Testing uWSGI

We can already test whether our uWSGI installation works.

cd path/to/server-skeleton  
source venv/bin/activate  # In case you haven't activated the venv yet.
uwsgi --http :8000 --module etesync_server.wsgi --virtualenv venv

This command runs the EteSync module, exposes it on port 8000 and uses the venv virtual environment. You can now surf to the IP address followed by port 8000 in the browser to check if it works (you should see "It works!")

Nginx

Nginx will form our proper web server.

Installing Nginx

Installation if done via apt.

sudo apt-get install nginx

Setup Nginx

First of all, create Django's static files so that Nginx can access them.

./manage.py collectstatic

Now we need to configure Nginx, using a configuration file. Create a new file called etesync_nginx.conf and paste the following into it. Don't forget to change server_name and the path to /static.

# mysite_nginx.conf

# the upstream component nginx needs to connect to
upstream django {
    # server unix:///tmp/etesync_server.sock; # for a file socket
    server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name example.com; # substitute your machine's IP address or domain name
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    location /static/ {
        alias /path/to/server_skeleton/static; # Project's static files
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params; # the uwsgi_params file, this path by default
    }
}

Move this file to /etc/nginx/sites-available and symlink it to /etc/nginx/sites-enabled. After restarting Nginx and launching uWSGI (on port 8001), you should be able to surf to the same url as before and see "It works!".

sudo cp etesync_nginx.conf /etc/nginx/sites-available/
sudo ln -s /etc/nginx/sites-available/etesync_nginx.conf /etc/nginx/sites-enabled/etesync_nginx.conf
systemctl restart nginx
uwsgi --socket :8001 --module etesync_server.wsgi --virtualenv venv

If you encounter any errors, the Nginx log is located in /var/log/nginx/error.log.

Finalize Nginx & uWSGI setup

For testing purposes, uWSGI exposes the Django application on port 8001. A more elegant solution would be to expose the application using a file socket.

Change /etc/nginx/sites-available/etesync_nginx.conf to accept file sockets by commenting in server unix:///tmp/etesync_server.sock; and commenting out server 127.0.0.1:8001;. The first part should now look like this:


# the upstream component nginx needs to connect to
upstream django {
    server unix:///tmp/etesync_server.sock; # for a file socket
    # server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

This will create a file socket at /tmp/etesync_server.sock. Now, configure uWSGI to also work using a file socket. Because a lot of parameters are needed, create a uwsgi.ini and copy the following in it. Don't forget to replace <user> by the name of the user for the server.

[uwsgi]
chdir = /path/to/server-skeleton/
socket = /tmp/etesync_server.sock
chown-socket = <user>:www-data
chmod-socket = 660
module = etesync_server.wsgi
master = true
uid = <user>
virtualenv = venv

Now to run uWSGI, all you need to do is tell it to use the .ini server. Restart Nginx and check if everything still works.

systemctl restart nginx
sudo uwsgi --ini uwsgi.ini  # has to be executed as root

That's it!

You now have a working EteSync server over HTTP. Don't forget to change allowed_hosts to your domain name in etesync-server.ini and to set server_name to your domain name in /etc/nginx/sites-available/etesync_nginx.conf.

An optional next step is to have your uWSGI run automatically at boot. More explanation can be found here: Run uWSGI at boot

It is also highly recommended to enable SSL for your EteSync server! A page detailing SSL setup can be found here: Setup HTTPS for EteSync

If you already want to test out the EteSync applications, be sure to use the ones in the Etebase announcement blog post as the official ones might not have been updated yet.