Files
neta/docs/deployment/self-hosting.md
T

3.4 KiB

Self-Hosting Deployment

Neta has two Docker modes.

Full-Stack Mode

Use this when the server should run Neta and the bundled Supabase-compatible stack.

Compose file:

docker-compose.full.yml

Services:

  • neta-web: Next.js app
  • neta-db: Postgres with pgvector
  • neta-auth: Supabase Auth
  • neta-rest: PostgREST
  • neta-storage: Supabase Storage with local disk backend
  • neta-supabase-proxy: single public API entrypoint
  • neta-migrations: Neta database migration runner

Generate production secrets:

node scripts/generate-full-stack-env.mjs > .env

Then adjust these values before starting:

  • NEXT_PUBLIC_SITE_URL: public Neta URL
  • NEXT_PUBLIC_SUPABASE_URL: public bundled Supabase API URL
  • NETA_PORT: host port for Neta when deploying directly with Docker
  • SUPABASE_API_PORT: host port for the bundled Supabase API
  • POSTGRES_PORT: host port for backup/manual DB access

Start:

docker compose -f docker-compose.full.yml up -d --build

Check the running stack:

sh ./scripts/selfhost-doctor.sh

To run a real Auth signup/login smoke test, enable the optional check:

NETA_DOCTOR_AUTH_SMOKE=1 sh ./scripts/selfhost-doctor.sh

App-Only Mode

Use this when Neta connects to an existing Supabase or Supabase-compatible backend.

Compose file:

docker-compose.yml

Required env values:

  • NEXT_PUBLIC_SITE_URL
  • NEXT_PUBLIC_SUPABASE_URL
  • NEXT_PUBLIC_SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY
  • DATABASE_URL only when applying migrations manually

Apply migrations:

DATABASE_URL='postgresql://postgres:password@host:5432/postgres' sh ./scripts/apply-migrations.sh

Start:

docker compose up -d --build

Coolify

For a no-external-service install, choose Docker Compose deployment and set the compose file to docker-compose.full.yml.

Set the generated full-stack env values in Coolify's environment variables. Route the app domain to neta-web:3000. If you expose Supabase through a second domain, route it to neta-supabase-proxy:8000 and set NEXT_PUBLIC_SUPABASE_URL to that public URL.

Dokploy

Create a Compose app from this repository. Use docker-compose.dokploy.yml for full-stack deployments and paste the generated env values into the environment panel. This compose file avoids fixed container names and host port bindings so Dokploy can route services itself.

Route the Neta domain to neta-web port 3000. Route the bundled Supabase API domain, if used, to neta-supabase-proxy port 8000.

Backup And Restore

Full-stack mode stores the database in the neta-db-data Docker volume and uploaded files in the neta-storage-data Docker volume.

Create a backup:

sh ./scripts/selfhost-backup.sh

The backup is written to ./backups/<timestamp>/ and contains:

  • postgres.dump: custom-format Postgres dump
  • storage.tar.gz: local storage archive
  • manifest.txt: backup metadata

Restore a backup:

sh ./scripts/selfhost-restore.sh ./backups/20260101T120000Z

Set NETA_RESTORE_FORCE=1 for non-interactive restores:

NETA_RESTORE_FORCE=1 sh ./scripts/selfhost-restore.sh ./backups/20260101T120000Z

First Admin

Open /register after the stack starts. The first registered user becomes the admin, and public registration is locked after that.

Full-stack deployments apply the first-admin registration guard automatically through neta-migrations; the installer should not run SQL manually.