Deploying an OpenSlides App
Introduction
OpenSlides is an open-source platform for digital assemblies, agendas, and live voting. Klutch.sh supports one internal port per app, so this guide uses a split deployment: a backend container (Django API + WebSocket/autoupdate) and a separate frontend container (static UI) that points to the backend URL. You will create two apps in Klutch.sh, each with its own Dockerfile, environment variables, and storage.
Prerequisites
- A Klutch.sh account (sign up)
- Two GitHub repositories or subdirectories, each with a Dockerfile (one for backend, one for frontend); GitHub is the only supported git source
- PostgreSQL database (deploy as a Klutch.sh TCP app on port
8000and connect on5432) - Redis instance (optional but recommended for caching/notifications; deploy as TCP on port
8000and connect on6379) - Domain and TLS for secure access
For onboarding, see the Quick Start.
Architecture and ports (split services)
- Backend (API + WebSocket/autoupdate): internal port
8000, HTTP traffic. The frontend communicates with this service. - Frontend (static UI): internal port
8080, HTTP traffic. Users hit this URL in the browser. - Database (PostgreSQL) and Redis run as separate Klutch.sh TCP apps.
- Persistent storage is required for backend media/static and recommended for frontend build assets if you serve them from disk.
Repository layout (example)
openslides-backend/├── Dockerfile├── manage.py├── openslides/ # Django project├── requirements.txt└── ...
openslides-frontend/├── Dockerfile├── package.json├── pnpm-lock.yaml # or yarn.lock / package-lock.json└── src/Keep secrets out of Git; store them in Klutch.sh environment variables.
Installation (local) and starter commands
Backend (local):
python -m venv .venv && source .venv/bin/activatepip install -r requirements.txtpython manage.py migratepython manage.py collectstatic --noinputpython manage.py runserver 0.0.0.0:8000Frontend (local):
pnpm installpnpm buildpnpm preview -- --port 8080Dockerfile for OpenSlides backend (production-ready)
Place this Dockerfile in the backend repo root; Klutch.sh auto-detects it:
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PORT=8000
WORKDIR /app
COPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
COPY . .RUN python manage.py collectstatic --noinput
EXPOSE 8000CMD ["bash", "-lc", "python manage.py migrate && gunicorn openslides.wsgi:application --bind 0.0.0.0:${PORT} --workers 3"]Notes:
- Add system dependencies if your requirements need them (
apt-get install -y build-essential libpq-dev). - WebSockets for autoupdate run on the same port with Django Channels if configured.
Dockerfile for OpenSlides frontend (production-ready)
Place this Dockerfile in the frontend repo root; Klutch.sh auto-detects it:
FROM node:18-alpine AS buildWORKDIR /app
COPY package.json pnpm-lock.yaml* yarn.lock* package-lock.json* ./RUN corepack enableRUN pnpm install --frozen-lockfile
COPY . .RUN pnpm build
FROM node:18-alpineWORKDIR /appENV PORT=8080
COPY --from=build /app /appRUN pnpm install --prod --frozen-lockfile
EXPOSE 8080CMD ["pnpm", "preview", "--", "--port", "8080", "--host", "0.0.0.0"]Notes:
- Set an environment variable (e.g.,
VITE_API_URL) at runtime to point to the backend URL. - Use a lightweight static server if your build output is static (
pnpm serveornpx serve dist), adjusting CMD accordingly.
Environment variables (Klutch.sh)
Backend app:
PORT=8000DATABASE_URL=postgres://<user>:<password>@<db-host>:5432/<db>REDIS_URL=redis://:<password>@<redis-host>:6379/0(if used)ALLOWED_HOSTS=example-app.klutch.shSECRET_KEY=<secure-random>MEDIA_ROOT=/app/mediaSTATIC_ROOT=/app/static
Frontend app:
PORT=8080VITE_API_URL=https://<backend-domain>(use backend app URL)
Nixpacks overrides (if deploying without Dockerfile):
- Backend:
NIXPACKS_PYTHON_VERSION=3.11,NIXPACKS_BUILD_CMD=pip install -r requirements.txt && python manage.py collectstatic --noinput,NIXPACKS_START_CMD=gunicorn openslides.wsgi:application --bind 0.0.0.0:8000 --workers 3 - Frontend:
NIXPACKS_NODE_VERSION=18,NIXPACKS_BUILD_CMD=pnpm install --frozen-lockfile && pnpm build,NIXPACKS_START_CMD=pnpm preview -- --port 8080 --host 0.0.0.0
Attach persistent volumes
Backend app:
/app/media— uploads and exported assets./app/static— collected static files.
Frontend app (optional if serving static build from disk):
/app/distor build output directory if you persist it./app/logsif you write logs locally.
Ensure mounted paths are writable inside each container.
Deploy OpenSlides on Klutch.sh (split workflow)
- Push the backend repository (with its Dockerfile at the root) to GitHub.
- Push the frontend repository (with its Dockerfile at the root) to GitHub.
- In klutch.sh/app, create two apps: one for the backend (HTTP, internal port
8000) and one for the frontend (HTTP, internal port8080). - For the backend app, set environment variables for database/Redis,
SECRET_KEY, and storage paths; attach volumes for/app/mediaand/app/static. - For the frontend app, set
VITE_API_URL(or equivalent) to the backend’s public URL; attach volumes if you persist build artifacts or logs. - Deploy both apps. Access OpenSlides via the frontend URL (e.g.,
https://example-app.klutch.sh), which calls the backend service.
Sample API usage (backend)
List meetings (example endpoint; adjust to your API version):
curl -X GET "https://<backend-domain>/rest/meetings/" \ -H "Accept: application/json"Health checks and production tips
- Backend: Add an HTTP probe to
/healthor a lightweight status endpoint; enforce HTTPS at the edge; store secrets only in Klutch.sh and rotate regularly. - Frontend: Probe
/for readiness; ensureVITE_API_URLpoints to the backend’s HTTPS URL. - Monitor volumes (
/app/media,/app/static) and database size; resize before they fill. - Pin image versions and test upgrades in staging; back up database and media before updates.
OpenSlides on Klutch.sh combines reproducible Docker builds with managed secrets, persistent storage, and flexible HTTP/TCP routing. With separate backend (port 8000) and frontend (port 8080) apps, plus external Postgres/Redis, you can deliver reliable digital assemblies without extra YAML or workflow overhead.