Configuration reference
Set every environment variable a self-hosted SpecsGraph install reads, store secrets and the GitHub App private key, and find the MCP URL for agents.
Where settings live
SpecsGraph reads its settings from environment variables. With the Docker Compose install, they live in .env next to the compose file, and every SpecsGraph service loads the same file. The compose file sets DATABASE_URL and REDIS_URL itself, pointing at the bundled Postgres and Redis.
After you change a value, run docker compose up -d. Compose recreates the services whose configuration changed. docker compose restart is not enough: it restarts containers with the settings they were created with.
Environment variables
To use a managed Postgres or Redis, set DATABASE_URL or REDIS_URL to its address in the x-specsgraph block of the compose file. For Postgres, write the full connection string instead of building it from POSTGRES_PASSWORD. Then remove the bundled service, its entry under depends_on in the same block, and its volume; Compose refuses to start while depends_on names a service that no longer exists. Use Postgres 16 and Redis 7, the versions the compose file runs.
Secrets
The .env file
.env holds the secret key, the database password and the GitHub credentials. Keep it readable only by the account that runs Docker (chmod 600 .env), keep it out of version control, and include it in your backups. If your team uses a secrets manager, generate .env from it at deploy time instead of editing it by hand.
The GitHub App private key
The private key is a file, not a variable. GITHUB_APP_PRIVATE_KEY_PATH tells SpecsGraph where to read it inside the container. The example compose file mounts ./secrets/github-app.pem as a Compose secret, which appears read-only at /run/secrets/github-app.pem. A read-only bind mount works too: replace the secrets entry of the x-specsgraph block with a volume.
x-specsgraph: &specsgraph
# ...other shared settings stay as they are
volumes:
- ./secrets/github-app.pem:/run/secrets/github-app.pem:roDocker mounts a single file by its identity on disk. When you replace the key, run docker compose up -d --force-recreate so every container sees the new file.
Changing the secret key
SPECSGRAPH_SECRET_KEY signs sessions and hashes access tokens. If you change it, everyone is signed out and existing personal access tokens stop working, so agents need new ones. Change it only when you suspect it leaked, and tell your team first.
MCP URL for agents
By default the MCP server answers at /mcp under SPECSGRAPH_PUBLIC_URL. For https://specsgraph.example.com, agents connect to https://specsgraph.example.com/mcp. This is the URL the agent setup guides call your server's MCP URL; their examples use the same example install.
Set SPECSGRAPH_MCP_PUBLIC_URL only when you serve MCP from a different host or path, for example a separate subdomain. Agents then connect to that URL instead.
Behind another reverse proxy
MCP over streamable HTTP keeps some responses open while the server streams results. Whatever proxy sits in front of the MCP server must pass responses through without buffering and allow long reads. In nginx, that looks like this:
location /mcp {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 1h;
}A proxy on the host needs the service ports published on the loopback interface. Remove the caddy service from the compose file and add an override:
services:
web:
ports:
- "127.0.0.1:3000:3000"
api:
ports:
- "127.0.0.1:8080:8080"
mcp:
ports:
- "127.0.0.1:8090:8090"With SMTP_URL set, SpecsGraph sends invitations and review notifications by email. Without it, the install sends no mail, and you share invitation links by hand as described in Members and roles.
Logging
Each service writes its logs to standard output, so docker compose logs shows them and any Docker logging driver can ship them to your log system. LOG_LEVEL controls how much they say.
# Follow the last 100 lines of the API
docker compose logs -f --tail=100 api
# Turn on debug output while you investigate, then apply it
sed -i 's/^LOG_LEVEL=.*/LOG_LEVEL=debug/' .env
docker compose up -dDebug output is verbose. Set LOG_LEVEL back to info when you are done. The example compose file caps each SpecsGraph service at five log files of 10 MB with the json-file driver. Add the same logging block to caddy, postgres and redis to cap them too; without such a limit, Docker keeps logs until the disk is full.
Next steps
- Create your GitHub App: where the GitHub values come from.
- Personal access tokens: create tokens for agents on your install.
- Upgrades and backups: keep the install current and recoverable.