Skip to main content
From a Django 5.2+ project on GitHub (or a fresh django-admin startproject mysite) to a live app at https://<app>.getfloo.app, with managed Postgres, signed-in users, and your own domain. New to floo? Start with the Quickstart.

1. Add a Dockerfile

Dockerfile
Add gunicorn and dj-database-url to your requirements.txt:
Bind to 0.0.0.0 on $PORT, not 127.0.0.1 on a fixed port. floo sets PORT at runtime and routes only to processes bound to all interfaces. The shell-form CMD expands $PORT. collectstatic gets a throwaway secret and an in-memory database URL because runtime credentials are not available at build time. This database is only for asset collection.

2. Configure Django for production

Read floo’s runtime env vars in mysite/settings.py:
mysite/settings.py
With DEBUG off and no DJANGO_SECRET_KEY, the container refuses to boot instead of serving with a guessable key. Step 4 sets one.

3. Initialize the floo config

Install the CLI and sign in: curl -fsSL https://getfloo.com/install.sh | bash, then floo auth login. An agent can run the same journey over the HTTP API instead, starting from getfloo.com/agents.md.
floo.app.toml
migrate_command runs as a one-off job with the new image before traffic moves to it. A failed migration stops the deploy. Use expand-then-contract migrations to keep the schema compatible with both old and new code.

4. Connect the repo and deploy

floo builds from GitHub, not local files, so push first. floo apps github connect needs the floo GitHub App on the account that owns the repository, and opens a browser to install it if it is missing. The app cannot boot until DJANGO_SECRET_KEY is set, so connect without deploying, set the key, then push to start the first deploy:
When the deploy is green:
Your Django app is live at https://my-django-app-dev.getfloo.app.Every git push origin main ships to dev. floo releases promote --app my-django-app publishes to https://my-django-app.getfloo.app. Prod has its own env vars, and the first promote creates the prod environment. After it, set DJANGO_SECRET_KEY in prod (the same command with --env prod) and promote again.

5. Add a Postgres database

The [managed.default] declaration in step 3 provisions Postgres on the first deploy. DATABASE_URL is injected, and dj-database-url parses it with no settings change. The deploy runs python manage.py migrate --noinput against that database. Dev and prod have separate databases. Do not use SQLite on the deployed container filesystem for persistent application data.

File storage

Add [managed.uploads] with type = "storage", attach storage:uploads, and deploy. Configure boto3 in your Django app; see Cloud storage for paygo restrictions and file operations.

6. Add per-user auth

Set access_mode = "accounts" and floo handles sign-in:
floo.app.toml
From the next deploy onward, floo’s gateway:
  • Redirects unauthenticated requests to a hosted login page.
  • Validates the session cookie on every request.
  • Injects identity headers into every request that reaches your Django app.
A small middleware puts the floo user on request.floo_user:
mysite/middleware.py
Wire it up:
mysite/settings.py
Use it in views:
mysite/views.py
Locally, run floo dev --fixture-user (see section 8) or send the headers yourself. Access modes and identity headers in full: Auth.

7. Add a custom domain

Declare the domain in floo.app.toml:
Commit and push, wait for that commit’s dev deploy to go live, then allow the host in prod, release to prod, and read the DNS records:
Publish the traffic and certificate CNAME records that show prints, then watch activation:
With USE_X_FORWARDED_HOST = True and SECURE_PROXY_SSL_HEADER, Django builds correct absolute URLs (redirects, mailers, request.build_absolute_uri) without extra config. DNS setup and troubleshooting: Custom domains.

8. Local development with dev credentials

Write-only DJANGO_SECRET_KEY is withheld locally. Set DJANGO_DEBUG=true in your local shell to use the development-only key from these settings, or supply a separate local DJANGO_SECRET_KEY. Never enable debug in a deployed environment.
Runs dev_command locally with DATABASE_URL and readable env vars from the app’s dev environment: a real connection to your dev Postgres, with no credentials in your shell history. Write-only secrets are withheld; supply separate local values when needed. Prod credentials never reach a local session. To test signed-in flows, add --fixture-user:
floo dev then puts a proxy in front of each accounts-mode service that injects the same X-Floo-User-* headers floo’s gateway adds in production. The output table shows the raw service URL and the auth-proxied URL; use the auth-proxied one for any path that reads identity headers.

Common gotchas

  • /healthz is reserved. floo’s edge intercepts that exact path. Use /health or /livez.
  • Bind to 0.0.0.0. floo cannot reach 127.0.0.1.
  • DEBUG = True in prod is a security hole. Set DJANGO_DEBUG=false (or leave it unset, which is the default above).
  • DJANGO_SECRET_KEY must be set in each environment. Without it, Django’s session cookies can be forged, so the settings above refuse to boot in production rather than fall back. Generate with get_random_secret_key() and set via floo env set.
  • collectstatic runs in the Dockerfile. WhiteNoise’s CompressedManifestStaticFilesStorage requires it.
  • SECURE_PROXY_SSL_HEADER is required behind a proxy. Without it, request.is_secure() returns False and SECURE_SSL_REDIRECT=True causes redirect loops.

What’s next

Auth, full reference

Identity headers, access policies, and access modes in detail.

Managed services

Postgres, Redis, Storage: what they cost and how isolation works.

Custom domains

DNS, verification, multi-service routing.

Cron jobs

Schedule recurring Django management commands inside your container.