How to Deploy Django with Gunicorn + Nginx + PostgreSQL on Ubuntu 24.04 VPS
Django is one of the most productive web frameworks available, but getting it into production requires stitching together a handful of moving parts: a WSGI server that can actually handle traffic, a reverse proxy that serves static files and terminates TLS, a real database instead of the default SQLite file, and a process manager that keeps everything running after reboots. This guide walks you through the full production deployment on a fresh Ubuntu 24.04 VPS — from creating a dedicated deploy user to serving your site over HTTPS with automated Let's Encrypt renewal.
Prefer a faster path? Spin up a CloudCore Starter VPS in under a minute and follow this guide from a clean baseline. Plans start at EUR 7.99/month with unmetered bandwidth.
Table of Contents
What You Are Building
By the end of this tutorial you will have a production-grade Django stack running on a single Ubuntu 24.04 VPS with the following layout:
- Nginx listening on ports 80 and 443, terminating TLS and serving
/static/and/media/files directly from disk - Gunicorn running as a systemd service, bound to a Unix socket at
/run/gunicorn.sock, socket-activated so it starts on first request after a reboot - PostgreSQL 16 listening only on
127.0.0.1, with a dedicated role and database for your project - Django installed inside a Python 3.12 virtual environment under a non-privileged
djangouser, reading its secrets from a systemdEnvironmentFile - Certbot with auto-renewal via systemd timer
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- A domain name pointing an A record at your server's public IP (required for TLS in Step 10)
- At least 1 GB of RAM (2 GB+ recommended once PostgreSQL and Gunicorn workers are running)
- At least 20 GB of disk space
Recommended Plan: CloudCore Starter>
For a single Django site with moderate traffic, we recommend the CloudCore Starter plan:>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Unmetered bandwidth
- EUR 7.99/month>
This is enough headroom for Django, PostgreSQL, Redis, and 3-4 Gunicorn workers on the same box.
Connect to your server via SSH as root:
ssh root@your-server-ipStep 1: Update the System and Create a Deploy User
Never run Django (or any public-facing service) as root. Create a dedicated unprivileged user that will own the project directory and run Gunicorn.
Start with a full package refresh:
apt update && apt upgrade -yIf the kernel was updated, reboot and reconnect:
rebootCreate the deploy user and add it to the sudo group (for administrative tasks during setup — you can remove it later):
adduser --disabled-password --gecos "" django
usermod -aG sudo djangoCopy your SSH keys so you can log in as the new user:
rsync --archive --chown=django:django ~/.ssh /home/djangoOpen a new SSH session as the django user to confirm it works:
ssh django@your-server-ipFrom here on, all commands assume you are logged in as django and will use sudo where privilege escalation is required.
Install the baseline build dependencies Python will need to compile packages with C extensions (psycopg, Pillow, etc.):
sudo apt install -y build-essential libpq-dev curl git pkg-configStep 2: Install PostgreSQL 16 and Create the Database
Django's default SQLite backend is fine for development but breaks down under any real concurrency. For production, use PostgreSQL — the most mature and feature-rich option among the databases Django officially supports.
For a full walkthrough with tuning guidance, see our dedicated How to Install PostgreSQL 16 on Ubuntu 24.04 guide. The short version is below.
Install PostgreSQL 16 from the Ubuntu repositories:
sudo apt install -y postgresql postgresql-contribConfirm the service is running:
sudo systemctl status postgresqlSwitch to the postgres OS user and open a psql shell:
sudo -u postgres psqlInside psql, create a role and a database for your project. Replace strongpassword with a long random string — you will reference it later from the environment file.
CREATE DATABASE mysite_prod;
CREATE USER mysite_user WITH PASSWORD 'strongpassword';
ALTER ROLE mysite_user SET client_encoding TO 'utf8';
ALTER ROLE mysite_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE mysite_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE mysite_prod TO mysite_user;
\c mysite_prod
GRANT ALL ON SCHEMA public TO mysite_user;
\qThe ALTER ROLE calls set sensible per-connection defaults that Django expects. The final GRANT ALL ON SCHEMA public is required on PostgreSQL 15+ because the default privileges on the public schema were tightened in that release — without it, migrate will fail with a permission error.
By default PostgreSQL listens only on 127.0.0.1, which is exactly what we want. Do not open port 5432 to the internet.
Step 3: Install Python 3.12 and Create a Virtual Environment
Ubuntu 24.04 ships with Python 3.12 as its system Python, which is supported by Django 5.0 and 5.1. If you need a different version, see our How to Install Python on Ubuntu 24.04 guide for deadsnakes PPA instructions.
Install the venv and pip packages:
sudo apt install -y python3-pip python3-venv python3-devCreate a directory for your project and a virtual environment inside it:
mkdir -p ~/apps/mysite
cd ~/apps/mysite
python3 -m venv venvActivate the environment:
source venv/bin/activateYour shell prompt should now be prefixed with (venv). Upgrade pip inside the venv:
pip install --upgrade pip setuptools wheelEverything installed from here while the venv is active stays isolated inside ~/apps/mysite/venv/ and will not conflict with system Python packages.
Step 4: Install Django, psycopg, and Gunicorn
With the venv active, install the three packages that form the core of the stack:
pip install "Django>=5.0,<6.0" "psycopg[binary]>=3.1" gunicorn python-decoupleA note on each:
- Django — the framework itself. We pin to the 5.x line; pick the version that matches your project.
- psycopg[binary] — the PostgreSQL driver. The
[binary]extra pulls a prebuilt wheel with libpq embedded, which avoids the need for thelibpq-devheaders at runtime.psycopg(v3) is the modern replacement forpsycopg2; Django 4.2+ supports both and the official recommendation is to use v3 for new projects. - gunicorn — the WSGI server. See gunicorn.org for configuration reference.
- python-decouple — optional, for reading
.envfiles. You can substitutedjango-environor plainos.environif you prefer.
requirements.txt so the server can be rebuilt deterministically:pip freeze > requirements.txtStep 5: Create or Clone Your Django Project
If you are starting fresh, scaffold a new project inside the current directory:
django-admin startproject mysite .The trailing dot puts manage.py at ~/apps/mysite/manage.py and the settings module at ~/apps/mysite/mysite/settings.py.
If you already have a project in a Git repository, clone it instead:
cd ~/apps
git clone https://github.com/yourorg/mysite.git
cd mysite
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtVerify the project boots with the development server before moving on:
python manage.py runserver 0.0.0.0:8000Open http://your-server-ip:8000 (you may need to temporarily allow port 8000 through UFW). You should see the Django welcome page or your own project's homepage. Stop the dev server with Ctrl+C — you will never use it again in production.
Step 6: Configure settings.py for Production
Open mysite/settings.py and make the following changes. This is the single most important step for a secure deployment.
import os from pathlib import Path from decouple import config, CsvBASE_DIR = Path(__file__).resolve().parent.parent
SECURITY --------------------------------------------------------------
SECRET_KEY = config("DJANGO_SECRET_KEY") DEBUG = config("DJANGO_DEBUG", default=False, cast=bool) ALLOWED_HOSTS = config("DJANGO_ALLOWED_HOSTS", cast=Csv())Database --------------------------------------------------------------
DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "NAME": config("DB_NAME"), "USER": config("DB_USER"), "PASSWORD": config("DB_PASSWORD"), "HOST": config("DB_HOST", default="127.0.0.1"), "PORT": config("DB_PORT", default="5432"), "CONN_MAX_AGE": 60, } }Static and media ------------------------------------------------------
STATIC_URL = "/static/" STATIC_ROOT = BASE_DIR / "staticfiles" STATICFILES_DIRS = [BASE_DIR / "static"]MEDIA_URL = "/media/" MEDIA_ROOT = BASE_DIR / "media"
TLS and proxy headers -------------------------------------------------
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") SECURE_SSL_REDIRECT = not DEBUG SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True SECURE_HSTS_SECONDS = 31536000 # 1 year SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_PRELOAD = True SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_REFERRER_POLICY = "same-origin" X_FRAME_OPTIONS = "DENY"
CSRF_TRUSTED_ORIGINS = config( "DJANGO_CSRF_TRUSTED_ORIGINS", default="", cast=Csv(), )
Things worth noting:
SECRET_KEYand database credentials come from the environment — never commit them. Step 11 wires these up via a systemdEnvironmentFile.ALLOWED_HOSTSmust contain every hostname that will reach Django, including your bare domain and thewww.variant if you use it. Leaving this empty or wildcarded is a common cause ofDisallowedHost400 errors in production.SECURE_PROXY_SSL_HEADERtells Django to trust theX-Forwarded-Protoheader that Nginx sets, sorequest.is_secure()returnsTrueandSECURE_SSL_REDIRECTdoes not create a redirect loop.STATIC_ROOTis the directorycollectstaticwrites to. Nginx will serve from here directly — Django itself never handles static files in production.- HSTS settings are aggressive: once a browser sees HSTS with a long
max-age, it will refuse to connect to your domain over HTTP even if you later disable TLS. Only enable these after you have confirmed HTTPS works end-to-end in Step 10.
python manage.py check --deployDjango will list any remaining deployment warnings — fix them before going live.
Step 7: Collect Static Files and Run Migrations
With settings in place, create the database schema and gather every static asset into STATIC_ROOT:
python manage.py migrate
python manage.py collectstatic --noinputExpected output from collectstatic:
176 static files copied to '/home/django/apps/mysite/staticfiles'.Create a superuser so you can log into the admin:
python manage.py createsuperuserFinally, test Gunicorn by hand before wrapping it in systemd:
gunicorn --bind 0.0.0.0:8000 mysite.wsgi:applicationVisit http://your-server-ip:8000 in a browser. The page should render, but /static/ assets will 404 because Django is not serving them and Nginx is not yet in the picture. That is expected — stop Gunicorn with Ctrl+C and move on.
Step 8: Gunicorn systemd Socket and Service
systemd socket activation lets the kernel hold the listening socket open and spawn Gunicorn on demand. The first request after boot triggers the service start; there is no race between Nginx and Gunicorn coming up.
Create the socket unit:
sudo tee /etc/systemd/system/gunicorn.socket > /dev/null <<'EOF' [Unit] Description=gunicorn socket[Socket] ListenStream=/run/gunicorn.sock SocketUser=django SocketGroup=www-data SocketMode=0660
[Install] WantedBy=sockets.target EOF
Create the service unit:
sudo tee /etc/systemd/system/gunicorn.service > /dev/null <<'EOF' [Unit] Description=gunicorn daemon for mysite Requires=gunicorn.socket After=network.target postgresql.service[Service] Type=notify User=django Group=www-data RuntimeDirectory=gunicorn WorkingDirectory=/home/django/apps/mysite EnvironmentFile=/etc/mysite/mysite.env ExecStart=/home/django/apps/mysite/venv/bin/gunicorn \ --access-logfile - \ --error-logfile - \ --workers 3 \ --worker-class sync \ --timeout 60 \ --bind unix:/run/gunicorn.sock \ mysite.wsgi:application ExecReload=/bin/kill -s HUP $MAINPID KillMode=mixed TimeoutStopSec=5 PrivateTmp=true Restart=on-failure
[Install] WantedBy=multi-user.target EOF
Key details:
User=django,Group=www-data— Gunicorn runs as the unprivileged deploy user, but the socket is group-owned bywww-data(the group Nginx runs under), so Nginx can write to it without Django needing to be in Nginx's group.SocketMode=0660— owner and group can read/write, world has no access.--workers 3— a common starting point is(2 * cores) + 1. On a 2 vCPU VPS, 3-5 workers is reasonable. Each worker is a separate process holding its own copy of Django in memory (roughly 80-150 MB).Type=notify— Gunicorn 20+ emitssd_notifymessages so systemd knows exactly when it has finished loading.
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn.socket
sudo systemctl status gunicorn.socketExpected output:
● gunicorn.socket - gunicorn socket
Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; preset: enabled)
Active: active (listening) since Wed 2026-04-16 10:00:00 UTC; 3s ago
Listen: /run/gunicorn.sock (Stream)The service itself will not start until something actually connects to the socket. Trigger it manually with curl over the Unix socket:
curl --unix-socket /run/gunicorn.sock http://localhost/You should see Django's HTML response. Confirm the service is now active:
sudo systemctl status gunicorn.serviceStep 9: Configure Nginx as a Reverse Proxy
Install Nginx (see our full How to Install Nginx on Ubuntu 24.04 guide for tuning):
sudo apt install -y nginxCreate a site config:
sudo tee /etc/nginx/sites-available/mysite > /dev/null <<'EOF' upstream django_app { server unix:/run/gunicorn.sock; }server { listen 80; server_name example.com www.example.com;
client_max_body_size 25m; access_log /var/log/nginx/mysite.access.log; error_log /var/log/nginx/mysite.error.log;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ { alias /home/django/apps/mysite/staticfiles/; expires 30d; add_header Cache-Control "public, immutable"; }
location /media/ { alias /home/django/apps/mysite/media/; expires 7d; }
location / { proxy_pass http://django_app; 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; proxy_read_timeout 60s; } } EOF
Nginx needs to read files inside /home/django/, so grant the www-data group execute permission on the path:
sudo chmod o+x /home/django /home/django/apps /home/django/apps/mysiteEnable the site, test the config, and reload:
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginxOpen http://example.com (substituting your domain). You should see your site with static files loading correctly.
Open the firewall for HTTP and HTTPS:
sudo ufw allow "Nginx Full"
sudo ufw allow OpenSSH
sudo ufw enableStep 10: Obtain a TLS Certificate with Certbot
Install Certbot and its Nginx plugin:
sudo apt install -y certbot python3-certbot-nginxRequest a certificate — Certbot reads your Nginx config, provisions from Let's Encrypt, and rewrites the server block to listen on 443 with HTTP to HTTPS redirect:
sudo certbot --nginx -d example.com -d www.example.comAnswer the prompts (email address, agree to TOS, choose redirect). When it finishes, confirm automatic renewal is scheduled:
sudo systemctl list-timers | grep certbotCertbot installs a systemd timer that runs twice daily and renews any certificate within 30 days of expiry. You do not need to do anything else.
Test the full TLS setup with the SSL Labs server test or a quick curl:
curl -I https://example.comLook for HTTP/2 200 and an Strict-Transport-Security header confirming HSTS is active.
Step 11: Manage Secrets with an EnvironmentFile
Your Gunicorn service references /etc/mysite/mysite.env — create it now.
sudo mkdir -p /etc/mysite sudo tee /etc/mysite/mysite.env > /dev/null <<'EOF' DJANGO_SECRET_KEY=replace-with-a-50-character-random-string DJANGO_DEBUG=False DJANGO_ALLOWED_HOSTS=example.com,www.example.com DJANGO_CSRF_TRUSTED_ORIGINS=https://example.com,https://www.example.com DB_NAME=mysite_prod DB_USER=mysite_user DB_PASSWORD=strongpassword DB_HOST=127.0.0.1 DB_PORT=5432 EOF
sudo chown root:django /etc/mysite/mysite.env sudo chmod 640 /etc/mysite/mysite.env
Only root can write the file; the django group (and therefore the Gunicorn process) can read it but no one else can. Generate a fresh secret key with:
python -c "import secrets; print(secrets.token_urlsafe(64))"Restart Gunicorn to pick up the variables:
sudo systemctl restart gunicorn.serviceIf you prefer python-decouple to read a .env file directly, drop the file at ~/apps/mysite/.env with the same contents and remove the EnvironmentFile= line from the systemd unit. The EnvironmentFile approach is preferred because it keeps secrets out of the project directory entirely.
Optional: Add Celery + Redis for Background Tasks
Any non-trivial Django site eventually needs asynchronous work: sending transactional email, generating PDFs, calling slow third-party APIs. The standard Django pattern is Celery with Redis as the broker.
See our How to Install Redis on Ubuntu 24.04 guide for the full Redis setup. The short version:
sudo apt install -y redis-server
sudo systemctl enable --now redis-serverInstall Celery and the Redis client in your venv:
source ~/apps/mysite/venv/bin/activate
pip install celery[redis]
pip freeze > requirements.txtAdd a mysite/celery.py:
import os from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") app = Celery("mysite") app.config_from_object("django.conf:settings", namespace="CELERY") app.autodiscover_tasks()
And import it from mysite/__init__.py:
from .celery import app as celery_app
__all__ = ("celery_app",)Append to settings.py:
CELERY_BROKER_URL = "redis://127.0.0.1:6379/0"
CELERY_RESULT_BACKEND = "redis://127.0.0.1:6379/1"
CELERY_TASK_SERIALIZER = "json"
CELERY_ACCEPT_CONTENT = ["json"]
CELERY_TIMEZONE = "UTC"Create a systemd service for the Celery worker at /etc/systemd/system/celery.service, modeled on the Gunicorn unit but with ExecStart=/home/django/apps/mysite/venv/bin/celery -A mysite worker --loglevel=info. For periodic tasks, add a matching celerybeat.service that runs celery -A mysite beat.
Deploy Flow for Future Updates
With everything in place, the standard deploy loop for code changes becomes:
cd ~/apps/mysite
source venv/bin/activate
git pull
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
sudo systemctl restart gunicorn.service
sudo systemctl restart celery.service # if using CeleryScript this as ~/apps/mysite/deploy.sh so future deploys are a one-liner. For zero-downtime deploys, look at Gunicorn's --reload flag during development, or graceful restarts via sudo systemctl reload gunicorn.service which sends HUP to the master and cycles workers one at a time.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
502 Bad Gateway from Nginx | Gunicorn not running or socket permissions wrong | sudo systemctl status gunicorn.service, check /var/log/nginx/mysite.error.log for permission denied, verify /run/gunicorn.sock is owned by django:www-data with mode 0660 |
500 Internal Server Error with no detail | DEBUG=False hides the traceback | sudo journalctl -u gunicorn -n 100 --no-pager to see the Python traceback from Gunicorn's stderr |
| Static files return 404 | collectstatic not run, wrong STATIC_ROOT, or Nginx cannot read the path | Run python manage.py collectstatic, confirm alias in Nginx matches STATIC_ROOT exactly (trailing slash matters), verify chmod o+x on parent directories |
DisallowedHost at / | Hostname not in ALLOWED_HOSTS | Add every hostname (bare domain, www., server IP if used directly) to DJANGO_ALLOWED_HOSTS in the env file, restart Gunicorn |
FATAL: password authentication failed for user "mysite_user" | Password mismatch between PG and env file, or pg_hba.conf set to peer | Confirm password with psql -U mysite_user -h 127.0.0.1 -d mysite_prod, check /etc/postgresql/16/main/pg_hba.conf has host all all 127.0.0.1/32 scram-sha-256 |
permission denied for schema public during migrate | PostgreSQL 15+ tightened public schema privileges | Reconnect as postgres, run GRANT ALL ON SCHEMA public TO mysite_user; inside the target database |
| CSRF verification failed on POST | Missing CSRF_TRUSTED_ORIGINS or mismatched scheme | Add https://example.com to DJANGO_CSRF_TRUSTED_ORIGINS, confirm SECURE_PROXY_SSL_HEADER is set so Django knows the request is HTTPS |
| Gunicorn socket file missing after reboot | Socket unit not enabled | sudo systemctl enable gunicorn.socket so it starts at boot |
| Infinite redirect loop on HTTPS | SECURE_SSL_REDIRECT=True without SECURE_PROXY_SSL_HEADER | Add the SECURE_PROXY_SSL_HEADER setting so Django recognizes Nginx's X-Forwarded-Proto: https |
| High memory usage / OOM kills | Too many Gunicorn workers for available RAM | Reduce --workers in the systemd unit; each worker is ~100 MB. On 2 GB RAM, 2-3 workers is the ceiling with PostgreSQL on the same box |
Viewing Logs
Three log streams matter:
# Gunicorn stdout/stderr (includes Django tracebacks when DEBUG=False)
sudo journalctl -u gunicorn -fNginx access and error logs
sudo tail -f /var/log/nginx/mysite.access.log /var/log/nginx/mysite.error.logPostgreSQL
sudo tail -f /var/log/postgresql/postgresql-16-main.logFAQ
Why Gunicorn instead of uWSGI or Uvicorn?
Gunicorn is the most widely documented WSGI server in the Django ecosystem — the official Django tutorial and most hosting providers use it as the default. It handles synchronous Django views efficiently and is trivial to configure. uWSGI is more featureful but notoriously harder to tune and its upstream is effectively unmaintained as of 2024. Uvicorn is an ASGI server and is the right choice if you are running Django Channels, async views exclusively, or serving WebSockets — for traditional sync Django, Gunicorn is simpler and faster.
Should I run PostgreSQL on the same VPS?
For sites under a few thousand daily active users, yes — co-locating Django and PostgreSQL on one box eliminates network latency on every query and keeps the architecture simple. The CloudCore Starter plan at 4 GB RAM comfortably runs both. Move PostgreSQL to a separate server (or managed service) once you need read replicas, when your database exceeds 20-30 GB, or when your application server can no longer fit the working set in RAM alongside Postgres.
Do I need Nginx if Gunicorn can serve HTTP directly?
Yes. Gunicorn is a WSGI server, not a production HTTP server. It does not serve static files efficiently, does not terminate TLS, has weak handling of slow clients (a classic slowloris vulnerability), and has no built-in caching or compression. Nginx exists in front of every serious Django deployment for exactly these reasons.
How many workers should I run?
The Gunicorn docs recommend (2 * CPU cores) + 1 as a starting point for CPU-bound sync workloads. On a 2 vCPU VPS that gives you 5 workers. In practice, the ceiling on small VPS plans is usually memory, not CPU — each worker consumes 80-150 MB of RAM depending on your dependencies. Measure with ps aux | grep gunicorn after the site has been running under load, and reduce --workers if you approach swap.
Can I deploy multiple Django sites on the same server?
Yes, and it is a common pattern. Create a separate deploy user, virtualenv, systemd socket+service pair, and Nginx server block for each site. Name the socket files uniquely (/run/gunicorn-site1.sock, /run/gunicorn-site2.sock). PostgreSQL happily hosts dozens of small databases in a single cluster — just create a dedicated role and database for each site.
What about Docker / Kubernetes?
Containerizing Django is absolutely viable and this guide translates directly — the Dockerfile installs Python and pip-installs your requirements.txt, and docker compose replaces the systemd units. For a single-server deployment, however, bare systemd is usually simpler to operate, uses less RAM, and avoids the complexity of container networking for static file serving. Reach for Docker when you need repeatable environments across dev/staging/prod or when you are about to move to multiple hosts.
Next Steps
You now have a production Django stack on Ubuntu 24.04. Good follow-ups:
- Tune PostgreSQL — the default
postgresql.confis extremely conservative. Run pgtune against your VPS specs and apply the recommendedshared_buffers,effective_cache_size, andwork_memvalues. - Set up automated backups — use
pg_dumpon a nightly cron, orpgBackRest/barmanfor point-in-time recovery. Pipe the dumps to object storage off-server. - Add application monitoring — install Sentry's self-hosted stack or hook into the managed SaaS for exception tracking with the
sentry-sdkDjango integration. - Rate-limit at Nginx — use
limit_req_zoneto cap abusive clients before they reach Gunicorn. - Add a CDN in front — Cloudflare's free tier pairs well with a small Django VPS, offloading static asset delivery and absorbing DDoS traffic.
Ready to deploy?>
Launch a CloudCore Starter VPS — 2 vCPU, 4 GB RAM, 50 GB NVMe, unmetered bandwidth, Ubuntu 24.04 preinstalled — and follow this guide start to finish in about 40 minutes.>
- EUR 7.99/month, billed monthly with no contract
- Instant provisioning, root access within 60 seconds
- 24/7 support if you get stuck on any step above>
Deploy Your Django VPS Now