Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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

The reliable production path for a small or moderate Django-and-React application is Browser → Nginx → Gunicorn → Django → PostgreSQL. Nginx terminates HTTPS, serves the React build and Django static/media files, and forwards API requests to Gunicorn. Gunicorn runs Django under systemd rather than the development server. The procedure below covers a single Ubuntu VPS, from a secured host and database through releases, TLS, verification, and rollback.

What the finished deployment looks like

A browser requests your domain. Nginx is the only public application entry point: it serves files that do not require Python, sends /api/ (and any other Django routes you choose) to Gunicorn, and provides the SPA fallback that lets React Router handle client-side URLs. Gunicorn listens only on a Unix socket or loopback address. Django reads PostgreSQL credentials and other secrets from the server environment, not from Git.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Nginx: ports 80 and 443, TLS termination, static files, media files, React history fallback, and reverse proxying.
  • Gunicorn: a production WSGI server running Django under systemd supervision.
  • Django: API, authentication, admin, server-rendered routes if any, and business logic.
  • React: a compiled production directory generated by the project’s build tool.
  • PostgreSQL: the application database, either on this VPS or on a managed service.

manage.py runserver is a development server. Do not expose it to production traffic; Django’s deployment guidance requires a production WSGI or ASGI server and a completed deployment checklist.

Before you start

Access and DNS

  • An Ubuntu VPS with administrative access and a supported Ubuntu release.
  • A domain whose DNS A (and, if used, AAAA) record points to the VPS address. Set this before requesting a certificate.
  • An SSH key for administration. You should be able to log in without a password before disabling password authentication.
  • A repository containing the Django project and React frontend, with documented build and start commands.

Decisions that affect the commands

  • Confirm the Django WSGI import path, such as myproject.wsgi:application.
  • Find the frontend’s actual build output in package.json and its tool configuration. Common names are dist and build, but do not assume either.
  • Confirm the React API base URL and whether production requests use /api/ on the same origin. A hard-coded localhost URL will fail after deployment.
  • Choose whether PostgreSQL is local or managed. A managed database reduces patching and backup work; a local database keeps the system self-contained but makes you responsible for its availability and backups.

1. Prepare and secure Ubuntu

Log in as the initial administrative user, update the host, and install the operating-system components needed for Python, Node-based builds, PostgreSQL (if self-hosted), Git, and Nginx.

#1 Best Overall
Sale
Compressed Air Duster,130000RPM Super Power Cordless Air Duster,Rechargeable Brushless Blower,3 Gear Adjustable Blower with LED Light,Dust Remover for Computer/House/Outdoor/Car
  • 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: 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.
  • Economical &Reusable: Built durable materials with a long-lasting battery,our CAGIWIRU air duster it's a sustainable alternative to disposable air cans.
sudo apt update
sudo apt upgrade
sudo apt install python3 python3-venv python3-pip python3-dev build-essential git nginx postgresql postgresql-contrib

Create a dedicated, non-root account for deployments and application processes. Give it ownership of the application directory, and use SSH keys for that account. Keep direct root login disabled once key-based access has been tested. A host firewall should allow SSH, HTTP, and HTTPS only; use your provider’s firewall or Ubuntu’s firewall tooling according to your operating policy.

sudo adduser deploy
sudo usermod -aG www-data deploy
sudo mkdir -p /srv/myapp
sudo chown -R deploy:deploy /srv/myapp

Do not put database passwords, Django’s SECRET_KEY, cloud credentials, or certificate private keys in the repository. Keep them in a root-readable environment file or a secrets manager, with permissions that prevent unrelated users from reading it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Install the application in a controlled directory

Switch to the deploy account, clone a known commit, and separate backend and frontend paths if the repository is a monorepo.

sudo -iu deploy
cd /srv/myapp
git clone <repository-url> current
cd current
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt

Pin Python dependencies in the project’s requirements or lock file. If native packages fail to compile, install the specific system development library named by the package error rather than bypassing dependency pinning. Keep a record of the commit and dependency set used for every release.

