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
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
The reliable production path for a Django site on one virtual private server is browser → Nginx → Gunicorn → Django → PostgreSQL. Nginx accepts HTTP or HTTPS traffic and serves static files, Gunicorn runs Django’s WSGI application, and Django uses PostgreSQL for persistent data. This design gives a small team direct control over the server without requiring containers, but you must configure security, migrations, backups, TLS, logging and restart behavior before sending users to it.
Django’s documentation is explicit: “The runserver command starts a lightweight development server, which is not suitable for production.” Use runserver only for local development; use a process manager and a production web server on the VPS.
Recommended Free Tools
What you are building
A single-VPS deployment separates responsibilities so that each component does one job:
| Component | Responsibility | Publicly reachable? |
|---|---|---|
| Browser | Requests pages, APIs, static assets and media. | Yes, through the domain. |
| Nginx | Terminates HTTP/HTTPS, applies request limits and headers, serves static files, and proxies application requests. | Yes, on ports 80 and 443. |
| Gunicorn | Runs Django’s WSGI application workers. | No; bind it to a Unix socket. |
| Django | Handles URLs, views, templates, authentication and application logic. | No direct listener is required. |
| PostgreSQL | Stores relational application data. | Preferably only on localhost or a private network. |
This pattern suits a small production site, an internal application or a team that wants a straightforward VM rather than a container platform. It is not automatically highly available: one VPS remains one failure domain, and upgrades, backups, monitoring and capacity planning remain your responsibility.
#1 Best Overall
- Powerful Turbo Fan:CAGIWIRU Electric Air Duster have reached speed up to 130000RPM,Can efficient remove dust and debris.With LED light and Three Adjustable Speed to meet with different cleaning tasks.
- With Attached USB C Fasting Charging cable.Charing 3 hours,Enjoy up to 240 minutes of use on the lowest setting, For third speed can use for 25mins.with four charging options to meet with your needs.
- Wide Application:Upgraded attached 5 different nozzles,making it suitable for a variety of scenes, such as car,pet, pc, keyboards, and other electronic devices. It also serves for office and home clean duster.
- Handy Design & Portable:Cordless air duster electric nozzle is Light weight and small size, design and comfortable to hold and space saving, convenient to carry around. You can put it in your room or inside the car without taking up space.
- Warranty & Support: Our Electric air duster comes with 5 years warranty and 24/7 customer service. During this period, if you have any questions,pls kindly feel free to contact us.
Plan the VPS before installing software
Choose the operating system and access model
Use a currently supported Linux distribution supplied by your VPS provider. The commands below assume a Debian-family system with apt; package names and service defaults can differ on another distribution. Log in with an administrative account only long enough to create and secure a separate deploy account.
- Create a non-root user for deployments and give it administrative access through
sudo. - Install your SSH public key for that user and test a second session before disabling password authentication.
- Record the VPS address, the eventual domain name, the application path and where backups will be stored.
- Decide whether PostgreSQL runs on this VPS or on a managed/remote database. A remote database still needs the PostgreSQL client library and, commonly, the
libpq-devbuild package for Python drivers.
Allow only required network ports
At the provider firewall and on the host firewall, allow SSH from the addresses that administer the server, HTTP during certificate issuance and redirects, and HTTPS for normal traffic. Do not expose Gunicorn’s socket or PostgreSQL’s database port to the public internet unless a private-network design specifically requires it.
Free tools Windows power users keep installed
One-click scans. No signup required.
Prepare the server
After connecting as the administrative user, update package metadata and install the tools required to obtain, build and serve the application:
sudo apt update
sudo apt upgrade
sudo apt install python3 python3-venv python3-pip git nginx ufw postgresql postgresql-contrib libpq-dev
If PostgreSQL is remote, install the client and development packages you need rather than running a local database service. Create a conventional directory layout owned by the deploy user. Keeping releases and shared configuration separate makes rollback easier:
sudo adduser --disabled-password --gecos "" deploy
sudo usermod --append --groups sudo deploy
sudo mkdir -p /srv/myproject/{releases,shared,run}
sudo chown -R deploy:deploy /srv/myproject
Replace myproject with your project’s directory name. Do not place secrets in the Git checkout; create a protected environment file under the shared directory:
sudo install -o deploy -g deploy -m 600 /dev/null /srv/myproject/shared/.env
Get the Django code and create its virtual environment
Switch to the deploy user, clone the repository into a release directory, and create an isolated Python environment. Pin application dependencies in a lock file or a fully versioned requirements file so a later release does not silently select incompatible packages.
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 minutesudo -iu deploy
cd /srv/myproject/releases
git clone https://example.com/your-project.git 2026-10-14
cd 2026-10-14
python3 -m venv /srv/myproject/shared/venv
. /srv/myproject/shared/venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install gunicorn
The repository URL above is an example; use your actual Git remote. If the project uses a packaging tool instead of requirements.txt, run that tool’s production install command inside the same virtual environment. Make the release path a symlink only after it has passed checks:
Rank #2
- Screen Cleaner is Your Screen’s New Bestfriend! - EVEO is proud to present a screen cleaner that’s perfectly suited for your TV. Meet your new screen cleaner, computer screen cleaner, laptop cleaner, iPad cleaner, Macbook,tv cleaner or any other electronic device. Our screen cleaner spray and wipe along with the included plush microfiber cloth, easily removes dust, fingerprints & other smudges on the screen’s surface. Clean effectively for a streak-free screen
- Gentle on your Screens - Our screen cleaner spray and wipes is compatible to be used even for the most sensitive LCD, LED, CRT, and OLED screens in proper use. Be at ease knowing that this product is compatible with all the major brands: LG, SONY, Samsung, Sharp, iPad, iPhone, Android screens, Kindle, PC monitors - we’ve got you covered! Can be used as LCD screen cleaner, tv cleaner, smart tv screen cleaner, and more
- Premium Super Soft Plush Microfiber Cloth - Included in this efficient screen cleaning kit. This screen cleaner spray and wipe has our signature plush microfiber cloth specially designed to comply with screens and monitors and leave them streak-free. Has been shown to effectively absorbs stubborn stains, zero streaks, and no fiber shedding. Always use this together with our screen cleaner for the best results
- Easy-to-Use Screen Cleaner Kit + microfiber cleaning cloth - The EVEO Screen Cleaning Kit will easily be your new favorite tool when it comes to taking care of the things you love most, quick and easy solution for a streak-free screen. Simply screw on the sprayer gun on the screen cleaner bottle. Spray the cleaning liquid onto the microfiber cloth, then wipe the screen until desired cleanliness & shine is achieved.
- Quality Screen Care Kit Worth Purchasing - Enjoy a convenient Screen Cleaner anytime, anywhere you need it. Your satisfaction is our top priority. We stand behind the quality of our products and that’s why, you shouldn’t be worrying at all. We manufacture the Best Screen Cleaner. and can be used for laptop cleaning kit, laptop screen cleaner, tv screen cleaner for smart tv. MacBook screen cleaner, monitor cleaner or screen cleaner spray for electronic devices with microfiber cleaning cloth
ln -sfn /srv/myproject/releases/2026-10-14 /srv/myproject/current
Set environment variables
Put the Django secret key, database connection details and deployment settings in /srv/myproject/shared/.env. A typical file contains values like these, with real secrets substituted on the server:
DJANGO_SETTINGS_MODULE=config.settings.production
SECRET_KEY=replace-with-a-long-random-value
DEBUG=False
ALLOWED_HOSTS=www.example.com,example.com
CSRF_TRUSTED_ORIGINS=https://www.example.com,https://example.com
DATABASE_URL=postgresql://app_user:database-password@127.0.0.1:5432/app_db
Your settings loader must actually read this file or systemd must import it. Keep permissions at mode 600, restrict ownership to the deploy user (or a dedicated service account), and never commit the file, print it in logs or paste its contents into an issue.
Configure Django for production
Production settings must be explicit. In addition to loading the secret and database values, configure:
Crashes, 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 minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11DEBUG = False.ALLOWED_HOSTSwith every hostname that should serve the application, and no wildcard unless you understand the security consequences.CSRF_TRUSTED_ORIGINSwith the complete scheme and hostname, such ashttps://example.com.SECURE_PROXY_SSL_HEADERso Django recognizes HTTPS after Nginx terminates TLS. Set it only when Nginx is the trusted proxy and sends the corresponding header.SECURE_SSL_REDIRECT = Truewhen all production traffic should use HTTPS.SESSION_COOKIE_SECURE = TrueandCSRF_COOKIE_SECURE = Trueonce HTTPS is working.- A production email backend, allowed file-storage locations and a logging configuration that sends errors to systemd or a central collector.
Run Django’s deployment audit before exposing the site:
cd /srv/myproject/current
. /srv/myproject/shared/venv/bin/activate
python manage.py check --deploy
Treat every warning as a release task. The check is useful, but it cannot validate your firewall, database backup process, business permissions or application-specific authorization.
Set up PostgreSQL
Local PostgreSQL on the VPS
If the database is local, create a dedicated database role and database rather than using the PostgreSQL superuser. Run these commands as the PostgreSQL administrator:
sudo -u postgres psql
CREATE ROLE app_user LOGIN PASSWORD 'use-a-strong-unique-password';
CREATE DATABASE app_db OWNER app_user;
q
Use a password generated for this application only. Keep PostgreSQL listening on localhost unless a private network requires another address. Restrict database access in PostgreSQL’s client-authentication rules and the host firewall. If the database is managed elsewhere, create the role and database there, require TLS as appropriate, and put the remote host and port in your environment configuration.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Rank #3
- 【Large size】:Measuring 800 x 300 mm/ 31. 5×12 inches, which is wider and taller than others. Large mouse pad can perfectly fit your keyboard and mouse of any size, and there is also ample space for peripherals such as phones, tablets, etc.
- 【LED backlight mouse pad】:Blade Hawks RGB mouse pad provides 7 static modes and 7 dynamic modes will give you the options you are looking for. Power-off memory function remembers the last lighting mode you selected. The super glow fiber Chroma will give you a colorful gaming setup that you want.
- 【Anti-slip rubber base】:Made from Natural rubber, this gaming mousepad will firmly grip your desktop, allowing you to enjoy the ultimate precision in the games you are most passionate about. It also comes with a texture that enhances this ability even further.
- 【Smooth and waterproof surface】: Micro-textured cloth surface, for extremely precise mouse control and a smooth movement. When liquid splashes on the gaming mouse pad, it forms water droplets and slides down. Will not delay your work or gameplay.
- 【Plug and play】: This mouse and keyboard pad is powered by USB, plug and play, no driver required. One button control light modes. Press one time to change the lighting mode, press twice to change the brightness, press and hold about 3 seconds turn ON/OFF.
Apply migrations deliberately
Migrations change the database schema and are part of a release, not an ad hoc repair. From the release directory, inspect the migration plan and apply it with the same environment used by Gunicorn:
cd /srv/myproject/current
. /srv/myproject/shared/venv/bin/activate
python manage.py makemigrations --check
python manage.py migrate --noinput
For each release, keep a database backup and a rollback plan. Code rollback alone cannot undo a destructive schema migration. Test backward-compatible migration ordering, record which migration ran, and know how to restore the database before deploying a change that removes or transforms data.
Collect and serve static and media files
Django does not make production static-file serving happen automatically. Define STATIC_ROOT and run:
python manage.py collectstatic --noinput
Point Nginx at the resulting directory and serve it directly. User-uploaded media should have a separate MEDIA_ROOT; serving it from a location that permits script execution is unsafe. For a small single-server site, both directories can live under a protected shared path, while larger deployments often move immutable static assets and media to object storage.
Run Gunicorn with systemd
Gunicorn belongs in the virtual environment and should not be started from an SSH shell. A systemd socket lets Nginx connect through /run/gunicorn.sock and allows systemd to start the service at boot.
Create the socket unit
Create /etc/systemd/system/gunicorn.socket as root:
[Unit]
Description=Gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
SocketUser=www-data
SocketGroup=www-data
SocketMode=0660
[Install]
WantedBy=sockets.target
Create the service unit
Create /etc/systemd/system/gunicorn.service. Adjust the Django module name and worker command to your project:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #4
- 【Softer and More Comfortable】Vaydeer wrist rest has unique diamond pattern, which is the combination of softness and aesthetics. The materials of wrist rest are improved into higher quality memory foam and covered with silky smooth lycra. The computer wrist rest makes you as comfortable and cushiony as like rest your wrists on clouds.
- 【Ergonomic Wrist Saver】The wrist rests for keyboard and mouse comes with a 17.32×3.15×0.83 inch keyboard wrist pad and a 5.94×3.15×0.83 inch mouse wrist support. Based on ergonomic design, the unique concave shape is the perfect fit for your wrist joints. The wrist rest pad fits most computer keyboards and laptops, improve hand and wrist posture, release your wrist and arm stress.
- 【Non-Slip Rubber Bottom】Featuring an anti-skid silicone base on the bottom, this wrist keyboard support stays firmly in place on your desk, preventing the padding from sliding around, ensuring stable and consistent wrist support during extended computer sessions.
- 【Better Experience & Pain Relief】Our keyboard arm rest is beneficial to alleviate the soreness caused by direct contact and friction between your arm and a hard desk surface, reducing the risk of wrist fatigue or carpal tunnel. The soft texture of memory foam can evenly distribute the pressure around your wrists and provide good support with just enough give.
- 【Helpful in Multiple Scenarios】Whether you're working, studying, writing, typing, gaming, this keyboard and mouse rest combo is an essential accessory to add comfort and support to your hands and wrists. It’s also a great gift for men, women, family, friend, coworker, gamer, teacher, etc.
[Unit]
Description=Gunicorn daemon for myproject
Requires=gunicorn.socket
After=network.target
[Service]
Type=notify
User=deploy
Group=www-data
WorkingDirectory=/srv/myproject/current
EnvironmentFile=/srv/myproject/shared/.env
ExecStart=/srv/myproject/shared/venv/bin/gunicorn
--workers 3
--bind unix:/run/gunicorn.sock
config.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
The worker count is an operational starting point, not a performance promise. Tune it only after observing memory use, response latency and concurrent workload. An application that needs long-lived asynchronous connections or other ASGI features may require an ASGI server and a different service command; Gunicorn in this guide is the WSGI path.
Enable and test the socket
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn.socket
sudo systemctl status gunicorn.socket
sudo systemctl status gunicorn
sudo journalctl -u gunicorn --since "10 minutes ago"
Confirm that /run/gunicorn.sock exists and that Nginx’s user can access it. If the service exits, inspect the journal before changing configuration; common causes are an incorrect module path, missing environment variables, an import error or a failed database connection.
Configure Nginx as the public entry point
Create a server block under /etc/nginx/sites-available/myproject. The example proxies dynamic requests to the Unix socket and serves static and media paths directly:
server {
listen 80;
server_name example.com www.example.com;
location /static/ {
alias /srv/myproject/shared/static/;
}
location /media/ {
alias /srv/myproject/shared/media/;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
Ensure the directories named by alias exist, contain the files produced by collectstatic, and have permissions that allow Nginx to read them. Do not point Nginx at the Git repository if releases are switched by symlink; use stable shared paths for generated static and media content.
Enable the site, validate the syntax and reload only after a successful test:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/myproject
sudo nginx -t
sudo systemctl enable nginx
sudo systemctl reload nginx
Keep Gunicorn bound to its Unix socket. Binding it to a public TCP address bypasses Nginx’s access controls and exposes an unnecessary application endpoint.
Point DNS at the VPS and enable HTTPS
- Create an address record for the production hostname pointing to the VPS address. Add a second hostname only if the application and certificate are configured for it.
- Put exactly those hostnames in Django’s
ALLOWED_HOSTSand the corresponding HTTPS origins inCSRF_TRUSTED_ORIGINS. - Ensure port 80 is reachable for certificate validation and HTTP-to-HTTPS redirection.
- Use Let’s Encrypt or another certificate service to obtain a certificate, configure Nginx to listen on 443, and redirect port 80 to HTTPS.
- After TLS works, enable Django’s secure redirect and secure cookies, then rerun
python manage.py check --deploy.
Certificate renewal is an operations task. Verify that the renewal timer exists, that Nginx reloads successfully after renewal, and that an expired certificate cannot silently take the site offline.
Best Value
- 【No Drill Mounted】Cable management tray can be assembled in as little as 3 minutes or less-simply. Side clips easily clampe the edge of desk, pass through the holes on the sides, and secure excess cables with baskets. Desk cable management supports inward or outward installation to meet your needs in different scenarios, and provides you with great convenience when collecting and organizing wires.
- 【Rubber Pad Protects Desk】Wire organizer under desk built-in soft rubber pads on the clamp protect your desk from scratches, so you will not damage your furniture or office.
- 【Sturdy and Beautiful】Cord management under desk is made of high-quality carbon steel and holds about 15 lbs. The wire basket has 2 holes on each side of the tray to enable your cables to pass freely. Cable baskets are suitable for desk thickness use from 0.4" to 2.4".
- 【Space Saving & Keep Organized】Desk cable management tray holds all your power cords, outlet strips, USB hubs and computer transformers hidden from your feet, and the data cables will not enter the vacuum cleaner to keep your desk clean and tidy. Desk wire organizer is also suitable for use in the kitchen and outdoors.
- 【Reduce Safety Risks】Cable tray under desk keeps all plugs away from your kids, no more worry about tripping. Using 2 holes wire tray saves extra space, helps you easily cabling and wire protection. The mesh design is not easy to accumulate dust, but avoids safety accidents caused by messy wires.
Use a repeatable release procedure
A release should be an observable sequence rather than a collection of commands typed from memory:
- Build or select a new versioned release directory and install its pinned dependencies in the shared virtual environment or a versioned environment.
- Review environment changes and confirm the backup and rollback plan.
- Run
python manage.py check --deploy, migration checks and tests without changing the live symlink. - Run
collectstatic --noinputinto the shared static directory. - Take the database backup required by the migration plan.
- Apply migrations.
- Switch
/srv/myproject/currentto the tested release. - Reload Gunicorn with
sudo systemctl reload gunicorn; restart only when a reload is insufficient. - Run an HTTP smoke test, check the admin login and inspect the service and Nginx logs.
If a release fails, switch the symlink back to the previous code only when its database schema remains compatible. Restore the database when a migration changed data and cannot be safely reversed. Record the failed release and the corrective action.
Verify the complete request path
Check locally on the VPS
sudo ss -lx | grep gunicorn.sock
sudo systemctl is-active gunicorn.socket
sudo systemctl is-active nginx
sudo nginx -t
curl --unix-socket /run/gunicorn.sock http://localhost/
The socket request should produce a Django response or redirect. A 502 from Nginx usually means the socket is absent, permissions are wrong, Gunicorn is stopped or the proxy path does not match the unit.
Check publicly
curl -I http://example.com
curl -I https://example.com
curl -I https://example.com/static/app.css
Confirm that HTTP redirects to HTTPS, HTTPS returns the expected status, static files do not pass through Django unnecessarily, and media URLs behave according to your privacy policy. Test a form submission and an authenticated admin session because CSRF and secure-cookie mistakes often appear only after login.
Inspect logs when something fails
journalctl -u gunicorn -fshows Python import errors, worker exits and database connection failures.journalctl -u nginx -fand Nginx access/error logs show proxy failures, permission errors and unexpected status codes.- Django’s application log should include a request identifier or enough context to correlate an error with the reverse-proxy timestamp, without logging passwords, session cookies or secret keys.
Common failure modes and fixes
| Symptom | Likely cause | First checks |
|---|---|---|
| Nginx returns 502 Bad Gateway | Gunicorn is stopped, the socket path differs, or Nginx cannot read the socket. | Check both systemd units, ls -l /run/gunicorn.sock, the service journal and the socket’s group permissions. |
| Django reports “DisallowedHost” | The requested hostname is missing from ALLOWED_HOSTS. |
Compare the browser hostname, Nginx server_name and the environment value, then reload Gunicorn. |
| CSRF verification fails after HTTPS | The HTTPS origin is absent or the proxy HTTPS header is incorrect. | Check CSRF_TRUSTED_ORIGINS, SECURE_PROXY_SSL_HEADER and the Nginx proxy headers. |
| CSS or JavaScript returns 404 | collectstatic was not run, STATIC_ROOT is wrong, or the Nginx alias path is incorrect. |
Inspect the collected file and request the exact static URL with curl. |
| Database connection fails | Wrong credentials, host, port, TLS requirement or firewall rule. | Test the connection with the PostgreSQL client from the VPS and inspect the environment file permissions and values. |
| Changes do not appear after deployment | The current symlink was not switched or Gunicorn workers still use the previous code. | Print the symlink target, reload Gunicorn and inspect its start time in systemd. |
Backups, security and ongoing operations
- Back up PostgreSQL on a schedule and test restoration on a separate system; a backup that has never been restored is only an assumption.
- Keep operating-system packages, Python dependencies and Django security updates current, with a maintenance window and rollback plan.
- Use least-privilege database credentials and a separate deploy account. Never use the PostgreSQL superuser from Django.
- Store secrets outside source control with restrictive permissions, rotate them when staff or infrastructure changes, and avoid exposing them in process listings or logs.
- Monitor disk space, memory, CPU, database growth, certificate expiry, failed systemd units and HTTP error rates.
- Restrict SSH, disable unused services, use key-based authentication and review firewall rules after every infrastructure change.
- Document who can deploy, where the current release lives, how to restore the database and how to recover if the VPS is unavailable.
When a different architecture is better
The Nginx–Gunicorn–Django arrangement is intentionally simple, but it is not the only valid production design.
| Option | Advantages | Trade-offs and questions |
|---|---|---|
| Single VPS (this guide) | Direct control, predictable layout and low architectural complexity. | One failure domain; you manage patching, backups, scaling and certificates. |
| PaaS | Automated builds, deployment workflows, certificates and often managed databases. | Less host-level control, provider-specific behavior and potentially higher recurring cost. |
| Docker Compose on one VM | Reproducible service versions and clear separation of application, proxy and database containers. | More moving parts; persistent volumes, networking, upgrades and backups still need operations work. |
| Caddy or another reverse proxy | Can simplify certificate management and configuration for teams that prefer its workflow. | Different syntax and operational conventions; the same application, database, backup and availability responsibilities remain. |
| Managed PostgreSQL | Provider-managed database patching, replication options and backup tooling. | Network latency, provider cost, credentials and private connectivity need consideration. |
| ASGI deployment | Appropriate for asynchronous views, WebSockets or other ASGI-specific behavior. | Requires an ASGI-compatible server and a design for long-lived connections; the WSGI Gunicorn setup here may not be sufficient. |
Choose another architecture when you need multiple application instances, high availability, automated horizontal scaling, container orchestration, asynchronous protocols or a database that must survive loss of the application VM. For a small Django deployment with ordinary synchronous requests, the single-VPS pattern remains a practical starting point when its operational limits are accepted.
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.

