Deploying Django and Flask Apps with uWSGI Emperor Mode – A Practical Guide
Learn how to run multiple Python web apps from a single uWSGI Emperor, achieve zero‑downtime reloads, and keep your deployment simple and reliable.
13 Feb 2026, 19:19 UTC

Problem: One Master, Many Apps
In a typical Python‑web stack you might have several Django or Flask services that all need to run on the same host. The naive approach is to launch a separate uWSGI instance for each application and then manage each one with its own systemd unit. That leads to a cluttered process tree, duplicated configuration files, and the risk of a missing restart after a crash. If you need zero‑downtime updates, you have to orchestrate graceful reloads for every instance manually.
uWSGI Emperor mode offers a clean alternative: a single master process watches a directory of configuration files and spawns a vassal (the actual worker pool) for each app. The Emperor itself never serves HTTP traffic; it only supervises the workers. This pattern gives you centralized control, simplifies configuration, and turns graceful reloads into a one‑liner.
Key Takeaway
Run a single uWSGI Emperor, drop an app’s .ini file into a watched folder, and let the Emperor handle worker lifecycle, zero‑downtime reloads, and automatic restarts. The only thing you need to monitor is the Emperor process itself.
1. Verify Your uWSGI Version
Emperor mode has been stable since uWSGI 1.9, but the most common features—per‑vassal reloads, graceful worker replacement, and the --emperor flag—are fully supported in 2.0+. Run uwsgi --version to confirm. If you see a version string older than 1.9, consider upgrading or be prepared for limited Emperor functionality.
Command to run on the host:
uwsgi --version
# Expected output example: "uWSGI 2.0.21"
2. Prepare the Configuration Directory
Create a dedicated directory that the Emperor will monitor. Give it read permissions for the user that will run the Emperor.
sudo mkdir -p /etc/uwsgi/vassals
sudo chmod 755 /etc/uwsgi/vassals
When you drop a new .ini file here, the Emperor will automatically spawn a vassal for it. When you delete the file, the vassal shuts down.
3. Write a Vassal Configuration
Each app needs its own .ini file. Below is a minimal example for a Flask app that listens on a Unix socket. Adjust module, socket, uid and gid as required.
[uwsgi]
module = myflaskapp:app
socket = /run/uwsgi/myflask.sock
chmod-socket = 666
master = true
processes = 4
threads = 2
vacuum = true
uid = www-data
gid = www-data
Key points:
master = truetells the vassal to spawn its own worker processes.vacuum = truecleans up the socket when the vassal exits.- Use a Unix socket (or a TCP port) that your reverse proxy (e.g., Nginx) can reach.
4. Launch the Emperor
Run the Emperor as the user that owns the configuration directory. If you need to bind to privileged ports (<1024), run the Emperor as root and let the vassals drop privileges. Otherwise, a non‑root user is fine.
sudo uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data
Parameters explained:
--emperorpoints to the watched directory.--uid/--gidspecify the user/group the Emperor itself runs as (useful for permission management).
5. Verify the Hierarchy
Check that a master process and at least one worker exist:
ps aux | grep uwsgi | grep -v grep
You should see one line with --emperor and another with --master and the vassal’s .ini file name. In the logs, look for entries like:
emperor: started vassal /etc/uwsgi/vassals/myflask.ini
vassal: started worker 0
6. Zero‑Downtime Reloads
When you update an app’s code or configuration, touch its .ini file or send SIGHUP to the Emperor. The Emperor will spawn a new vassal instance, wait for it to accept connections, then terminate the old vassal. No 502 errors appear.
sudo touch /etc/uwsgi/vassals/myflask.ini
# or
sudo kill -HUP $(pgrep -f "uwsgi --emperor")
After the reload, the process list should show two vassal processes for a brief period before the old one exits.
7. Monitoring and Reliability
Because the Emperor is the single point of supervision, you should keep it under watch. The most common practice is to wrap the Emperor in a systemd unit that automatically restarts it on failure:
[Unit]
Description=uWSGI Emperor
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
With Restart=on-failure, systemd will bring the Emperor back up if it crashes, re‑establishing all vassals automatically.
Trade‑offs and Limitations
- Single Point of Failure: The Emperor is the only supervisor. If it dies, vassals keep running but won’t be restarted automatically. Use systemd or a watchdog to mitigate.
- Socket Contention: All vassals share the same Nginx socket pool. If you have many workers across apps, you may hit the OS limit for open file descriptors. Tune
worker_processesand consider separate sockets per app if traffic is heavy. - Permission Complexity: The Emperor must have read access to all vassal .ini files and the ability to change to the
uid/gidspecified inside. Mis‑configured permissions can prevent workers from starting. - Version Compatibility: Features like per‑vassal graceful reloads are fully supported only in 2.0+. In older releases you may see limited behavior or errors.
Actionable Checklist for Production
- Ensure uWSGI ≥ 2.0 (or ≥ 1.9 if you need Emperor).
- Run the Emperor under a systemd unit with
Restart=on-failure. - Keep the configuration directory readable by the Emperor’s user.
- Set
vacuum = truein each vassal to clean sockets on exit. - Test a reload by touching an .ini file and watching the worker replacement.
- Monitor
ps aux | grep uwsgiand logs for unexpected shutdowns. - Adjust
processesandthreadsper app based on load testing.
Conclusion
uWSGI Emperor mode turns a messy multi‑service setup into a single‑process supervisor that is easy to deploy, maintain, and scale. By keeping the Emperor as a systemd service and ensuring proper permissions, you get the benefits of zero‑downtime reloads and automatic recovery without the overhead of dozens of individual systemd units.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.