Things to know (best practices and “issues”) READ IT !!!

  • Obviously, never expose a socket speaking the uwsgi protocol to the public network unless you know what you are doing. That channel allows for dynamic loading of applications (read: arbitrary execution of code). The protocol is meant to be sanitized/validated by a proxy like nginx, apache, the uWSGI routers, etc. For example, if uwsgi uses --socket :1234 parameter, it listens to port 1234 on every network interfaces. It can be limited to loopback interface with --socket localhost:1234 parameter.

  • The http and http-socket options are entirely different beasts. The first one spawns an additional process forwarding requests to a series of workers (think about it as a form of shield, at the same level of apache or nginx), while the second one sets workers to natively speak the http protocol. TL/DR: if you plan to expose uWSGI directly to the public, use --http, if you want to proxy it behind a webserver speaking http with backends, use --http-socket.

  • Till uWSGI 2.1, by default, sending the SIGTERM signal to uWSGI means “brutally reload the stack” while the convention is to shut an application down on SIGTERM. To shutdown uWSGI use SIGINT or SIGQUIT instead. If you absolutely can not live with uWSGI being so disrespectful towards SIGTERM, by all means enable the die-on-term option. Fortunately, this bad choice has been fixed in uWSGI 2.1

  • If you plan to host multiple applications do yourself a favor and check the The uWSGI Emperor – multi-app deployment docs.

  • Always use uwsgitop, through The uWSGI Stats Server or something similar to monitor your apps’ health.

  • uWSGI can include features in the core or as loadable plugins. uWSGI packages supplied with OS distributions tend to be modular. In such setups, be sure to load the plugins you require with the plugins option. A good symptom to recognize an unloaded plugin is messages like “Unavailable modifier requested” in your logs. If you are using distribution supplied packages, double check that you have installed the plugin for your language of choice.

  • Config files support a limited form of inheritance, variables, if constructs and simple cycles. Check the Configuration logic and How uWSGI parses config files pages.

  • To route requests to a specific plugin, the webserver needs to pass a magic number known as a modifier to the uWSGI instances. By default this number is set to 0, which is mapped to Python. As an example, routing a request to a PSGI app requires you to set the modifier to 5 - or optionally to load the PSGI plugin as modifier 0. (This will mean that all modifierless requests will be considered Perl.)

  • There is no magic rule for setting the number of processes or threads to use. It is very much application and system dependent. Simple math like processes = 2 * cpucores will not be enough. You need to experiment with various setups and be prepared to constantly monitor your apps. uwsgitop could be a great tool to find the best values.

  • If an HTTP request has a body (like a POST request generated by a form), you have to read (consume) it in your application. If you do not do this, the communication socket with your webserver may be clobbered. If you are lazy you can use the post-buffering option that will automatically read data for you. For Rack applications this is automatically enabled.

  • Always check the memory usage of your apps. The memory-report option could be your best friend.

  • If you plan to use UNIX sockets (as opposed to TCP), remember they are standard filesystem objects. This means they have permissions and as such your webserver must have write access to them.

  • Common sense: do not run uWSGI instances as root. You can start your uWSGIs as root, but be sure to drop privileges with the uid and gid options.

  • uWSGI tries to (ab)use the Copy On Write semantics of the fork() call whenever possible. By default it will fork after having loaded your applications to share as much of their memory as possible. If this behavior is undesirable for some reason, use the lazy-apps option. This will instruct uWSGI to load the applications after each worker’s fork(). Beware as there is an older options named lazy that is way more invasive and highly discouraged (it is still here only for backward compatibility)

  • By default the Python plugin does not initialize the GIL. This means your app-generated threads will not run. If you need threads, remember to enable them with enable-threads. Running uWSGI in multithreading mode (with the threads options) will automatically enable threading support. This “strange” default behaviour is for performance reasons, no shame in that.

  • If you spawn a new process during a request it will inherit the file descriptors of the worker spawning it - including the socket connected with the webserver/router. If you do not want this behaviour set the close-on-exec option.

  • The Ruby garbage collector is configured by default to run after every request. This is an aggressive policy that may slow down your apps a bit – but CPU resources are cheaper than memory, and especially cheaper than running out of memory. To tune this frequency use the ruby-gc <freq> option.

  • On OpenBSD, NetBSD and FreeBSD < 9, SysV IPC semaphores are used as the locking subsystem. These operating systems tend to limit the number of allocable semaphores to fairly small values. You should raise the default limits if you plan to run more than one uWSGI instance. FreeBSD 9 has POSIX semaphores, so you do not need to bother with that.

  • Do not build plugins using a different config file than used to build the uWSGI binary itself – unless you like pain or know exactly what you are doing.

  • By default uWSGI allocates a very small buffer (4096 bytes) for the headers of each request. If you start receiving “invalid request block size” in your logs, it could mean you need a bigger buffer. Increase it (up to 65535) with the buffer-size option.

    Note

    If you receive ‘21573’ as the request block size in your logs, it could mean you are using the HTTP protocol to speak with an instance speaking the uwsgi protocol. Don’t do this.

  • If your (Linux) server seems to have lots of idle workers, but performance is still sub-par, you may want to look at the value of the ip_conntrack_max system variable (/proc/sys/net/ipv4/ip_conntrack_max) and increase it to see if it helps.

  • Some Linux distributions (read: Debian 4 Etch, RHEL / CentOS 5) make a mix of newer kernels with very old userspace. This kind of combination can make the uWSGI build system spit out errors (most notably on unshare(), pthread locking, inotify…). You can force uWSGI to configure itself for an older system prefixing the ‘make’ (or whatever way you use to build it) with CFLAGS="-DOBSOLETE_LINUX_KERNEL"

  • By default, stdin is remapped to /dev/null on uWSGI startup. If you need a valid stdin (for debugging, piping and so on) add --honour-stdin.

  • You can easily add non-existent options to your config files (as placeholders, custom options, or app-related configuration items). This is a really handy feature, but can lead to headaches on typos. The strict mode (--strict) will disable this feature, and only valid uWSGI options are tolerated.

  • Some plugins (most notably Python and Perl) have code auto-reloading facilities. Although they might sound very appealing, you MUST use them only under development as they are really heavy-weight. For example the Python –py-autoreload option will scan your whole module tree at every check cycle.

  • wsgi.file_wrapper is an optimization of the WSGI standard. In some corner case it can raise an error. For example when returning an in-memory bytes buffer (io.BytesIO) in Python 3.5. See this issue. You can disable it by setting the option wsgi-disable-file-wrapper to true.