Skip to content

Deploy Graft with Docker

Run your own Sync server for Eidos Lite. Start the container, generate its private initialization link on the server, then open that complete link to choose storage. Graft creates the access key for you. The root address and /setup alone are not authorized setup entry points.

Use local disk for the simplest setup, or configure S3-compatible storage in the browser. Both options need persistent disk space on your server.

  • A Linux AMD64 or ARM64 server with Docker Engine and Compose v2 and curl.
  • An HTTPS address supplied by your existing proxy or hosting platform. If you need a proxy, use the optional Caddy configuration below.
  • Eidos Lite with Spark active on each computer that will use this server. An official Sync subscription is not required.

Caddy is optional. Replace sync.example.com below with your actual hostname. Run the commands on your server.

For a new installation, create a private directory and download the deployment file:

Terminal window
mkdir -m 700 ~/graft-sync
cd ~/graft-sync
curl -fL --retry 3 -o compose.yaml \
https://github.com/eidos-space/graft/releases/download/graft-docker-v0.2.1/compose.yaml
cat > .env <<'EOF_ENV'
GRAFT_PUBLIC_ORIGIN=https://sync.example.com
EOF_ENV

The file uses the public Graft Docker 0.2.1 release and pins the image by digest. No GitHub login, source checkout or local build is needed. Use an HTTPS address without a path. Run later Compose commands from this directory.

Forward your HTTPS address to http://127.0.0.1:8787 on the server. A proxy in another container needs the same Docker network and upstream http://graft:8787. Keep port 8787 private. Allow request bodies of at least 64 MiB and transfers of at least 120 seconds. Forward paths and authorization headers unchanged and disable API caching. Continue to step 3.

Use this option only if you need a proxy. Point your domain’s DNS to the server, make ports 80 and 443 reachable, and ensure no other service occupies them.

Terminal window
curl -fL --retry 3 -o compose.caddy.yaml \
https://github.com/eidos-space/graft/releases/download/graft-docker-v0.2.1/compose.caddy.yaml
curl -fL --retry 3 -o Caddyfile \
https://github.com/eidos-space/graft/releases/download/graft-docker-v0.2.1/Caddyfile
cat >> .env <<'EOF_ENV'
GRAFT_DOMAIN=sync.example.com
COMPOSE_FILE=compose.yaml:compose.caddy.yaml
EOF_ENV

Use the same hostname in GRAFT_DOMAIN and GRAFT_PUBLIC_ORIGIN. Caddy starts alongside Graft and manages certificates. No host installation or system-file editing is needed.

Run both commands on your server, from the directory containing compose.yaml. Get the initialization link before opening the browser; do not open the root address or type /setup manually to configure storage.

Terminal window
docker compose up -d --wait
docker compose exec graft node services/graft-remote-docker/manage.mjs setup-link

Open the complete URL printed by setup-link, including #token=…, in your browser. It points to /setup at your public address and proves access to the server terminal. Keep the whole link private. Filling in storage details does not provide this authorization. If HTTPS is not ready, check DNS and proxy logs, then retry.

The link survives restarts until setup completes. If you close the page early, run the same command to obtain it again. Opening /setup without that link does not grant permission to configure the server.

Choose Local disk to continue without extra fields. To use S3-compatible storage, enter the details of an existing private bucket:

Field Value
S3 endpoint Your provider’s HTTPS S3 API endpoint
Region The region specified by your provider
Bucket name An existing dedicated bucket, or one with a prefix reserved for this installation
Access Key ID / Secret Access Key Bucket-scoped S3 credentials

Advanced settings contain the object prefix (default graft/), path-style addressing and an optional session token. Use a dedicated prefix ending in / and the addressing style your provider supports.

For S3, choose Test connection. Graft writes, reads and deletes a temporary object. Correct errors before continuing. Credentials also need multipart-upload permissions, including aborting incomplete uploads; versioned buckets need permission to delete object versions. This connection test does not verify large multipart uploads. Avoid retention, Object Lock or expiration rules that interfere with the installation’s objects.

