Skip to content

feat: add Dockerfile for self-hosted deployment#36

Open
felipeelias wants to merge 2 commits intoEveryInc:mainfrom
felipeelias:feat/add-dockerfile
Open

feat: add Dockerfile for self-hosted deployment#36
felipeelias wants to merge 2 commits intoEveryInc:mainfrom
felipeelias:feat/add-dockerfile

Conversation

@felipeelias
Copy link
Copy Markdown

Hey, thanks for releasing Proof. I started using it, hosting it myself, and this is the Dockerfile I'm using. Thought it would be great to share.

Summary

Add a multi-stage Dockerfile so anyone can self-host the Proof SDK server with docker build && docker run.

Why

No official way to run Proof SDK in a container. This makes self-hosting straightforward: build the image, run it, configure with environment variables.

What

  • Multi-stage build: builder stage compiles native modules (better-sqlite3) and builds the Vite frontend, production stage is a clean node:22-slim
  • Use tsx for server execution (same as npm run serve) since src/ files don't compile cleanly under tsconfig.server.json
  • Copy dist/* into public/ so the Express static middleware serves built assets (the server reads from both directories)
  • Run as non-root node user with dumb-init for proper signal handling
  • No secrets in layers: all config via runtime environment variables

Environment variables

Variable Required Default Purpose
DATABASE_PATH No proof-share.db SQLite database path
PORT No 4000 Server port
PROOF_PUBLIC_BASE_URL Yes (HTTPS) - Public URL for WebSocket URLs
PROOF_COLLAB_SIGNING_SECRET Yes (non-local) - Required when public URL is non-localhost
PROOF_CORS_ALLOW_ORIGINS No localhost Comma-separated allowed origins
SNAPSHOT_DIR No snapshots/ Snapshot directory

Usage

docker build -t proof-sdk .
docker run -d \
  -p 4000:4000 \
  -v proof-data:/data \
  -e DATABASE_PATH=/data/proof-share.db \
  -e PROOF_PUBLIC_BASE_URL=https://proof.example.com \
  -e PROOF_COLLAB_SIGNING_SECRET=$(openssl rand -hex 32) \
  proof-sdk

Compose example

services:
  proof:
    build: .
    image: proof-sdk:latest
    container_name: proof
    restart: unless-stopped
    ports:
      - "4000:4000"
    environment:
      DATABASE_PATH: /data/proof-share.db
      PROOF_COLLAB_SIGNING_SECRET: ${PROOF_COLLAB_SIGNING_SECRET}
      PROOF_PUBLIC_BASE_URL: ${PROOF_PUBLIC_BASE_URL:-http://localhost:4000}
      # PROOF_CORS_ALLOW_ORIGINS: "https://proof.example.com"
    volumes:
      - proof-data:/data

volumes:
  proof-data:

Known limitation

The repo gitignores package-lock.json, so the build uses npm install instead of npm ci. Dependency versions may drift between builds.

Copilot AI review requested due to automatic review settings March 29, 2026 14:55
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an official Dockerfile to enable self-hosted container deployments of the Proof SDK server (including building the Vite frontend and native deps) with a multi-stage build.

Changes:

  • Introduces a multi-stage Docker build (builder compiles deps/builds frontend; runtime is slim + non-root + dumb-init).
  • Copies built frontend artifacts into the runtime image and runs the server via tsx (matching npm run serve).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +25 to +30
# Build frontend SPA (Vite → dist/), then merge into public/ so the
# Express static middleware can serve the built assets alongside existing
# static files, then prune dev dependencies.
# Single RUN so dev deps don't persist in any layer.
RUN npm run build \
&& cp -r dist/* public/ \
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cp -r dist/* public/ will copy dist/index.html into public/, and because express.static(.../public) is registered before app.get('/') (see server/index.ts), requests to / will start serving the SPA index.html instead of the server’s landing page route. To avoid this behavior change, only copy the built asset directory into public (e.g. dist/assets -> public/assets) while keeping dist/index.html in dist/ for share-web-routes to read.

Suggested change
# Build frontend SPA (Vite → dist/), then merge into public/ so the
# Express static middleware can serve the built assets alongside existing
# static files, then prune dev dependencies.
# Single RUN so dev deps don't persist in any layer.
RUN npm run build \
&& cp -r dist/* public/ \
# Build frontend SPA (Vite → dist/), then copy only built assets into
# public/ so Express can serve them, while keeping dist/index.html in dist/
# for the server routes to read, then prune dev dependencies.
# Single RUN so dev deps don't persist in any layer.
RUN npm run build \
&& mkdir -p public/assets \
&& cp -r dist/assets/* public/assets/ \

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The copy is intentional. Serving the SPA at / via public/index.html is the expected behavior. share-web-routes reads dist/index.html separately for document pages (/d/... routes), not the root. Both paths work correctly with this setup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants