Documentation Index
Fetch the complete documentation index at: https://getfloo.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
This guide walks a Django 4+ app from local code to a production URL with a database and per-user auth. Every step has runnable Python code. By the end you have a working app at https://<app>.on.getfloo.com with a Postgres sibling service, signed-in users, and (optionally) your own domain.
If you’ve never deployed to floo before, read Golden Path first for the minimal three-command flow.
Before you start
You need:
- A Django 4+ project (or a fresh
django-admin startproject mysite).
- The project pushed to a GitHub repository.
- The floo CLI installed and authenticated (
curl -fsSL https://getfloo.com/install.sh | bash then floo auth login).
1. Add a Dockerfile
FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
RUN apt-get update -qq && \
apt-get install -y --no-install-recommends build-essential libpq-dev && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "mysite.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]
Add gunicorn and dj-database-url to your requirements.txt:
Django>=4.2
gunicorn>=21
dj-database-url>=2.1
psycopg[binary]>=3
whitenoise>=6.6
requests>=2.31
Bind to 0.0.0.0, not 127.0.0.1. Cloud Run only routes traffic to processes bound to all interfaces.
Update mysite/settings.py to read floo’s runtime env vars:
import os
from pathlib import Path
import dj_database_url
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "dev-only-do-not-use-in-prod")
DEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"
# floo's edge sets X-Forwarded-Host. Trust it for ALLOWED_HOSTS.
ALLOWED_HOSTS = ["*"] if DEBUG else [
".on.getfloo.com",
*os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(","),
]
# Trust X-Forwarded-Proto so Django knows the request is HTTPS behind floo's edge.
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
USE_X_FORWARDED_HOST = True
# Cookies
SESSION_COOKIE_SECURE = not DEBUG
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_SECURE = not DEBUG
# WhiteNoise serves collectstatic output
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
# ... rest of your middleware
]
STATIC_ROOT = BASE_DIR / "staticfiles"
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}
# Database — read DATABASE_URL from floo
DATABASES = {
"default": dj_database_url.config(default="sqlite:///db.sqlite3", conn_max_age=600),
}
Generate a real DJANGO_SECRET_KEY and set it once the app exists (step 4).
3. Initialize the floo config
[app]
name = "my-django-app"
[services.web]
type = "web"
path = "."
port = 8000
ingress = "public"
dev_command = "python manage.py runserver 0.0.0.0:8000"
migrate_command = "python manage.py migrate --noinput"
migrate_command runs after every deploy and promote.
4. Connect the repo and deploy
git add . && git commit -m "feat: floo config + Dockerfile"
git push origin main
floo apps github connect owner/my-django-app
floo deploys watch --app my-django-app
Set the secret key once the app exists, then redeploy:
floo env set DJANGO_SECRET_KEY="$(python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')" --app my-django-app
floo redeploy --app my-django-app
floo apps status my-django-app
Your Django app is live at https://my-django-app-dev.on.getfloo.com.
5. Add a Postgres database
floo services add postgres --app my-django-app
git add .floo/services.lock && git commit -m "feat: add postgres"
git push origin main
DATABASE_URL is injected. dj-database-url parses it automatically — no settings change needed. The next deploy runs your migrate_command against the new database before traffic shifts.
6. Add per-user auth
floo manages user authentication for you. Set access_mode = "accounts" in floo.app.toml:
[app]
name = "my-django-app"
access_mode = "accounts"
Push and deploy. From the next deploy onward, floo’s gateway sits in front of your app and:
- 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.
Add a tiny middleware that hangs the floo user on request.floo_user:
from dataclasses import dataclass
@dataclass
class FlooUser:
id: str
email: str
name: str | None
class FlooUserMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
email = request.META.get("HTTP_X_FLOO_USER_EMAIL")
user_id = request.META.get("HTTP_X_FLOO_USER_ID")
name = request.META.get("HTTP_X_FLOO_USER_NAME")
request.floo_user = FlooUser(id=user_id, email=email, name=name) if email else None
return self.get_response(request)
Wire it up:
MIDDLEWARE = [
# ... existing entries
"mysite.middleware.FlooUserMiddleware",
]
Use it in views:
from django.http import JsonResponse, HttpResponseUnauthorized
def dashboard(request):
if not request.floo_user:
return HttpResponseUnauthorized()
return JsonResponse({"hello": request.floo_user.email})
For local development, send the headers yourself or extend the middleware to inject a fixture user when they’re missing.
For the full reference on access modes and identity headers, see Add User Auth to Your App.
7. Add a custom domain
floo domains add app.example.com --app my-django-app
floo env set DJANGO_ALLOWED_HOSTS=app.example.com --app my-django-app
floo redeploy --app my-django-app
USE_X_FORWARDED_HOST = True and SECURE_PROXY_SSL_HEADER mean Django builds correct absolute URLs (for redirects, mailers, request.build_absolute_uri) without extra config.
8. Local development with prod data
floo dev --app my-django-app --service web
Runs dev_command locally with DATABASE_URL and other env vars sourced from your dev floo app — real Cloud SQL connection, no credentials in your shell history.
To also test signed-in flows for this accounts-mode app, add --fixture-user:
floo dev --app my-django-app --service web --fixture-user you@example.com
floo dev then starts a small proxy in front of each service that injects the same X-Floo-User-* headers floo’s gateway adds in production. The output table shows both the raw service URL and the auth-proxied URL — hit the auth-proxied one for any path that reads identity headers.
Common gotchas
/healthz is reserved. Cloud Run’s edge intercepts that exact path. Use /health or /livez.
- Bind to
0.0.0.0. 127.0.0.1 won’t accept Cloud Run traffic.
DEBUG = True in prod is a security hole. Set DJANGO_DEBUG=false (or just don’t set it — the default in the example above).
DJANGO_SECRET_KEY must be set. Without it, Django’s session cookies can be forged. 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 Django redirect loops can form when SECURE_SSL_REDIRECT=True.
What’s next
Add User 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.