3. Create PostgreSQL and its credentials

For a database on the VPS, create a database role with a password and a database owned by that role. Use a dedicated role; do not configure Django with the PostgreSQL superuser.

sudo -u postgres psql
CREATE ROLE myapp_user LOGIN PASSWORD 'use-a-long-random-secret';
CREATE DATABASE myapp_db OWNER myapp_user;
q

Use the project’s normal PostgreSQL connection variables (for example, database name, user, password, host, and port). If the database is managed elsewhere, use its private endpoint or provider-recommended TLS settings and do not open PostgreSQL to the entire internet. Establish a tested backup and restore procedure before treating the VPS as production-ready.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
EVEO® Screen Cleaner Spray Kit (Streak-Free) TV Screen Cleaner for Smart TV, Lcd, LEd, Oled | Computer Screen Cleaner Spray and Wipe Microfiber Cloth - TV, Monitor, Laptop, iPad, Car - 6.7oz 1 Pack
  • 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

4. Configure Django for production

Create an environment file outside Git. The exact variable names depend on your settings module; the important point is that settings read values from the environment and fail safely when required secrets are missing.

sudo install -o root -g deploy -m 0640 /dev/null /etc/myapp.env
sudoedit /etc/myapp.env

Typical values include:

DJANGO_SECRET_KEY=replace-with-a-random-secret
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=example.com,www.example.com
DJANGO_CSRF_TRUSTED_ORIGINS=https://example.com,https://www.example.com
DATABASE_URL=postgresql://myapp_user:password@127.0.0.1:5432/myapp_db

In production settings, set DEBUG = False, define every hostname in ALLOWED_HOSTS, configure trusted HTTPS origins for CSRF-protected requests, and enable secure session and CSRF cookies when all traffic is HTTPS. Set STATIC_ROOT to a directory Nginx can read, configure media storage deliberately, and send errors to a useful logging destination without leaking secrets. If Nginx terminates TLS, configure Django’s proxy and secure-URL settings consistently with the forwarded HTTPS header.

Run Django’s deployment checks before exposing the site:

cd /srv/myapp/current
. .venv/bin/activate
python manage.py check --deploy

Resolve every warning that applies to your threat model. A warning is not automatically harmless because the application appears to work in a browser.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Apply migrations and collect Django assets

Make database changes an explicit release step. Run migrations against the production database, then collect static files into the configured STATIC_ROOT.

python manage.py migrate
python manage.py collectstatic --noinput

Take a database backup, or verify the managed provider’s restore point, before migrations that alter or remove data. Keep a migration-compatible rollback plan; reverting application code without considering the schema can leave the previous release unable to start.

Rank #3
Sale
BladeHawks RGB Gaming Mouse Pad Extra Large Extended 31.5x12 Inch-Black | LED mouse pad with 14 lighting modes, covers keyboard & mouse, anti-slip rubber base, waterproof surface, USB powered
  • 【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.

6. Build the React frontend

Install the exact locked JavaScript dependencies in the frontend directory and invoke the build script defined by the repository. npm documents npm run-script build (also written npm run build) as the way to run a package’s build script.

cd /srv/myapp/current/frontend
npm ci
npm run build

The output directory is toolchain-specific. Read the build output and package configuration, then use that exact absolute path as Nginx’s document root. Production environment variables, including the API base URL, must be supplied at build time for toolchains that compile them into JavaScript. Rebuild after changing those values; changing a server environment file alone will not alter already-generated browser assets.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

7. Run Django with Gunicorn and systemd

Install Gunicorn in the virtual environment if it is not already pinned, then create a systemd unit. A Unix socket keeps Gunicorn off the public interface; loopback TCP is a valid alternative when your Nginx and deployment layout make it simpler.

cd /srv/myapp/current
. .venv/bin/activate
pip install gunicorn

Create /etc/systemd/system/myapp.service with the correct user, directory, environment file, virtualenv path, and WSGI callable:

