Using uWSGI in Gentoo
Tags: uwsgi, python, gentoo
Published: 2021-01-10 20:09:21

Here some quick notes on how to use [uwsgi](https://uwsgi-docs.readthedocs.io/en/latest/) (and [flask](https://flask.palletsprojects.com/) on Gentoo.

## Flask

Flask is a python microframework for web development, it is fairly simple and you can find lots of [extensions](https://pypi.org/search/?c=Framework+%3A%3A+Flask) for nearly everything.

Flask implements the [wsgi](https://www.python.org/dev/peps/pep-3333/) specification so usually it is deployed using [gunicorn](https://gunicorn.org/) or other **WSGI** servers.

I like a lot [uwsgi](https://uwsgi-docs.readthedocs.io/en/latest/)

## uWSGI

uWSGI is a neat multi-language server that has a fairly good support for python.

It has a fairly straightforward configuration system that let you do simple things in simple ways and increase complexity as you need.

## Using both in Gentoo

Usually you use [virtualenv](https://virtualenv.pypa.io/en/stable/) to keep your webapp dependencies in a single place, so portage is not in the equation for Flask.

uWSGI on the other hand can be managed by your init system and for stable deployments it is a good idea.

## Emperor vs single-instance

uWSGI has multiple ways to run, the OpenRC init scripts let you pick if you want it to host multiple webapp by itself (emperor) or just run every instance as a single service.

```
/etc/init.d/uwsgi <- emperor mode
/etc/init.d/uwsgi.app_name <- single instance
```
You simply use `ln -s` to create the single instances and then write its configuration in `/etc/conf.d/uwsgi.app_name` as usual.

If you want to use the emperor mode you should put the configuration in `/etc/uwsgi.d/`, I find the `ini` variants simpler, but uwsgi supports multiple formats.

``` ini
[uwsgi]
plugins = python38
socket = /run/app.sock
chown-socket = app_user:nginx
chmod-socket = 664
chdir = /home/app/path
virtualenv = /home/app/path/.venv
mount = /=your_python_class:app
threads = 4
env=SOME_VAR=somevalue
```
Usually you have a callable called `app` in your application main class. Since it is common to run `flask` by calling the  `App::run()` method, make sure you do not have it or you have guarded with the usual `if __name__ == "__main__"`.

# nginx

I prefer using nginx as frontend server, the configuration of its side is simple enough as well:

``` nginx
server {
    ...
    server_name name.tdl;

    access_log /var/log/nginx/name.access_log main;
    error_log /var/log/nginx/name.error_log info;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/app.sock;
    }
}
```

`uwsgi_params` are already provided and you just have to make sure both nginx and uwsgi can access the socket.

# metalog

I like to have uwsgi log using the syslog facility so in its `/etc/conf.d/uwsgi` I have:

``` sh
UWSGI_EXTRA_OPTIONS="--logger syslog:uwsgi"
```

and in `/etc/metalog.conf` I added:

``` yaml
uWSGI Emperor :
    program = "uwsgi"
    logdir  = "/var/log/uwsgi"
    break   = 1
```

## Pitfalls

Overall it is _that_ kind of simple, but here a checklist if something does not work as intended:

- If you use App::run() make sure it is guarded. It was fairly common when you develop to call directly your app using `python`. `flask run` made it way less common.

- Mention the `virtualenv` in the `ini` configuration

- Explicitly mention the python `plugin` in the `ini` configuration, uWSGI supports multiple languages.

- Add the app user to the `nginx` group and make sure all can write to the socket path.