Framework Frankfurt, Germany

Deploy Django on Nodion

Nodion recognizes Django by manage.py and Django in your dependencies. The Python buildpack installs them, runs collectstatic and starts Gunicorn on your project's WSGI module. With a release: line in a Procfile, migrations run before each new version goes live, and the app and its PostgreSQL database run in Frankfurt.

Deploy to Nodion ›

from 1 EUR / month

Up to 15 € credit when signing up

Detected by
manage.py and Django in your dependencies
Start
gunicorn <project>.wsgi, 3 workers
Python
3.10 to 3.15, default 3.13
Region
EU Central (Frankfurt)

Deploy Django step by step

  1. Add Gunicorn, WhiteNoise and a database driver Nodion starts Gunicorn but does not install it, so it belongs in your dependencies. Gunicorn does not serve static files; WhiteNoise serves what collectstatic writes. Pin the Python version in .python-version, because a range such as requires-python = ">=3.10" picks the newest release. requirements.txt
    Django>=5.2
    gunicorn
    whitenoise
    dj-database-url
    psycopg[binary]
  2. Read settings from the environment collectstatic runs during the build, where only variables marked Build exist, so the settings must import without runtime secrets. Django checks SECRET_KEY only when it is used. Add WhiteNoise right after SecurityMiddleware. settings.py
    import os
    import dj_database_url
    
    SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "")
    DEBUG = os.environ.get("DJANGO_DEBUG") == "1"
    ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")
    CSRF_TRUSTED_ORIGINS = [f"https://{h}" for h in ALLOWED_HOSTS if h]
    
    DATABASES = {"default": dj_database_url.config(conn_max_age=600)}
    
    STATIC_ROOT = BASE_DIR / "staticfiles"
    # MIDDLEWARE: "whitenoise.middleware.WhiteNoiseMiddleware"
    # right after "django.middleware.security.SecurityMiddleware"
  3. Answer the health check before the host check Nodion's health check calls each instance by its internal address, which is not in ALLOWED_HOSTS, so Django would answer 400 and the release never goes live. Put a small middleware first in MIDDLEWARE and set the health check path to /healthz in the app settings. health.py
    from django.http import HttpResponse
    
    
    class HealthCheckMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            if request.path == "/healthz":
                return HttpResponse("ok")
            return self.get_response(request)
  4. Run migrations on every deploy A release: line in a Procfile runs once per build, after the build and before the new version starts. If it fails, the deploy stops and the running version stays live. Procfile
    release: python manage.py migrate --noinput
  5. Create the app and the database Create an application from your repository in the region EU Central, then a PostgreSQL database in the same region, and attach it on the Environment tab: it arrives as DATABASE_URL on the next deploy. Set DJANGO_SECRET_KEY as a secret and DJANGO_ALLOWED_HOSTS to your app's hostname and your own domains, then push.

Good to know

  • Celery and other workersAdd worker: celery -A myproject worker to the Procfile together with an explicit web: gunicorn myproject.wsgi --bind 0.0.0.0:$PORT; without a web: line the first Procfile entry other than release: becomes the default command. Then add a process named worker without a port on the Processes tab. Valkey in the same region gives you REDIS_URL as broker.
  • ASGIThe default start command is WSGI. For Channels or async views, set your own web: line, for example with Uvicorn workers, and bind it to 0.0.0.0:$PORT.
  • Dependency filesrequirements.txt, poetry.lock and Pipfile.lock are installed as they are. A Pipfile without its lock file installs nothing.

What Nodion runs for you

  • Deploys without downtime Push to your branch and Nodion builds a new release. Traffic switches once the new instances answer their health check; a failed release leaves the running one in place. Apps with a local volume restart instead, because the disk belongs to one instance.
  • Databases next to the app Managed PostgreSQL, pgvector, MySQL, Valkey and ClickHouse in the same region. Attached databases arrive as DATABASE_URL, REDIS_URL or CLICKHOUSE_URL.
  • Previews per pull request Turn on previews and pull requests from your repository get their own app with its own URL and fresh, empty databases, created automatically or by hand. Forks and bot pull requests are skipped.
  • Workers, cron jobs and scaling Run workers as extra processes of the same app, schedule jobs on the Cron tab, and scale every process to up to 16 instances.
  • Release step With buildpacks, a Procfile release: line runs with every new build. Dockerfile apps, and redeploys or rollbacks to an earlier image, use a release command set on the app itself, which also takes precedence over the Procfile line. On static sites a release step runs in an image that holds only the built files.
  • Logs and metrics Build, release and runtime logs plus CPU, memory, disk and network metrics for every instance in the dashboard.
  • Domains and HTTPS A default hostname with HTTPS from the first deploy; your own domains get certificates automatically.

Further reading

Django on Nodion: questions and answers

Does Nodion run Django migrations for me?

Only if you ask for it: add release: python manage.py migrate --noinput to a Procfile. It runs once per build before the new version starts, and a failure stops the deploy.

Why does my Django deploy never become ready?

Usually the health check gets a 400 from ALLOWED_HOSTS or a 404 on /. Answer a path such as /healthz in a middleware placed before the host check and set it as the app's health check path.

Can I use Poetry instead of requirements.txt?

Yes. With a poetry.lock, Nodion installs Poetry and runs poetry install --only main. Pipenv works with a Pipfile.lock.

Where does my Django app run?

In the EU Central region in Frankfurt, Germany. Build, registry, the app and its databases, volumes, buckets, logs and metrics stay in that region, and Nodion's API and control plane are hosted in Germany. Nodion GmbH is based in Stuttgart.

Can I use Django in line with the GDPR?

Nodion provides the basis for it: Nodion GmbH is based in Stuttgart, Germany, in the Frankfurt region the app, its databases and volumes run in Germany, and you conclude the data processing agreement (DPA) under Art. 28 GDPR electronically in the dashboard. Whether your setup complies also depends on how you configure and use the app.

How much does it cost to run Django on Nodion?

An app instance starts at 1 EUR per month. The setup in the cost box costs 3.50 EUR per month: App 2 EUR, PostgreSQL 1.50 EUR. Prices are net and billed per second, and you pick bigger sizes or more instances whenever you need them.

Can I use my own domain for my Django app?

Yes. Every app gets a default hostname with HTTPS. Add your own domain on the app's Domains tab; the TLS certificate is issued and renewed automatically.

Give your agent a cloud.

Earn up to 15 € in credit when signing up.

Continue with GitHub

or with email

Stay in the loop.

Product news, no spam. Unsubscribe anytime.