Deployment Overview
Choose between production image-based deployment and local source-based development for the LDS Stake Portal.
The Stake Portal is made up of five independent services. In production, all five run as Docker containers managed by a single Docker Compose file and fronted by Caddy, which handles TLS automatically via Let's Encrypt.
| Service | Role | Port |
|---|---|---|
backend | FastAPI REST API | 8000 (internal) |
frontend | React SPA + Express proxy | 3100 (internal) |
docs-site | Fumadocs documentation site | 3400 (internal) |
caddy | Reverse proxy + TLS termination | 80, 443 (public) |
discordbot | Discord bot — optional profile | 8001 (internal) |
Choose Your Path
Production: Pre-Built Images
Pull tested, pre-built container images from GHCR and run them with Docker Compose. No source code, no Node.js or Python required on the host. This is the recommended path for any server or VPS deployment.
Development: Build from Source
Clone the repository and run each service directly on your machine. Requires Node.js, Python 3.11+, and uv. Best for local development or contributing to the project.
Do not use the development path in production. Running services directly from source without containerization means you are responsible for process supervision, restarts on failure, and keeping Node.js and Python versions consistent.
Production Prerequisites
Before you begin a production deployment, confirm the following are in place.
| Requirement | Details |
|---|---|
| Linux server | Ubuntu 22.04 LTS or later recommended |
| Docker Engine | v24+ (includes Docker Compose v2 as docker compose) |
| Open ports | TCP 22 (SSH), 80 (HTTP/ACME), 443 (HTTPS) |
| Domain name | A registered domain you control |
| DNS records | Either three A records (DOMAIN, api.DOMAIN, docs.DOMAIN) pointing to your server IP, or a single A record for DOMAIN plus a wildcard CNAME (*.DOMAIN) if using Cloudflare proxy |
DNS must resolve to your server before you start the stack for the first time. Caddy provisions Let's Encrypt TLS via HTTP-01 ACME challenge, which requires port 80 to be publicly reachable. Cloudflare proxy is supported — see the Docker Deployment guide for both DNS paths and the Cloudflare SSL/TLS mode requirement.
Development Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Node.js | 18 or later | Required for the frontend |
| Python | 3.11 or later | Required for backend and Discord bot |
| uv | Latest | Python package manager — install here |
What Happens on First Boot
When the backend starts against an empty database it automatically bootstraps the portal. No manual SQL or seed scripts are required. See First Run and Bootstrap for the full walkthrough, including how to configure your wards and complete the initial admin login.
Further Reading
- Docker Deployment — complete production guide
- Manual Deployment — development and source-based guide
- Environment Variables — full reference for all configuration values
- First Run and Bootstrap — initial setup after the backend starts
- Upgrading — how to pull updated images and restart safely