This repository contains a DAppNode package for the upstream Supabase self-hosted Docker stack. Codex should read this file first when continuing work on this package.
- Package name:
supabase.public.dappnode.eth - Current test version:
0.1.7 - Current test architecture:
linux/amd64only - Latest uploaded test CID:
/ipfs/QmYQ1D2iK9Ai5QdzNNzySSN8YAREGAwLW3Wzvq3Zb8M21V - Latest installer URL:
http://my.dappnode/installer/public/%2Fipfs%2FQmYQ1D2iK9Ai5QdzNNzySSN8YAREGAwLW3Wzvq3Zb8M21V - User confirmed
0.1.7works on the test DAppNode. - Install of
0.1.6worked on a clean DAppNode after old Supabase volumes were removed; old partial DB volumes were the likely cause of earlier Analytics install failures. - Supabase Studio UI is reachable through Kong at
http://supabase.public.dappnode:8000. - Rest no longer restarts after the
0.1.7shell-free launcher fix.
- Added
setup-wizard.ymlto ask forPOSTGRES_PASSWORDandDASHBOARD_PASSWORD. - Fresh installs now require setup-wizard passwords; the package must not randomly generate the Studio dashboard password.
POSTGRES_PASSWORDis restricted to alphanumeric characters to keep generated DB connection strings safe.- Moved DAppNode Info-tab package sent values from Kong to the
secretsservice, where credentials are generated/reused. - Package sent values are URL-encoded and logged/retried by
assets/secrets/generate-secrets.js. - Fixed the shell-less PostgREST image by adding a static Go launcher at
build/rest/with-secrets-rest/. build/rest/Dockerfilenow builds and copies/usr/local/bin/with-secrets-restinstead of usingwith-secrets.sh.- Added a Rest healthcheck and made Storage wait for Rest to be healthy.
- Added a longer Analytics healthcheck grace period.
- Uploaded and tested amd64 package
0.1.7at/ipfs/QmYQ1D2iK9Ai5QdzNNzySSN8YAREGAwLW3Wzvq3Zb8M21V.
For first test builds, always ask which architecture the test DAppNode needs and build only that architecture. Do not build multi-arch for early testing. Multi-arch is only for after the package has been tested and works.
For the current test DAppNode, use linux/amd64 unless the user says otherwise.
Use a Docker config without credential helpers to avoid local credential-store problems:
env DOCKER_CONFIG=/tmp/docker-config-no-cred npx @dappnode/dappnodesdk build --provider http://172.33.0.10:5001 --timeout 180min --verboseOlder provider used during testing:
env DOCKER_CONFIG=/tmp/docker-config-no-cred npx @dappnode/dappnodesdk build --provider http://172.33.0.3:5001 --timeout 180min --verboseThe provider may occasionally fail during upload with write EPIPE. If the build itself completed and only upload failed, retry once before changing code.
On this Mac, the installed Docker CLI may not expose docker compose or docker buildx even though Docker Desktop has the plugins. A working local shim was:
#!/bin/sh
if [ "$1" = "compose" ]; then
shift
exec /Users/lanski/.docker/cli-plugins/docker-compose "$@"
fi
if [ "$1" = "buildx" ]; then
shift
exec /Users/lanski/.docker/cli-plugins/docker-buildx "$@"
fi
exec /opt/homebrew/bin/docker "$@"Put it at /tmp/docker-compose-shim/docker, make it executable, and run:
env PATH=/tmp/docker-compose-shim:$PATH DOCKER_CONFIG=/tmp/docker-config-no-cred npx @dappnode/dappnodesdk build --provider http://172.33.0.10:5001 --timeout 180min --verboseUseful validation:
npx @dappnode/dappnodesdk validate
docker compose config --quietLocal compose smoke test pattern:
env DOCKER_CONFIG=/tmp/docker-config-no-cred docker compose --project-name supabase-debug up --detach
env DOCKER_CONFIG=/tmp/docker-config-no-cred docker compose --project-name supabase-debug ps
env DOCKER_CONFIG=/tmp/docker-config-no-cred docker compose --project-name supabase-debug down --volumesBe careful with down --volumes: only use it for local throwaway debug projects.
- Keep persistent data in named volumes so updates do not wipe databases.
- Current persistent volumes:
configfor generated Supabase secrets at/run/supabase-configdb-datafor Postgres data at/var/lib/postgresql/datadb-configfor Postgres custom configstoragefor object storagefunctionsfor edge functionssnippetsfor Studio snippetsdeno-cachefor Edge Runtime cache
- DAppNode install rollback may leave enough state around to confuse later tests. When debugging first install behavior, test with all old Supabase volumes removed. This was confirmed: removing old Supabase volumes allowed the package to install.
- Do not rely on bind mounts from the upstream Supabase compose; DAppNode packages need config baked into images or stored in package volumes.
- Non-core DAppNode packages should not depend on mounting the Docker socket. This package disables the optional upstream Vector log collector for that reason.
- DAppNode package sent values are typically sent from inside the package with:
POST http://my.dappnode/data-send?key=<urlencoded key>&data=<urlencoded value>
- Package sent values must be URL-encoded. JWTs, base64 strings, and generated passwords may contain characters that break raw query params.
- Prefer publishing package sent values from the service that owns/generates the values. For this package, that should be the
secretsservice, not Kong. - For values the user must know or choose, prefer
setup-wizard.ymlover random generation. - The DAppNode setup wizard runs before package install and only injects environment variables. It cannot fetch generated runtime values.
- The DAppNode Info tab can display "Key and Package Sent Values" after install, using the
data-sendpattern.
Supabase upstream:
- Repository:
https://github.com/supabase/supabase - Upstream Docker stack:
https://github.com/supabase/supabase/tree/master/docker - Upstream
.env.example:https://raw.githubusercontent.com/supabase/supabase/master/docker/.env.example - Self-hosting docs:
https://supabase.com/docs/guides/hosting/docker
DAppNode package / setup wizard reference:
- Obol package repository:
https://github.com/dappnode/DAppNodePackage-obol-generic - Setup wizard reference:
https://raw.githubusercontent.com/dappnode/DAppNodePackage-obol-generic/main/setup-wizard.yml - Obol package metadata reference:
https://raw.githubusercontent.com/dappnode/DAppNodePackage-obol-generic/main/dappnode_package.json - Obol compose reference:
https://raw.githubusercontent.com/dappnode/DAppNodePackage-obol-generic/main/docker-compose.yml - Obol getting started reference:
https://raw.githubusercontent.com/dappnode/DAppNodePackage-obol-generic/main/getting-started.md - Obol package sent values pattern was previously inspected in its cluster scripts. Re-check the Obol repo if the DAppNode
data-sendbehavior needs confirmation.
The package uses a generated config file:
/run/supabase-config/supabase.env
Generated by:
assets/secrets/generate-secrets.js
Consumed by:
assets/secrets/with-secrets.sh
Most services wrap their upstream image with with-secrets.sh, which waits for supabase.env, sources it, exports service-specific env vars, and execs the upstream service.
This works only in images that include /bin/sh.
Symptom on DAppNode:
exec /usr/local/bin/with-secrets.sh: no such file or directory
Root cause:
build/rest/Dockerfilecopiesassets/secrets/with-secrets.sh.- The script starts with
#!/bin/sh. postgrest/postgrest:v14.8has no/bin/sh.- Docker's error is misleading: the wrapper script may exist, but its interpreter does not.
This was reproduced locally:
env DOCKER_CONFIG=/tmp/docker-config-no-cred docker run --rm --entrypoint /usr/local/bin/with-secrets.sh rest.supabase.public.dappnode.eth:0.1.6It fails with:
exec /usr/local/bin/with-secrets.sh: no such file or directory
And:
env DOCKER_CONFIG=/tmp/docker-config-no-cred docker run --rm --entrypoint /bin/sh rest.supabase.public.dappnode.eth:0.1.6 -lc 'ls'fails with:
exec: "/bin/sh": stat /bin/sh: no such file or directory
Resolution:
- Added a static Go launcher at
build/rest/with-secrets-rest/main.go. build/rest/Dockerfilebuilds this launcher in a Go builder stage and copies it into the shell-less PostgREST image.- The launcher waits for
/run/supabase-config/supabase.env, parses required values, sets PostgREST env vars, andexecspostgrest.
Current behavior:
- Fresh installs generate
DASHBOARD_PASSWORDrandomly ingenerate-secrets.js. - This is bad UX because the user cannot know it if Info tab publishing fails.
Implemented behavior:
- Added
setup-wizard.yml. - Asks user for
DASHBOARD_PASSWORD. - Asks user for
POSTGRES_PASSWORD. - Persists these values into
supabase.env. - Fresh installs fail if wizard passwords are missing.
Password guidance:
POSTGRES_PASSWORDshould be letters and numbers only to avoid URL-encoding issues in DB connection strings.DASHBOARD_PASSWORDcan be user-selected, but keep validation/guidance simple for first iteration.
Current behavior:
assets/api/kong-entrypoint.shposts package sent values tohttp://my.dappnode/data-send.- The Info tab did not show them in
0.1.6. - The post is silent and raw query strings are not URL-encoded.
Implemented behavior:
- Moved value publishing to
secretsservice aftergenerate-secrets.jsgenerates or reusessupabase.env. - Uses JavaScript
URL.searchParams, which URL-encodes keys and values. - Logs success/failure for each published key so DAppNode logs show what happened.
- Keeps retry behavior because DAppNode UI/API may not be immediately reachable.
Values to publish:
Supabase URLSupabase Anon KeySupabase Service Role Key (server only)Supabase Dashboard UsernameSupabase Dashboard PasswordSupabase S3 Access Key IDSupabase S3 Secret Access Key
analytics is Logflare and can take time on DAppNode. Current healthcheck has no start_period.
Implemented in 0.1.7 with a longer start period and more retries.
Rest currently has no container healthcheck. Add a healthcheck that proves PostgREST is reachable.
Implemented in 0.1.7 using /usr/local/bin/with-secrets-rest healthcheck.
Also add an end-to-end smoke test through Kong:
curl -i -sS \
-H "apikey: <ANON_KEY>" \
-H "Authorization: Bearer <ANON_KEY>" \
http://localhost:8000/rest/v1/Expected result for a working empty DB is HTTP/1.1 200 OK.
Rest is PostgREST. It needs these values from supabase.env:
POSTGRES_PASSWORD
JWT_SECRET
JWT_EXP
These become:
PGRST_DB_URI=postgres://authenticator:<POSTGRES_PASSWORD>@db:5432/postgres
PGRST_JWT_SECRET=<JWT_SECRET>
PGRST_APP_SETTINGS_JWT_SECRET=<JWT_SECRET>
PGRST_APP_SETTINGS_JWT_EXP=<JWT_EXP>
It also uses static config:
PGRST_DB_SCHEMAS=public,storage,graphql_public
PGRST_DB_MAX_ROWS=1000
PGRST_DB_EXTRA_SEARCH_PATH=public
PGRST_DB_ANON_ROLE=anon
PGRST_DB_USE_LEGACY_GUCS=false
Implemented a tiny static launcher binary for Rest instead of a shell script:
- Wait until
/run/supabase-config/supabase.envexists. - Parse lines like
export KEY='value'. - Set PostgREST env vars listed above.
- Execute PostgREST directly, replacing itself.
Language: Go.
Example build approach:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o with-secrets-rest ./build/rest/with-secrets-restThen copy the static binary into the Rest image and set:
ENTRYPOINT ["/usr/local/bin/with-secrets-rest"]
CMD ["postgrest"]Do not use /bin/sh in the Rest image.
The implementation is intentionally scoped to Rest because it is the known shell-less image. Later, consider replacing with-secrets.sh for all services with one shared binary launcher to avoid base-image surprises.
setup-wizard.yml exists at repo root.
Minimum fields:
DASHBOARD_PASSWORDPOSTGRES_PASSWORD
The secrets service receives wizard-injected env vars, and generate-secrets.js requires them for fresh installs.
Important:
- Setup wizard cannot fetch or display generated values before install.
- Generated values that users need after install should be displayed through package sent values in the Info tab.
- Commit and push any follow-up fixes before rebuilding.
- Test credential display in the DAppNode Info tab after
0.1.7. - Test API smoke through Kong with anon and service-role keys:
/auth/v1/health/rest/v1/- Studio login with setup-wizard dashboard password
- If
0.1.7remains stable, prepare a multi-arch build only after confirming target architectures and user approval. - Consider removing the obsolete top-level Compose
versionfield to silence DAppManager warnings. - Consider a future shared binary secrets launcher for all services, but do not expand scope unless a base-image shell issue appears elsewhere.
- Add
setup-wizard.ymlfor dashboard and Postgres passwords. - Update
docker-compose.ymlsecrets.environmentto pass wizard values into the secrets generator. - Update
assets/secrets/generate-secrets.js:- accept wizard-provided
DASHBOARD_PASSWORD - accept wizard-provided
POSTGRES_PASSWORD - preserve old values if
supabase.envalready exists - publish package sent values with URL encoding and visible logs
- accept wizard-provided
- Add static Go Rest launcher:
- new source under
build/rest/with-secrets-rest/orassets/secrets/with-secrets-rest/ - multi-stage build in
build/rest/Dockerfile - no shell dependency
- new source under
- Add Rest healthcheck.
- Add analytics
start_periodand/or more retries. - Bump version to
0.1.7. - Validate:
docker compose config --quietnpx @dappnode/dappnodesdk validate
- Build amd64-only test package, upload to the user's specified IPFS provider, and report CID.
- Only after the user confirms it works, discuss multi-arch.
Before upload:
- Confirm target test architecture with user if not already specified.
- Confirm target IPFS provider with user if not already specified.
- Confirm clean install vs update test.
- Verify Rest image directly:
env DOCKER_CONFIG=/tmp/docker-config-no-cred docker run --rm --entrypoint /usr/local/bin/with-secrets-rest rest.supabase.public.dappnode.eth:<version>Expected direct run without config file should wait or timeout with a clear message, not no such file or directory.
-
Verify local compose stack:
dbhealthysecretsrunninganalyticshealthyauthhealthyrestrunning/healthyrealtimehealthystoragehealthystudiohealthykonghealthy
-
Verify API smoke:
curl -i -sS http://localhost:8000/auth/v1/health
curl -i -sS -H "apikey: <ANON_KEY>" -H "Authorization: Bearer <ANON_KEY>" http://localhost:8000/rest/v1/- Verify Info tab publisher logs from
secretsservice show successful publication.
docker-compose.ymldappnode_package.jsonassets/secrets/generate-secrets.jsassets/secrets/with-secrets.shassets/api/kong-entrypoint.shbuild/rest/Dockerfilebuild/secrets/Dockerfilebuild/kong/DockerfileREADME.md
- Do not build multi-arch for test iterations.
- Do not silently swallow package sent value publishing errors in the next version.
- Do not randomize dashboard password once setup wizard provides it.
- Do not break existing persisted volumes on package update.
- Do not remove generated secrets if
supabase.envalready exists. - Do not rely on
/bin/shin the PostgREST image.