Back to Hoppscotch

Hoppscotch Webapp Server (Go)

packages/hoppscotch-selfhost-web/webapp-server/README.md

2026.4.05.0 KB
Original Source

Hoppscotch Webapp Server (Go)

Static web server for Hoppscotch Webapp with content bundling (zstd + zip) and verification (blake3 + ed25519).

Quick Start

bash
go build -o webapp-server .
GO_ENV=development ./webapp-server

or with Docker

bash
docker build -t hoppscotch-webapp-server .

Configuration

VariableDescriptionDefault
WEBAPP_SERVER_PORTServer port3200
WEBAPP_SERVER_READ_TIMEOUTHTTP read timeout (Go duration, e.g. 30s; 0 disables)15s
WEBAPP_SERVER_WRITE_TIMEOUTHTTP write timeout (Go duration, e.g. 30s; 0 disables)15s
WEBAPP_SERVER_IDLE_TIMEOUTHTTP idle timeout (Go duration, e.g. 2m; 0 disables)60s
FRONTEND_PATHPath to frontend assets/site/selfhost-web (prod) or ../dist (dev)
WEBAPP_SERVER_SIGNING_SECRETSecret string for key derivationNone
WEBAPP_SERVER_SIGNING_SEEDBase64 encoded 32-byte seedNone
WEBAPP_SERVER_SIGNING_KEYBase64 encoded 64-byte private keyNone
WEBAPP_SERVER_SIGNING_KEY_FILECustom path for key file/data/webapp-server/signing.key
GO_ENVSet to development for dev modeNone

Signing Key Persistence

The server needs a stable signing key. Without one, users get "Invalid signature" errors when they have cached bundles from a previous server instance. Keys are resolved in order:

  1. Environment variable: WEBAPP_SERVER_SIGNING_KEY, WEBAPP_SERVER_SIGNING_SEED, or WEBAPP_SERVER_SIGNING_SECRET
  2. Key file on disk at /data/webapp-server/signing.key
  3. Auto-generate and persist to disk
  4. Ephemeral fallback (logs the key for manual config)

For Kubernetes, either mount a persistent volume at /data/webapp-server or set WEBAPP_SERVER_SIGNING_SECRET to the same value across replicas.

If the server can't persist to disk, it logs the generated key:

========================================
SIGNING KEY PERSISTENCE FAILED
========================================
Could not save signing key to: /data/webapp-server/signing.key

To persist this key, set this environment variable:

  WEBAPP_SERVER_SIGNING_KEY=<base64-encoded-key>

Or mount a persistent volume at:
  /data/webapp-server
========================================

Copy the logged key value and set it as an environment variable before the next restart.

API Endpoints

EndpointDescription
GET /healthHealth check
GET /api/v1/manifestBundle metadata with file hashes and signature
GET /api/v1/bundleDownload signed ZIP bundle
GET /api/v1/keyPublic verification key

All endpoints also available under /desktop-app-server/ prefix for desktop app compatibility.

Architecture

Frontend files → zstd ZIP → BLAKE3 per file → ED25519 sign → HTTP serve
                                ↓
                          Manifest JSON
                    (paths, sizes, hashes, MIME types)

Bundle Format

ComponentMethod
Compressionzstd (ZIP method 93)
File hashingBLAKE3 (base64)
Bundle signingED25519 over ZIP content

Troubleshooting

"Invalid signature" after restart: Server generated a new key because persistence wasn't configured. Mount a volume at /data/webapp-server or set WEBAPP_SERVER_SIGNING_SECRET.

"Invalid signature" with multiple replicas: Each replica has a different key. Use env var config with the same secret across all replicas.

Key file permission errors: Container can't write to /data/webapp-server. Make it writable or use env var config.

Development

bash
GO_ENV=development go run .
go test ./...
CGO_ENABLED=0 GOOS=linux go build -o webapp-server .

Migration from Rust Version

Full API and bundle format compatibility with the Rust version. Same ZIP structure, same BLAKE3 hashing, same ED25519 signatures, identical API responses. New feature is automatic signing key persistence.