[Unit]
Description=Gunicorn for myapp
After=network.target

[Service]
User=deploy
Group=www-data
WorkingDirectory=/srv/myapp/current
EnvironmentFile=/etc/myapp.env
ExecStart=/srv/myapp/current/.venv/bin/gunicorn 
  --workers 3 
  --bind unix:/run/myapp.sock 
  myproject.wsgi:application
Restart= on-failure

[Install]
WantedBy=multi-user.target

Remove the space after Restart= if you copy this unit: the valid directive is Restart=on-failure. Choose worker settings based on the application and available resources rather than copying a universal number. Ensure the service account can create or access the socket directory; many installations use a RuntimeDirectory=myapp setting and bind to unix:/run/myapp/myapp.sock to let systemd create it.

sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp
sudo journalctl -u myapp -e

Fix import errors, missing environment variables, and permission failures here before involving Nginx. A local Gunicorn request is a useful isolation test once the socket exists.

Rank #4
Sale
Vaydeer Wrist Rest for Keyboard and Mouse, Computer Ergonomic Wrist Support Pad, Soft Memory Foam Arm Cushion for Desk, Palm Hand Office Laptop Typing
  • 【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.

8. Configure Nginx for React, Django, and the socket

Create a server block that uses the React build directory as root. The try_files fallback is essential for client-side routes: a refresh of /dashboard must return index.html instead of a 404. Keep API and Django paths ahead of the fallback so they reach Python.

server {
    listen 80;
    server_name example.com www.example.com;

    root /srv/myapp/current/frontend/dist;
    index index.html;

    location /static/ {
        alias /srv/myapp/current/staticfiles/;
    }

    location /media/ {
        alias /srv/myapp/current/media/;
    }

    location /api/ {
        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_pass http://unix:/run/myapp.sock;
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Adjust the React directory, static directory, media directory, and upstream path to your project. If Django also owns non-API URLs, add explicit locations for those paths that proxy to Gunicorn rather than letting the SPA fallback swallow them. Check the configuration before reloading:

sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status nginx

Nginx’s alias paths must match the directories Django actually populated, and the Nginx worker must have permission to traverse every parent directory. Never use a broad writable directory for uploaded media or static assets.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

9. Add DNS and HTTPS

With DNS pointing at the VPS, first make sure the HTTP server block answers for the intended hostname. Obtain a trusted certificate with a supported ACME client such as Certbot, then configure a port 443 server block and redirect HTTP to HTTPS. Ubuntu’s Nginx guidance uses an SSL listener on 443 and an HTTP-to-HTTPS redirect.

After TLS is active, verify that:

  • Both the bare domain and any intended www name resolve to the correct host.
  • HTTP redirects to HTTPS without a loop.
  • Django’s secure-cookie, CSRF-origin, and proxy settings agree with the HTTPS setup.
  • Certificate renewal is enabled and its renewal path is tested, not merely installed.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

10. Verify the complete request path

Test each layer separately, then test it as a user would.

  1. Check service state: sudo systemctl status myapp nginx.
  2. Read recent application errors: sudo journalctl -u myapp --since "15 minutes ago".
  3. Inspect Nginx access and error logs for the exact request and upstream response.
  4. Curl the local upstream or socket through a temporary diagnostic path, then curl the public URL over HTTPS.
  5. Open the React application, sign in, make an API request, refresh a deep client-side route, and sign out.
  6. Request a known CSS, JavaScript, static, and media file directly. In browser developer tools, check the Network and Console tabs for 404, mixed-content, CORS, or JavaScript runtime errors.

Do not call a deployment complete because the home page loads. Authentication, protected API requests, uploads, admin pages, migrations, deep links, and error responses exercise different parts of the configuration.

Best Value
Sale
Under Desk Cable Management Tray No Drill, Metal Mesh Cable Management Under Desk with Clamp Mount, 2 Hole Cable Tray with Wire Management and Cord Organizer for Home Office Standing Desk
  • 【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.

Common failures and targeted fixes

502 Bad Gateway

  • Confirm Gunicorn is running with systemctl status myapp and inspect its journal for import or settings errors.
  • Compare the socket path in proxy_pass with Gunicorn’s --bind value.
  • Check that Nginx can traverse the socket directory and read the socket.
  • Verify the WSGI callable and WorkingDirectory; a wrong module path prevents Gunicorn from starting.

React route returns 404 after refresh

Ensure the SPA location contains try_files $uri $uri/ /index.html; and that a more specific location is not intercepting the route. This fallback belongs on the Nginx server that serves the compiled React files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Missing CSS or JavaScript

  • Confirm the Nginx root is the directory produced by the frontend build, not the source directory.
  • Check the asset URLs in the browser and verify the files exist at those exact paths.
  • For Django assets, rerun collectstatic and verify STATIC_ROOT matches the Nginx alias.
  • Rebuild React after correcting the production API or asset base URL.

403 CSRF or rejected host

Check that the request hostname is in ALLOWED_HOSTS, the HTTPS origin is in the trusted CSRF origins, and Nginx forwards the original host and protocol. Do not solve this by enabling DEBUG or disabling CSRF protection.

Static files work but uploads do not

Static files are generated during release; media files are user data. Configure a persistent media directory or object storage, grant Django write access only where required, grant Nginx read access, and include media backups in the recovery plan.

Release, monitoring, and rollback discipline

Keep the previous known-good commit, dependency lock files, and a database backup or compatible migration plan until smoke tests pass. A repeatable release normally checks out the new commit, installs pinned dependencies, updates environment values if needed, runs migrations, collects static files, builds React, restarts Gunicorn, reloads Nginx, and runs the verification list. Restart only after build and migration commands succeed so a failed release does not replace a working process.

For rollback, restore the previous code and dependency set, apply the database migration plan that is compatible with that code, restart Gunicorn, reload Nginx, and retest login and API requests. A code rollback alone cannot undo a destructive schema change.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choosing alternatives as the application grows

Decision Single-VPS approach Alternative and trade-off
Frontend hosting Nginx serves the React build beside Django. Object storage/CDN can offload static delivery but adds deployment and cache-invalidation configuration.
Python interface Gunicorn WSGI is suitable for ordinary synchronous Django requests. Use an ASGI deployment when the application genuinely needs long-lived connections or realtime workloads; audit every dependency for async compatibility.
Database PostgreSQL runs on the VPS and shares its maintenance window. A managed database shifts patching, backups, and failover operations to the provider but introduces network dependency and separate cost.
Gunicorn binding Unix socket avoids exposing the app listener publicly. Loopback TCP is easier to inspect and can simplify container or multi-process layouts; bind it to loopback, not a public interface.
Releases Manual, documented commands are transparent for a small service. CI/CD can build, test, migrate, and deploy consistently, but requires secret management, rollback automation, and pipeline maintenance.
TLS operations Run certificate issuance and renewal on the VPS with an ACME client. Managed TLS reduces host-level renewal work while adding provider-specific configuration.

Choose the simplest arrangement that meets the application’s availability, traffic, compliance, and operational requirements. Splitting the frontend, API, and database does not remove the need for secure settings, migrations, logging, backups, and a tested rollback.

Production completion checklist

  • SSH keys work for the deploy account; root and unnecessary password access are disabled.
  • DNS resolves correctly, HTTPS is trusted, HTTP redirects, and renewal is scheduled.
  • DEBUG is false; hosts, CSRF origins, secure cookies, proxy settings, and logging are configured.
  • Secrets are outside Git and readable only by the required service accounts.
  • Gunicorn is supervised by systemd and not reachable on a public address.
  • Nginx passes nginx -t, serves the correct React build, proxies API requests, and exposes only intended static/media paths.
  • Migrations and collectstatic completed against the production settings.
  • Backups have a tested restore path, and the release can be rolled back with compatible schema steps.
  • Logs, service status, login, API calls, deep links, uploads, and browser console errors have been checked after deployment.

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.