All installation guides are updated to add the instructions about how to deploy docs with yhub.
13 KiB
Deployment on Scalingo
This guide explains how to deploy Docs on Scalingo using a custom buildpack.
Overview
Scalingo is a Platform-as-a-Service (PaaS) that simplifies application deployment. This setup uses a custom buildpack to handle both the frontend (Next.js static export) and backend (Django) builds, serving them through Nginx. The conversion service (y-provider) runs alongside the Django backend.
Warning
The buildpack does not start the collaboration server yet. Since the content of a document moved there, a Scalingo app deployed on its own cannot save documents: the editor opens, and nothing is persisted. The y-provider the buildpack starts is the conversion service only — it stopped serving the collaboration websocket in this release.
Until the buildpack starts it, run the collaboration server (
lasuite/impress-yhub) elsewhere — a container platform, a VM, another provider — and point this app at it withYHUB_API_BASE_URLandCOLLABORATION_WS_URL, as described in Collaboration server below. The compose and kubernetes guides deploy it as part of the stack.
Prerequisites
- A Scalingo account
- Scalingo CLI installed (optional but recommended)
- A PostgreSQL database Scalingo addon
- A Redis Scalingo addon (for caching and sessions)
- An external Identity Provider that supports OpenID Connect protocol
- An external Object Storage that implements S3 API
- Somewhere to run the collaboration server, with a PostgreSQL database and a Redis/Valkey instance of its own (see the warning above)
Step 1: Create Your App
Create a new app on Scalingo using scalingo CLI or using the Scalingo dashboard.
Step 2: Provision Addons
Add the required PostgreSQL and Redis services.
This will set the following environment variables automatically:
SCALINGO_POSTGRESQL_URL- Database connection stringSCALINGO_REDIS_URL- Redis connection string
Step 3: Configure Environment Variables
Set the following environment variables in your Scalingo app:
Buildpack Configuration
scalingo env-set BUILDPACK_URL="https://github.com/suitenumerique/buildpack#main"
scalingo env-set LASUITE_APP_NAME="docs"
scalingo env-set LASUITE_BACKEND_DIR="src/backend/"
scalingo env-set LASUITE_FRONTEND_DIR="src/frontend/"
scalingo env-set LASUITE_NGINX_DIR="."
scalingo env-set LASUITE_SCRIPT_POSTCOMPILE="bin/buildpack_postcompile.sh"
scalingo env-set LASUITE_SCRIPT_POSTFRONTEND="bin/buildpack_postfrontend.sh"
Database and Cache
scalingo env-set DATABASE_URL="\$SCALINGO_POSTGRESQL_URL"
scalingo env-set REDIS_URL="\$SCALINGO_REDIS_URL"
Django Settings
scalingo env-set DJANGO_SETTINGS_MODULE="impress.settings"
scalingo env-set DJANGO_CONFIGURATION="Production"
scalingo env-set DJANGO_SECRET_KEY="<generate-a-secure-secret-key>"
scalingo env-set DJANGO_ALLOWED_HOSTS="my-docs-app.osc-fr1.scalingo.io"
OIDC Authentication
Configure your OIDC provider (e.g., Keycloak, Authentik):
scalingo env-set OIDC_RP_CLIENT_ID="docs-client-id"
scalingo env-set OIDC_RP_CLIENT_SECRET="<your-client-secret>"
scalingo env-set OIDC_RP_SIGN_ALGO="RS256"
scalingo env-set OIDC_OP_BASE_URL="https://auth.yourdomain.com/realms/docs"
Or configure individual endpoints if your provider doesn't support discovery:
scalingo env-set OIDC_OP_AUTHORIZATION_ENDPOINT="https://auth.yourdomain.com/authorize"
scalingo env-set OIDC_OP_TOKEN_ENDPOINT="https://auth.yourdomain.com/token"
scalingo env-set OIDC_OP_USER_ENDPOINT="https://auth.yourdomain.com/userinfo"
scalingo env-set OIDC_OP_JWKS_ENDPOINT="https://auth.yourdomain.com/.well-known/jwks.json"
scalingo env-set OIDC_OP_LOGOUT_ENDPOINT="https://auth.yourdomain.com/logout"
S3 Media Storage
To store uploaded media files in an S3-compatible object storage:
scalingo env-set AWS_S3_ENDPOINT_URL="https://s3.amazonaws.com"
scalingo env-set AWS_S3_ACCESS_KEY_ID="<your-access-key>"
scalingo env-set AWS_S3_SECRET_ACCESS_KEY="<your-secret-key>"
scalingo env-set AWS_STORAGE_BUCKET_NAME="docs-media"
scalingo env-set AWS_S3_REGION_NAME="eu-west-1"
Collaboration server
The collaboration server holds the content of the documents. The backend reads and writes them through its REST API, and the editors sync with it over the websocket, so the app needs to know where it is — the first url is reached by the backend, the second by the browser:
scalingo env-set YHUB_API_BASE_URL="https://yhub.yourdomain.com"
scalingo env-set COLLABORATION_WS_URL="wss://yhub.yourdomain.com/collaboration/ws/v1/docs"
They authenticate each other with signed tokens rather than a shared secret: each signs with an RSA key of its own and verifies the other against the JWKS it publishes. Generate the backend one and set it:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem
scalingo env-set JWT_PRIVATE_KEY="$(cat private.pem)"
The collaboration server needs a key of its own (YHUB_JWT_PRIVATE_KEY), the
backend it calls (COLLABORATION_BACKEND_BASE_URL), the origins a browser may
open a websocket from (COLLABORATION_SERVER_ORIGIN), and its two stores
(POSTGRES, REDIS). Its schema is created by the script it ships,
npm run init-db, which has to run once before it starts and again after every
upgrade. Its variables are listed in env.md, and
src/yhub-server/README.md documents what each of them changes.
Email Configuration (Optional)
For email notifications see https://doc.scalingo.com/platform/app/sending-emails:
scalingo env-set DJANGO_EMAIL_HOST="smtp.example.org"
scalingo env-set DJANGO_EMAIL_PORT="587"
scalingo env-set DJANGO_EMAIL_HOST_USER="<smtp-user>"
scalingo env-set DJANGO_EMAIL_HOST_PASSWORD="<smtp-password>"
scalingo env-set DJANGO_EMAIL_USE_TLS="True"
scalingo env-set DJANGO_EMAIL_FROM="docs@yourdomain.com"
Step 4: Deploy
Deploy your application:
git push scalingo main
The buildpack will automatically:
- Build the frontend (Next.js static export)
- Build the backend (Django)
- Run the post-compile script (cleanup unused files to reduce slug size)
- Run the post-frontend script (move assets, inject theme, prepare for deployment)
- Start uvicorn, the y-provider conversion service, and Nginx
- Run Django migrations
Step 5: Create superuser
After the first deployment, create an admin user:
scalingo run python manage.py createsuperuser
Custom Domain (Optional)
To use a custom domain:
- Add the domain in Scalingo dashboard
- Update
DJANGO_ALLOWED_HOSTSwith your custom domain - Configure your DNS to point to Scalingo
scalingo domains-add docs.yourdomain.com
scalingo env-set DJANGO_ALLOWED_HOSTS="docs.yourdomain.com,my-docs-app.osc-fr1.scalingo.io"
Theme Customization
Docs supports theme customization via environment variables. The theme controls the appearance of the header, footer, waffle (La Suite services widget), favicon, and more.
Custom Logo (Optional)
To replace the default Docs logo with your own, set the THEME_CUSTOMIZATION_LOGO_URL environment variable with an HTTPS URL pointing to an SVG file (max 5MB):
scalingo env-set THEME_CUSTOMIZATION_LOGO_URL="https://cdn.yourdomain.com/logo.svg"
The logo is validated during build:
- Must use HTTPS
- Must be a valid SVG file
- Must not exceed 5MB
- SSRF protection is applied
Custom Theme (Optional)
To customize the theme (footer links, waffle, translations, etc.), set the THEME_CUSTOMIZATION_JSON environment variable with a JSON object. The buildpack merges your custom JSON with the default theme, so you only need to specify the parts you want to override.
Important: The
THEME_CUSTOMIZATION_JSONvalue must be valid JSON. Ensure it is properly escaped when setting as an environment variable.
scalingo env-set THEME_CUSTOMIZATION_JSON='{"footer":{"default":{"externalLinks":[{"label":"GitHub","href":"https://github.com/your-org/"},{"label":"Your Org","href":"https://yourdomain.com"}],"legalLinks":[{"label":"Legal Notice","href":"https://docs.yourdomain.com/legal/"},{"label":"Privacy Policy","href":"https://docs.yourdomain.com/privacy/"}],"bottomInformation":{"label":"Unless otherwise stated, all content on this site is under","link":{"label":"licence etalab-2.0","href":"https://github.com/etalab/licence-ouverte/blob/master/LO.md"}}},"en":{"bottomInformation":{"label":"Unless otherwise stated, all content on this site is under","link":{"label":"licence MIT","href":"https://github.com/your-org/license"}}},"fr":{"bottomInformation":{"label":"Sauf mention contraire, tout le contenu de ce site est sous","link":{"label":"licence etalab-2.0","href":"https://github.com/etalab/licence-ouverte/blob/master/LO.md"}}}},"waffle":{"apiUrl":"https://your-api.example.com/api/v1.0/lagaufre/services/","widgetPath":"https://static.example.com/widgets/"},"header":{"logo":{},"icon":{"src":"/assets/icon-docs.svg","style":{"width":"32px","height":"auto"},"alt":"Your Org Logo","withTitle":true}},"home":{"with-proconnect":false,"icon-banner":{"src":"/assets/icon-docs.svg","style":{"width":"64px","height":"auto"},"alt":"Your Org Logo"}},"favicon":{"light":{"href":"/assets/favicon-light.png","type":"image/png"},"dark":{"href":"/assets/favicon-dark.png","type":"image/png"}}}'
Available Theme Sections and Configuration
For detailed information on all available theme sections, waffle configuration modes, and customization options, see the Customization Guide.
Theme Cache
The theme is cached in Redis for 24 hours by default. If you update THEME_CUSTOMIZATION_JSON and don't see changes, clear the Redis cache:
scalingo run python -c "from django.core.cache import cache; cache.clear()"
Or set THEME_CUSTOMIZATION_CACHE_TIMEOUT to a shorter duration:
scalingo env-set THEME_CUSTOMIZATION_CACHE_TIMEOUT=60
Note: Changing
THEME_CUSTOMIZATION_CACHE_TIMEOUTdoes not clear existing cached values in Redis. After changing this setting, clear the cache manually:scalingo run python -c "from django.core.cache import cache; cache.clear()"
Troubleshooting
Check Logs
scalingo logs --tail
Common Issues
- Build fails: Check that all required environment variables are set
- Database connection error: Verify
DATABASE_URLis correctly set to$SCALINGO_POSTGRESQL_URL - Static files not served: Ensure the buildpack post-frontend script ran successfully
- OIDC errors: Verify your OIDC provider configuration and callback URLs
- Theme not updating: Clear Redis cache with
scalingo run python -c "from django.core.cache import cache; cache.clear()" - Collaboration not working, or documents opening empty: the collaboration server is a separate deployment. Verify it is running, that
COLLABORATION_WS_URLandYHUB_API_BASE_URLpoint at it, thatJWT_PRIVATE_KEYis set on this app andYHUB_JWT_PRIVATE_KEYon that one, and that itsnpm run init-dbhas been run - Conversion not working (export, markdown import): verify the y-provider process is running and
Y_PROVIDER_API_BASE_URLpoints at it
Useful Commands
# Open a console
scalingo run bash
# Restart the app
scalingo restart
# Scale containers
scalingo scale web:2
# One-off command
scalingo run python manage.py shell
# Check environment variables
scalingo env
# View app status
scalingo status
Architecture
On Scalingo, the application runs as follows:
Build Phase
- The buildpack compiles the frontend (Next.js static export)
- The buildpack compiles the backend (Python dependencies)
bin/buildpack_postcompile.shruns to clean up unused files and reduce slug sizebin/buildpack_postfrontend.shmoves the frontend build tobuild/frontend-out, downloads custom logos, injects the custom theme, and prepares the deployment structure
Runtime
The bin/buildpack_start.sh script starts three processes:
- Nginx serves static files and proxies requests to the backend
- uvicorn runs the Django ASGI application on port 8000
- y-provider runs the conversion service on port 4444
Nginx routes:
/api/and/admin/→ Django backend (port 8000)/media/→ S3 object storage (with auth proxy)/→ Static frontend files
The collaboration server is not one of these processes. /collaboration/ is
served by the separate deployment COLLABORATION_WS_URL points at, and the
conversion service is called by the backend directly on
Y_PROVIDER_API_BASE_URL — nothing is routed to it.