This repository is deployed on a single Ubuntu host with:
- local
nginx systemdfor API and web- Docker for PostgreSQL and Redis
- desktop web on a production Next.js server
- optional localhost-only Next dev server for remote debugging over SSH
Install the host packages:
sudo apt-get update
sudo apt-get install -y docker.io docker-compose-v2 nginx
sudo systemctl enable --now docker nginxGenerate the local-only env files:
./setup.shThis creates:
.envpackages/web-next/.env.local
Optional web env:
NEXT_ALLOWED_DEV_ORIGINSfor extra Next dev origins, as a comma-separated list of hostnames or URLs
Before starting the API in any environment, fill the Volcengine realtime ASR variables in .env:
ASR_PROVIDER=volcengineVOLCENGINE_ASR_APP_IDVOLCENGINE_ASR_ACCESS_TOKENVOLCENGINE_ASR_SECRET_KEYVOLCENGINE_ASR_RESOURCE_ID=volc.seedasr.sauc.durationVOLCENGINE_ASR_WS_URL=wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_asyncVOLCENGINE_ASR_MAX_CONCURRENCY=3VOLCENGINE_ASR_CONNECT_TIMEOUT_MS=10000VOLCENGINE_ASR_IDLE_TIMEOUT_MS=15000
Default seeded platform admin:
- email:
demo@synapse.dev - password:
demo1234
Start the local-only infrastructure containers:
sudo docker compose up -d postgres redisNotes:
- Redis is bound to loopback and requires a password from
.env
Install Node dependencies:
npm ciFor full reset plus seed data:
bash -lc 'set -a && source ./.env && set +a && npm run db:reset -w packages/api'For schema-only initialization:
bash -lc 'set -a && source ./.env && set +a && npm run db:migrate -w packages/api'Install and enable the services:
sudo install -m 644 infrastructure/systemd/synapse-api.service infrastructure/systemd/synapse-web.service infrastructure/systemd/synapse-web-dev.service -t /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now synapse-api synapse-webImportant:
- On hosts with
synapse-api.serviceenabled, do not also start the API manually withnpm run start -w packages/api,node dist/index.js, ornpm run dev -w packages/api. synapse-api.serviceis the only supported API process on the host. A second API instance can grab port3001, triggerEADDRINUSE, and cause repeated restart attempts.infrastructure/scripts/start-api.shnow refuses to start when port3001is already in use, and exits with status200. The unit file treats that exit code as non-restartable to avoid restart storms.synapse-web.serviceis the only public web entrypoint and binds127.0.0.1:3000for nginx to proxy.synapse-web-dev.servicebinds127.0.0.1:3002only. Keep it disabled by default and start it only when you need remote dev debugging.
For remote web development:
sudo systemctl start synapse-web-dev
ssh -L 3002:127.0.0.1:3002 <user>@<host>Then open http://127.0.0.1:3002 locally through the tunnel.
Do not commit the real infrastructure/nginx.conf.
It is intentionally gitignored.
Create a local config from infrastructure/nginx.conf.template and replace:
{{SERVER_NAME}}{{API_UPSTREAM}}{{WEB_UPSTREAM}}{{TLS_CERT_PATH}}{{TLS_KEY_PATH}}
Install it:
sudo install -d -m 755 /etc/nginx/certs /etc/nginx/sites-available /etc/nginx/sites-enabled
sudo install -m 644 infrastructure/nginx.conf /etc/nginx/sites-available/synapse.conf
sudo ln -sfn /etc/nginx/sites-available/synapse.conf /etc/nginx/sites-enabled/synapse.conf
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginxCheck services:
systemctl is-active synapse-api synapse-web nginx dockerCheck health:
curl -sS http://localhost:3001/api/v1/health
curl -sS https://<your-domain>/api/v1/health
curl -I http://127.0.0.1:3000If a session shows Recovered after the previous worker stopped while this turn was still running.:
- A previous API worker exited while a turn was still marked
running. The message is a recovery marker, not a model response. - First check for duplicate API processes:
systemctl status synapse-api.service --no-pager
ss -ltnp | rg ':3001'
ps -eo pid,ppid,lstart,etime,cmd | rg 'node dist/index.js|npm run start -w packages/api|tsx watch src/index.ts'- If port
3001is owned by a user-session process instead ofsynapse-api.service, stop the stray process and then restart the service:
sudo systemctl stop synapse-api.service
kill <stray-pid>
sudo systemctl start synapse-api.service- If you need to confirm whether the service is looping on startup, inspect the API journal:
journalctl -u synapse-api.service -n 100 --no-pager