Two ways to run Sitepins: directly with pnpm, or with Docker Compose.
With pnpm
git clone https://github.com/sitepins/sitepins.git
cd sitepins
pnpm install
Create both environment files:
cp api/.env.example api/.env
cp app/.env.example app/.env
Fill them in (see below), then start both services:
pnpm dev
Or run them separately in two terminals:
pnpm dev:api
pnpm dev:app
The app is at http://localhost:3000 and the API at http://localhost:4000.
With Docker
Docker Compose brings up MongoDB, the API, and the app together:
cp api/.env.example api/.env
cp app/.env.example app/.env
docker compose up --build
MongoDB runs as a service in the compose file, so you can leave MONGO_URI unset and it will be used automatically.
Generating Secrets
Several variables are secrets you generate rather than credentials from a third party:
openssl rand -base64 32
Use that for BETTER_AUTH_SECRET. Then:
openssl rand -hex 32
Run it separately for JWT_SECRET, SANDBOX_ENCRYPTION_KEY, and INTERNAL_API_SECRET.
INTERNAL_API_SECRET must be identical in api/.env and app/.env. Generate it once and paste the same value into both. A mismatch produces authentication failures that look unrelated to configuration.
Essential Environment Variables
The .env.example files are grouped and commented, and the repository READMEs document every variable. These are the ones you can’t skip.
api/.env
| Variable | Purpose |
|---|---|
BASE_URL | The API’s own public URL |
MONGO_URI | MongoDB connection string |
CORS_ORIGINS | Comma-separated browser origins allowed to call the API |
BETTER_AUTH_SECRET | Session signing secret |
JWT_SECRET, JWT_TOKEN_EXPIRE | Internal action tokens, e.g. 7d |
SANDBOX_ENCRYPTION_KEY | Encrypts sandbox tokens at rest |
INTERNAL_API_SECRET | Shared with the app |
S3_* | Media storage — see Media Storage |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET | OAuth sign-in with GitHub |
app/.env
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_BACKEND_URL | The API’s base URL |
NEXT_PUBLIC_HP_WS_URL | WebSocket URL for live cursors — ws://localhost:4000/api/v1/editor/collab in dev |
NEXT_PUBLIC_BUCKET_URL | Public base URL of your S3 bucket |
INTERNAL_API_SECRET | Must match the API’s copy |
GITHUB_APP_*, NEXT_PUBLIC_GITHUB_APP_NAME | GitHub App credentials — see Git Apps |
NEXT_PUBLIC_GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET | GitLab OAuth credentials |
There are two separate GitHub integrations, and they are not interchangeable. GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET on the API is a plain OAuth app for signing in. GITHUB_APP_* on the app is a GitHub App for repository access. You need both, created separately.
Transactional email — verification codes, password resets, organization invitations — goes through whichever provider you configure:
brevo— setBREVO_API_KEYsmtp— setSMTP_HOSTand its companionsconsole— the default when nothing is configured. Messages, including OTP codes and reset links, are logged to stdout
The console provider means signup works with zero mail setup — useful for local development. Read the code from the terminal.
To skip email verification entirely, set REQUIRE_EMAIL_VERIFICATION=false.
Branding
A self-hosted instance can replace the Sitepins name and links without touching code:
| Variable | Default |
|---|---|
NEXT_PUBLIC_BRAND_NAME | Sitepins |
NEXT_PUBLIC_BRAND_URL | https://sitepins.com |
NEXT_PUBLIC_SUPPORT_URL | <BRAND_URL>/contact |
NEXT_PUBLIC_UPDATES_URL | https://updates.sitepins.com |
NEXT_PUBLIC_COMMUNITY_URL | The Sitepins Discord |
Health Check
curl http://localhost:4000/healthz
Returns { "status": "ok", "uptime": <seconds> } — point your load balancer or orchestrator at it.
Production Notes
- Set
NODE_ENV=productionand real values forBASE_URLandCORS_ORIGINS TRUST_PROXYdefaults to 1 in production for one reverse proxy hop; setfalseif the API is exposed directly- Leave
COOKIE_DOMAINunset for single-host deploys. Set it to a leading-dot domain (.example.com) only when the app and API sit on different subdomains and need to share the session cookie - Back up MongoDB. Your content is safe in Git, but users, organizations, and project configuration are not