Deployment configuration ​

This guide covers the server and container settings operators can configure. For a complete list of supported values, defaults, sensitivity, source readers, and owning pages, see the operator configuration reference. The Docker / FabLab Server instructions cover initial setup and compose commands.

GitHub Pages browser demo ​

The documentation workflow also builds a static editor demo and publishes it at /Demo/. Its Next.js base path is set at build time to /<repository>/Demo, and the workflow stages the export alongside the documentation site. The editor stores each visitor's projects in that visitor's browser. Static hosting does not provide server-side project storage or the REST API; use a server deployment for those features.

Docker listener ​

The compose files publish container port 3000 on host port 3000 by default. Set SKETCHFORGE_PORT to change the host port. Inside the container, PORT selects the Next.js listener port, HOSTNAME selects its bind address, and SKETCHFORGE_LEGACY_PORT selects the compatibility proxy port (80 by default). The launcher accepts ports from 1 through 65535 and falls back to its documented default for invalid values. Set the legacy port equal to PORT to disable the compatibility proxy. See the port configuration example.

Server-backed projects ​

Set SKETCHFORGE_PROJECTS_DIR to a writable persistent directory to store a user's projects on the server instead of in browser-local storage. The Docker compose configuration maps /data/my-projects to the sketchforge-projects volume by default; SKETCHFORGE_PROJECTS_VOLUME changes that volume or bind-mount source. See server-side project storage for migration and persistence behavior.

Who can do what ​

Server-backed projects and the shared project library are available to any caller that can reach the SketchForge server. They do not require a user account or an API token:

  • GET /api/projects is unauthenticated: it lists every server-backed project, and GET /api/projects?projectId=… reads that project's .skf file. When SKETCHFORGE_PROJECTS_DIR is configured, POST creates or overwrites a project and DELETE removes it.
  • GET /api/shared-projects is unauthenticated: it lists or downloads shared projects and thumbnails. When SKETCHFORGE_SHARED_PROJECTS_DIR is configured, POST publishes or replaces a shared project and DELETE removes one.
  • The write and delete handlers reject browser requests whose Origin does not match the server origin. They accept requests with no Origin header, which includes common command-line and scripted clients. A non-browser caller can also set request headers itself, so this same-origin check is a cross-site request defense, not authentication or an authorization boundary.
  • SKETCHFORGE_API_TOKEN protects the separate scripting API under /api/v1. It does not protect /api/projects or /api/shared-projects.

For a trusted classroom or lab network, limit access to the server to that network. For deployments reachable by untrusted users, put SketchForge behind a reverse proxy or identity gateway that authenticates and authorizes requests to these routes. Keep the application port inaccessible to clients that could bypass the proxy; proxy authentication only protects requests that pass through it. The REST API token alone does not secure server-backed or shared project storage.

The desktop-only POST /api/local-download helper is enabled only when SKETCHFORGE_DESKTOP=1 and SKETCHFORGE_LOCAL_DOWNLOAD_ROOT is configured. Its JSON request body is capped at 26 MiB and its multipart request body at 513 MiB before parsing; text content remains limited to 25 MiB and uploaded files to 512 MiB. The packaged desktop server binds to loopback. Do not enable this helper on a network listener.

REST API access ​

Set SKETCHFORGE_API_TOKEN together with SKETCHFORGE_PROJECTS_DIR to enable authenticated REST API access. Treat the token as a secret: use a high-entropy value, store it in the deployment's secret manager, and keep it out of browser code and logs. See the REST API deployment instructions.

Shared projects ​

The Docker image stores shared projects at /data/projects by default. Set SKETCHFORGE_SHARED_PROJECTS_DIR to change the path, and mount persistent storage there. The default compose volume is sketchforge-shared-projects; set SKETCHFORGE_SHARED_PROJECTS_VOLUME to choose another named volume or bind-mount source. See shared Docker projects.

Volume ownership ​

The server runs as the node user, UID 1000, so every directory it saves into must be writable by that user. Docker creates the mount point of a fresh named or anonymous volume owned by root whenever the path does not already exist in the image, and the storage directories are whatever SKETCHFORGE_SHARED_PROJECTS_DIR and SKETCHFORGE_PROJECTS_DIR name, so the image cannot prepare them ahead of time. Instead the container starts as root in a small entrypoint that creates both configured directories, hands each one to node, and then drops privileges before the server starts. Named volumes at the documented paths, at paths of your own, and volumes left root-owned by images up to 1.23.0 all work without setup.

The entrypoint changes the owner of the directory itself, not of the files below it. The server wrote those files as node, so they already belong to it.

Bind mounts. A bind-mounted host directory is handed to UID 1000 the same way, which changes that directory's owner on the host. Create it first if you want to choose where it lives:

bash
mkdir -p /srv/sketchforge/my-projects
SKETCHFORGE_PROJECTS_DIR=/data/my-projects \
SKETCHFORGE_PROJECTS_VOLUME=/srv/sketchforge/my-projects \
  docker compose -f deploy/docker/compose-ghcr.yaml up -d

Running without root. With docker run --user 1000:1000, rootless Docker, or a platform that refuses root containers, the entrypoint cannot change ownership. It still creates what it can, starts the server as that user, and logs a line naming any configured directory that user cannot write, so a misconfigured mount shows up in docker logs rather than on the first save. Make the mounted directory writable by that UID yourself in this mode.

The container health check asks /api/shared-projects for its status. Turning shared projects off with an empty SKETCHFORGE_SHARED_PROJECTS_DIR leaves the container healthy; an unreadable shared library reports it unhealthy.

Application updates ​

The dashboard checks the official release manifest and offers an update when a newer version exists. The Update button calls POST /api/app-update, which works in one of two modes. Each mode has its own gate.

Server mode is for container and managed deployments. Set SKETCHFORGE_UPDATE_TRIGGER_URL to an internal endpoint you control that recreates only the SketchForge application and keeps its project volumes. Also set SKETCHFORGE_UPDATE_ADMIN_KEY, the key the administrator types into the update dialog. SKETCHFORGE_UPDATE_TRIGGER_TOKEN is optional; SketchForge sends it as a bearer token to the trigger endpoint. The Docker image contains no .git directory, so a container always uses server mode.

Local mode applies when the server runs from a git clone and the request is addressed to localhost, 127.0.0.1, or [::1]. It runs git fetch and git merge --ff-only against the official repository and npm install in that checkout, then restarts the dev server. It needs one of the following:

  • SKETCHFORGE_UPDATE_ADMIN_KEY: the dialog asks for the key, as in server mode.
  • SKETCHFORGE_LOCAL_UPDATE=1: no key is asked for. Set this only when the server listens on loopback alone, for example npx next dev apps/web -H 127.0.0.1.

With neither set, the dialog links to the update guide and the endpoint returns 403.

The address check uses the Host header, which the client controls. A route handler cannot see the TCP peer address: Next.js keeps a client-supplied X-Forwarded-For header and does not replace it. Any machine that can reach the server can therefore claim to be localhost. Treat the admin key or the loopback-only listener as the security boundary.

Releases up to 1.23.0 ran local mode with neither setting. If you update a source checkout from the dashboard, set one of them.

The packaged desktop app does not use this endpoint. It updates through its built-in release updater, and none of these settings affect it.


Documentation version: 1.30.0 · Repository revision: 1cb9fee8dff4d394684c229dd67a21da539d167f · View source