---
sidebar_position: 10
sidebar_label: Deploying
---

# Deploying a Django app

Under Gunicorn or uWSGI behind nginx, on a PaaS, or under an ASGI server: nothing realtime is kept on your servers, so any of them answers any request.

## Its settings

| | |
|---|---|
| `WORDPLUS_SITE`, `WORDPLUS_SECRET` | from your app in WordPlus Cloud |
| `WORDPLUS_LOCAL_KEY` | yours: kept as long as the app |

Set them in the server environment, as you do `SECRET_KEY`. Keep the secret and the local key out of your repository and out of every page. The key reaches pages through `config_for()`, which is what it is for.

## Its addresses

Add every address your pages are served from to the app in WordPlus Cloud: scheme, host and port exactly (`https://shop.example.com`, `https://www.shop.example.com`). A page anywhere else is refused with `wrong_origin`. Up to 20 addresses an app. If your server hears [webhooks](sending.md#webhooks), set their address there too.

## Its files

`realtime-worker.js`, `realtime-rooms.min.js`, `realtime-rooms-e2ee.worker.js` and `realtime-ui.min.js` go out with your static files: copy them into a folder of `STATICFILES_DIRS` in your build (`npx wordplus-realtime copy static/`), then `collectstatic`. They must be served from the address of your pages: a browser runs a worker only from the page origin. With a CDN on another host for static files, serve these four from the app host instead, and set `worker` and `rooms` to their addresses.

## Workers and threads

The routes and the rules are plain functions, so every Gunicorn worker answers them. An emit is an HTTPS request to WordPlus Cloud, done in the view. For many emits, or ones you do not want a request to wait on, send them from Celery or a task queue.

## Behind a proxy

Set `SECURE_PROXY_SSL_HEADER` and `CSRF_TRUSTED_ORIGINS` as for any Django app behind TLS: the browser routes use the session and the Django CSRF check.

## Content Security Policy

If your pages send one, let them reach the WordPlus Cloud servers (the realtime servers, which may move a connection to another of them, and the media servers for group calls) and run the workers from your own address:

```text
connect-src 'self' https://*.wordplus.cloud wss://*.wordplus.cloud;
worker-src 'self';
```

## Clocks

Your server signs what it sends with the time. Keep its clock synced (NTP): one more than 5 minutes off has its emits refused with `stale_signature`.