Click Complete setup. Save the displayed server address and access key in your password manager. The key grants access to every Space on this server. The page displays it only once; see recovery below if you lose it.

Graft generates the key and saves configuration automatically. No terminal password generation, secret-file creation or permission commands are needed. Restarting or upgrading does not reopen setup.

In Lite, open Sync → Add server, enter a name, paste the server address and access key, then choose Test and save. Select the server for your Space and follow the prompts. See Connect a self-hosted server.

The server address must not include /setup or the initialization credential. Your Space sync password is separate: it encrypts and unlocks your Space. Save both. For an already connected Space, use Switch server instead of replacing its address.

Add a record and a small attachment, then download the Space on another computer. Open both, edit a record there and confirm the first computer receives the change. This checks synchronization beyond a server health check.

If you did not save the key, run this on the server:

Terminal window
docker compose exec graft node services/graft-remote-docker/manage.mjs access-key

This retrieves the existing key without changing it or reopening setup. Do not include keys or initialization links in screenshots or support messages.

Use docker compose stop and docker compose start from the deployment directory. Keep its files and data volumes. Do not use docker compose down -v unless you intend to delete the installation’s local data. Run one Graft instance per data volume.

Pause synchronization and stop Graft before backing up:

  • Local storage: back up the complete /data volume, including its private configuration.
  • S3 storage: back up /data and matching bucket objects while stopped. Neither copy alone is sufficient. S3 mode still uses server disk for metadata, upload parts and assembled uploads.
  • Back up Compose files, .env, externally managed secrets and, if used, Caddy’s certificate data. Keep Space sync passwords separately.

Protect backups: web configuration contains the server key and any S3 credentials. Test restoration into a separate empty volume and verify a client download. Object storage alone is not a backup; synchronization can delete objects.

Back up first. Download the new release’s files into a separate directory and compare them with your installation. Update the image reference and necessary settings, preserving data volumes, .env and credentials. Then run:

Terminal window
docker compose pull
docker compose up -d --wait

Upgrading from 0.1.1: keep your existing Compose file and mounted access-key file. Update its image reference to the new release’s digest. Existing key-file deployments remain supported and skip web setup. Replacing their Compose file with the new default would omit the key mount. The compose.secrets.yaml release asset supports externally managed keys with the new template.

Changing storage mode, endpoint, bucket or prefix does not migrate data. Deploy a separate server with fresh storage, then use Lite’s Switch server flow.

For Cloudflare R2, use the bucket’s S3 endpoint and region auto. Create S3 credentials with bucket-scoped Object Read & Write permission, rather than a general API token. For Backblaze B2, use the bucket’s endpoint and region and a bucket-restricted application key: keyID is the Access Key ID and applicationKey is the Secret Access Key.

Web setup was tested with local disk and MinIO S3. R2 storage was also tested in the previous server release; B2 is a configuration example, not a claim of live B2 acceptance. Provider storage, request and transfer charges apply.

Problem Next step
Container fails to start Run docker compose logs --tail=100 graft; check volume permissions and free disk space.
Setup link does not open Check the public address, DNS and HTTPS proxy. With optional Caddy, inspect docker compose logs --tail=100 caddy.
Test connection / Complete setup stays disabled Run docker compose exec graft node services/graft-remote-docker/manage.mjs setup-link on the server from the Compose directory; open its complete output, including #token=…. Storage fields cannot authorize setup.
Initialization link is invalid or incomplete Retrieve it again from the same installation. Links do not expire with time; they become invalid when setup completes. If already complete, use the access-key command above instead.
Setup rejects a submission Open the link directly at the HTTPS address matching GRAFT_PUBLIC_ORIGIN, without a redirect to another origin.
Setup says it is complete Use your saved key or the access-key recovery command.
S3 test fails Check endpoint, region, bucket, addressing style and permissions. If deletion was denied, clean up any leftover test object before retrying.
/healthz returns 503 before setup Expected: finish setup first. Container liveness uses /livez; it does not prove synchronization works.
Lite reports an authorization error Use the server key, not the setup credential, S3 credentials or Space sync password.