Brave Sync at sync.brunner.ninja
This chart runs the official Brave Sync v2 server from the commit in upstream-commit.txt. The app image is built by Gitea Actions because Brave does not publish an official container image. DynamoDB Local holds the encrypted sync entities on a rook-ceph-block PVC. Valkey provides the server cache. The Sync API is published through Traefik with a cert-manager certificate.
The service has no web UI or interactive login. https://sync.brunner.ninja/ returns a simple HTTP heartbeat; browsers use the /v2/command/ API. Brave authenticates with a Sync Chain code and encrypts sync data before upload. Keep that code private and back it up separately. The server still sees metadata such as device information and item IDs. Brave Sync supports passwords, bookmarks, history, and other enabled sync types, but it is not a complete browser profile backup; check the options on every device and keep independent backups of valuable data.
Versioning
Edit only chart-version.txt for a new base chart version. CI packages a unique version <base>-r<run number> on each push to main, with appVersion set to the exact immutable sha-<commit> image tag from that run. Chart.yaml contains a fixed placeholder because Helm requires that field in source charts; package.sh replaces it when packaging. values.yaml contains only the HTTPS hostname; fixed image versions and homelab defaults live in the templates. To update Brave server source, set upstream-commit.txt to a reviewed full upstream commit and push the change.
Initial setup
- Create the Gitea repository yourself, push this local repository's
mainbranch, and configureQUAY_USERNAME,QUAY_TOKEN,PACKAGE_USERNAME,PACKAGE_TOKEN, and laterKUBE_CONFIG_BASE64as Gitea Actions repository secrets. The Quay repository path isregistry.brunner.ninja/feedc0de/brave-sync. - The initial rollout created a Cloudflare CNAME from
sync.brunner.ninjatobrunner.ninjaand cert-manager issuedbrave-sync-tls. For a fresh installation elsewhere, create equivalent DNS before connecting browsers. - Wait for the first
mainCI run to publish the image and chart. Its image tag issha-<first 12 characters of commit SHA>. - Bootstrap the namespace and copy the existing homelab Quay pull credentials with
./bootstrap.sh. This copy stays within the homelab cluster. The initial rollout has already completed this step. - Run
IMAGE_TAG=sha-<first 12 characters of commit SHA> ./install.sh. The script checks the default context, lints/renders the chart, performs server dry-runs, then runshelm upgrade --install --wait. The initial rollout has already installed the chart. - The limited deployer ServiceAccount and Role already exist. Run
./create-ci-kubeconfig.shand store its single-line output only in theKUBE_CONFIG_BASE64Gitea secret. Do not commit it. Then rerun the workflow or push the next change. CI can update only the named workload objects; it cannot read Kubernetes Secrets or create/delete workloads.
The published chart is available via helm repo add brunner https://brunner.ninja/charts && helm repo update brunner. install.sh is kept for manual deployments. CI renders the same chart and patches the named existing resources, since Helm release storage would require CI to read Kubernetes Secrets. A later manual Helm upgrade reconciles Helm's stored release revision with the latest chart.
Connect a Brave browser
On each supported Brave device, set brave://flags/#brave-override-sync-server-url to https://sync.brunner.ninja/v2, relaunch, and confirm the endpoint in brave://sync-internals/. Then create or join the Sync Chain at brave://settings/braveSync/setup. Enable the data types you want on each device. A compatibility route handles Brave versions that strip /v2 from the custom URL after relaunch. Do not put Authentik forward authentication on this API; browser sync requests cannot complete its interactive login. On platforms where the flag is unavailable, a client policy or --sync-url=https://sync.brunner.ninja/v2 may be required.
Avoid moving an existing production Sync Chain blindly. Export passwords and bookmarks before switching its endpoint and confirm sync on a second test profile first. Each device in a chain must point to the same server.
Check health and backups
./test.sh lints and renders the chart without duplicating deployment values. ./smoke-test.sh IMAGE runs a real server with DynamoDB Local and Valkey in Podman and verifies its HTTP command path. After installation, check kubectl -n brave-sync get pods,ingress,pvc,certificate, helm -n brave-sync status brave-sync, and brave://sync-internals/. Back up the data-brave-sync-dynamodb-0 PVC regularly; the server stores the encrypted Sync Chain data there. Test restoring it before relying on this instance as the only copy of credentials.