iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
You can host several Django sites on one Linux server by running one public Nginx instance and giving each site its own Gunicorn process, environment, settings, logs, and private Unix socket (or loopback TCP port). Nginx chooses a site from the request hostname, serves that site’s static and media files, and proxies dynamic requests only to the matching Gunicorn upstream.
The isolation matters: a deployment, restart, configuration error, or exhausted worker pool in one project should not automatically take the others offline. The examples below use site1.example and site2.example; replace every domain, path, user, group, module name, and credential with values appropriate to your server.
Architecture: one router, separate Django applications
Each domain must have a complete path through DNS, Nginx, Gunicorn, and Django:
- DNS records for each hostname point to the server’s public address.
- Nginx receives the request on ports 80 or 443 and selects a
serverblock using the HTTPHostheader. - That block serves static and media files from the selected project’s directories.
- Requests that need Python are proxied to that project’s Unix socket or loopback port.
- Gunicorn loads the project’s WSGI application and returns the response through Nginx.
Do not expose Gunicorn directly on a public interface when Nginx is the intended entry point. Keep sockets under /run, or bind TCP listeners to 127.0.0.1. Forward the original host, client address, and protocol so Django can construct correct URLs and apply its security checks.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
Plan the per-site isolation before installing anything
Use a separate project root, virtual environment, settings module, environment file, database credentials, log destination, systemd unit, and upstream endpoint for every site. A practical layout might look like this:
/srv/site1/current/ # site1 project and manage.py
/srv/site1/venv/ # site1 Python environment
/srv/site1/.env # secrets and production settings
/srv/site1/shared/static/ # STATIC_ROOT
/srv/site1/shared/media/ # MEDIA_ROOT
/run/site1-gunicorn.sock # private runtime socket
/srv/site2/current/
/srv/site2/venv/
/srv/site2/.env
/srv/site2/shared/static/
/srv/site2/shared/media/
/run/site2-gunicorn.sock
The names are examples, not distribution requirements. Create directories with ownership that lets the relevant service read application code and lets Nginx read the static/media trees. Keep each site’s database user restricted to that site’s database, and do not commit .env files or secret keys to source control.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePrepare the host and each Django project
1. Provision DNS, firewall, and service identities
Create an A or AAAA record for every public hostname and allow only the ports you need. A typical public web server permits TCP 80 and 443; SSH should be restricted to your administration policy. Create a dedicated Unix user (or otherwise enforce a separate service identity) for each project so a process cannot casually write into another project’s files.
2. Create virtual environments and install pinned dependencies
From each project root, create a virtual environment and install the application’s locked requirements. Use the Gunicorn executable from that environment, not a system-wide executable that could load the wrong dependency set.
python3 -m venv /srv/site1/venv
/srv/site1/venv/bin/pip install --upgrade pip
/srv/site1/venv/bin/pip install -r /srv/site1/current/requirements.txt
python3 -m venv /srv/site2/venv
/srv/site2/venv/bin/pip install --upgrade pip
/srv/site2/venv/bin/pip install -r /srv/site2/current/requirements.txt
Confirm the WSGI import manually for each project before involving Nginx. For a project whose WSGI module is config.wsgi, for example:
cd /srv/site1/current
/srv/site1/venv/bin/python -c "import config.wsgi; print('site1 WSGI import OK')"
3. Configure production settings, migrate, and collect assets
Set the production settings module and environment variables for each site. Run migrations against the correct database and collect static files into that site’s STATIC_ROOT:
Recommended Free Tools
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
cd /srv/site1/current
/srv/site1/venv/bin/python manage.py migrate --settings=config.settings.production
/srv/site1/venv/bin/python manage.py collectstatic --noinput --settings=config.settings.production
cd /srv/site2/current
/srv/site2/venv/bin/python manage.py migrate --settings=config.settings.production
/srv/site2/venv/bin/python manage.py collectstatic --noinput --settings=config.settings.production
Run the deployment check separately for every project:
/srv/site1/venv/bin/python /srv/site1/current/manage.py check --deploy --settings=config.settings.production
/srv/site2/venv/bin/python /srv/site2/current/manage.py check --deploy --settings=config.settings.production
Create one Gunicorn service per site
A separate service gives each project independent restarts, deploys, logs, resource accounting, and failure boundaries. The unit must use that site’s working directory, virtual environment, WSGI module, and environment file.
Socket-activated pattern
Socket activation gives Nginx a stable path and lets systemd create the socket with explicit ownership and mode. Create /etc/systemd/system/site1-gunicorn.socket:
[Unit]
Description=site1 Gunicorn socket
[Socket]
ListenStream=/run/site1-gunicorn.sock
SocketUser=nginx
SocketGroup=site1
SocketMode=0660
[Install]
WantedBy=sockets.target
Use the account name used by your distribution’s Nginx worker instead of nginx if necessary. The matching service, /etc/systemd/system/site1-gunicorn.service, can be:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →[Unit]
Description=site1 Gunicorn service
Requires=site1-gunicorn.socket
After=network.target
[Service]
Type=notify
User=site1
Group=site1
WorkingDirectory=/srv/site1/current
EnvironmentFile=/srv/site1/.env
ExecStart=/srv/site1/venv/bin/gunicorn
--workers 3
--bind unix:/run/site1-gunicorn.sock
config.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target
Repeat the pair with unique names, paths, users, and WSGI modules for site2. Do not copy the worker count blindly: the correct number depends on application behavior, available memory, request latency, and background work. The documented primitives do not provide a universal multi-site formula or benchmark.
If you do not want socket activation, run a service that binds only to a unique loopback port, such as 127.0.0.1:8101 for site1 and 127.0.0.1:8102 for site2. Never reuse a port.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
Enable and test every service
sudo systemctl daemon-reload
sudo systemctl enable --now site1-gunicorn.socket site1-gunicorn.service
sudo systemctl enable --now site2-gunicorn.socket site2-gunicorn.service
sudo systemctl status site1-gunicorn.service site2-gunicorn.service
sudo journalctl -u site1-gunicorn.service -n 100 --no-pager
Before DNS cutover, test from the local machine. For a Unix socket, the exact curl syntax depends on the installed curl build; use a request that targets the socket and supplies the intended host header. For a loopback listener, test each port directly:
curl -i -H 'Host: site1.example' http://127.0.0.1:8101/
curl -i -H 'Host: site2.example' http://127.0.0.1:8102/
A successful local response proves that the WSGI import, environment, database connection, and application process work before Nginx is added.
Configure Nginx server blocks
Reject unknown hostnames
Define a default server that does not route an unrecognized Host header to one of your applications. Returning status 444 is a common Nginx policy; use another explicit rejection response if it better fits your operations.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
Route site1
Create a dedicated file such as /etc/nginx/sites-available/site1.example and enable it using your distribution’s normal sites-enabled mechanism:
server {
listen 80;
listen [::]:80;
server_name site1.example www.site1.example;
location /static/ {
alias /srv/site1/shared/static/;
}
location /media/ {
alias /srv/site1/shared/media/;
}
location / {
proxy_pass http://unix:/run/site1-gunicorn.sock;
proxy_set_header Host $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_redirect off;
}
}
The trailing slash in each alias value is intentional. It maps the URL prefix to the corresponding filesystem directory. Ensure the Nginx worker can traverse every parent directory and read the files.
Route site2 to its own upstream
server {
listen 80;
listen [::]:80;
server_name site2.example www.site2.example;
location /static/ {
alias /srv/site2/shared/static/;
}
location /media/ {
alias /srv/site2/shared/media/;
}
location / {
proxy_pass http://unix:/run/site2-gunicorn.sock;
proxy_set_header Host $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_redirect off;
}
}
If you use loopback TCP instead, replace the corresponding proxy_pass value with http://127.0.0.1:8101 or http://127.0.0.1:8102. Keep the mapping one-to-one: a site1 server block must never point at site2’s endpoint.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteRank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Validate before reloading
sudo nginx -t
sudo systemctl reload nginx
Always run the syntax test first. A reload applies the new configuration without unnecessarily terminating existing connections; if validation fails, keep the running configuration and inspect the reported file and line.
Add HTTPS for every public domain
Obtain a certificate covering each hostname, then create TLS server blocks on port 443. Redirect the corresponding port-80 block to HTTPS after certificate validation:
server {
listen 80;
listen [::]:80;
server_name site1.example www.site1.example;
return 301 https://$host$request_uri;
}
The HTTPS block retains site1’s static/media locations and socket, but adds the certificate paths and listens on 443:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name site1.example www.site1.example;
ssl_certificate /etc/ssl/site1/fullchain.pem;
ssl_certificate_key /etc/ssl/site1/privkey.pem;
location /static/ { alias /srv/site1/shared/static/; }
location /media/ { alias /srv/site1/shared/media/; }
location / {
proxy_pass http://unix:/run/site1-gunicorn.sock;
proxy_set_header Host $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_redirect off;
}
}
Repeat with site2’s certificate and upstream. If TLS terminates at another trusted proxy before this Nginx instance, establish a single, well-defined termination layer and restrict which proxy addresses Django trusts. Do not blindly trust client-supplied forwarded headers from the public internet.
Free tools Windows power users keep installed
One-click scans. No signup required.
Set Django’s production security settings per project
Hosts and CSRF origins
With DEBUG = False, Django requires an explicit ALLOWED_HOSTS list. Configure only the domains that belong to that project:
DEBUG = False
ALLOWED_HOSTS = ["site1.example", "www.site1.example"]
CSRF_TRUSTED_ORIGINS = ["https://site1.example", "https://www.site1.example"]
Use the equivalent list for site2. These settings prevent an arbitrary Host header from being treated as a valid site and make cross-site form protection match the actual HTTPS origins.
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Secrets, cookies, and proxy-aware HTTPS
Load SECRET_KEY, database passwords, email credentials, and other secrets from the per-site environment or a secrets manager. Keep them out of source control. When Nginx terminates TLS and sends X-Forwarded-Proto, configure Django consistently:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
Only set SECURE_PROXY_SSL_HEADER when the proxy is configured to overwrite the header and the network path is trusted. Otherwise an attacker may be able to spoof the scheme. Sites that support login should use HTTPS site-wide because passwords, session cookies, and password-reset tokens are credentials.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Static and media paths
Each project needs distinct roots:
STATIC_URL = "/static/"
STATIC_ROOT = "/srv/site1/shared/static"
MEDIA_URL = "/media/"
MEDIA_ROOT = "/srv/site1/shared/media"
Set site2’s values to its own directories, then rerun collectstatic after deployments that change assets. Do not point two projects at one writable media directory unless sharing is an intentional, separately secured design.
Unix sockets or loopback TCP ports?
Both approaches keep Gunicorn private. Choose according to your operational needs rather than assuming one is universally faster.
| Consideration | Unix socket | Loopback TCP |
|---|---|---|
| Permission management | Requires correct socket user, group, mode, and directory access. | Uses local network binding and avoids filesystem socket ACLs. |
| Observability | Socket existence and ownership are useful diagnostics, but tooling is less familiar to some teams. | Standard port checks and local HTTP tools make endpoint testing straightforward. |
| Portability | Convenient when Nginx and Gunicorn share one host. | Easier to move the application to another host or container without changing the protocol. |
| Cross-host support | Not usable across machines. | Can support a separate host when protected by a private network and appropriate access controls. |
| Failure diagnosis | Check the path, service state, ownership, group, and mode. | Check that the process listens on the expected address and that no other service owns the port. |
One shared Gunicorn service or one per site?
A single service can reduce unit-file overhead, but it couples applications operationally. Separate services are usually the safer default for unrelated sites.
| Axis | Shared service | Separate service per site |
|---|---|---|
| Isolation | One process configuration and lifecycle may affect several projects. | Each project has its own environment, workers, logs, and restart boundary. |
| Deployments | Coordinating code and dependency changes is more complex. | Deploy and restart one site without touching the others. |
| Blast radius | A crash, bad import, or resource spike can affect all applications in the service. | A failing site normally leaves the other services running. |
| Resource accounting | Usage is harder to attribute to a particular project. | Per-unit status, logs, limits, and alerts are clearer. |
| Overhead | Fewer units and endpoints to maintain. | More configuration files, service names, sockets, and health checks. |
Separate services do not remove host-level limits. Monitor memory, CPU, file descriptors, database connections, and disk space across the machine, and set resource limits only after measuring each workload.
Deployment sequence that minimizes surprises
- Provision the Linux host, firewall rules, DNS records, and per-site users or service identities.
- Create each project’s directory tree and virtual environment; install pinned dependencies.
- Set production secrets and settings, then run migrations and
collectstaticfor each database and project. - Add and validate each Gunicorn service and socket (or loopback port); enable them with systemd.
- Verify socket ownership or port bindings and test each WSGI application locally.
- Add Nginx’s default rejection server and one server block per domain.
- Run
nginx -t, reload Nginx, and test each hostname with an explicit Host header. - Install certificates, add HTTPS blocks and HTTP-to-HTTPS redirects, then reload again.
- Run
check --deployfor every site, inspect application and Nginx logs, and verify static files, media access, login, redirects, and error pages. - Restart one site deliberately and confirm the other domains remain available before declaring the setup operational.
Troubleshoot by following the request path
| Symptom | Checks and corrective action |
|---|---|
| 502 Bad Gateway | Check that the matching Gunicorn unit is active, the socket or port exists, the WSGI module imports under that site’s virtual environment, and Nginx can connect. For sockets, inspect user, group, mode, and parent-directory permissions. |
| The wrong site appears | Inspect DNS resolution, the request’s Host header, exact server_name values, the default server, and the upstream path in the selected block. Confirm that no site points at another project’s socket or port. |
| Static files return 404 | Check that STATIC_ROOT matches the Nginx alias, rerun collectstatic, verify URL prefixes, and grant Nginx read and directory-traverse permission. |
| Media files fail | Verify MEDIA_ROOT, the matching /media/ alias, filesystem permissions, and whether the application actually wrote the file under that site’s media directory. |
| Redirect loop or insecure URL | Ensure Nginx sends X-Forwarded-Proto, Django’s proxy-SSL setting matches the trusted TLS topology, and only the intended layer performs HTTPS redirects. |
| Permission denied on socket | Align SocketUser, SocketGroup, SocketMode, the Gunicorn service identity, and Nginx’s worker account. Recreate the socket after changing the unit and reload systemd. |
| Changes do not appear | Confirm that the deployment updated the directory named by WorkingDirectory, restarted the correct unit, and did not leave an old virtual environment or process serving the request. |
Operational checks after launch
- Keep Nginx access/error logs and each Gunicorn service log separated by site.
- Alert on repeated Gunicorn restarts, rising 5xx responses, socket disappearance, disk exhaustion, and memory pressure.
- Test every hostname after certificate renewal, Nginx changes, Django upgrades, and dependency updates.
- Back up each database and media directory independently, and document how to restore one site without restoring all sites.
- Review forwarded-header trust whenever the proxy topology changes.
- Run the Django deployment check again after changing security, host, cookie, database, or email settings.
The Bottom Line
The reliable multi-site pattern is simple: Nginx is the only public router, every hostname has its own server block, and every Django project has an independent Gunicorn service and private endpoint. Correct host validation, HTTPS, forwarded headers, static-file ownership, and socket permissions determine whether that design remains secure and supportable in production.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

