Running it yourself
What GAdvisory needs from a host, what it never needs, and what you are taking on by running it. Written so you can decide before you install rather than after.
Four processes and a data plane
GAdvisory is an API, a web tier, a worker and a one-shot migration step. They share one Postgres database, one Redis, a Meilisearch index and an object store. Everything else is optional and off by default.
The primary deployment target is a single Linux host running the processes under systemd, with TLS terminating on a reverse proxy you already own. There is a container path as well. Neither is exotic: if you can run a Node application and a Postgres database, you can run this.
What has to be there
| Component | Needed for |
|---|---|
| PostgreSQL 16 | Every record. The only durable store; nothing important lives anywhere else. |
| Redis 7 | Live editing across processes, a lock for the git mirror, and health. |
| Meilisearch | Search. The index is derived, so losing it costs a rebuild rather than data. |
| S3-compatible storage | Attachments and avatars. MinIO on the same host is a supported answer. |
| Temporal | Durable execution for everything asynchronous, including the audit trail's own fan-out. |
| An identity provider | Sign-in. Self-hosted, and it stays inside your perimeter like everything else. |
| Node 22 LTS | The runtime for all four processes. |
Optional, and genuinely optional rather than optional-until-something-breaks: an SMTP server for outbound mail, an IMAP mailbox for report intake, HashiCorp Vault if you would rather secrets never reached the database at all, ClamAV if you want uploads scanned, and Sentry if you want the telemetry.
Where the keys live
Credentials for upstream registries, webhook signing secrets and mail passwords are encrypted at rest under a key you supply and this project never sees. You can hold that key as a file, as an environment value, or derive it from a passphrase.
If you run Vault, each of those secrets can live there instead and never be written to the database in any form, with the encryption key itself held by Vault's transit engine. That is the stronger arrangement, and it is a per-secret choice rather than an all-or-nothing switch.
Getting your data out is not an export button
Advisories, requests, comments and the audit log mirror continuously into git repositories you control, as canonical JSON with one file per record. It is a live mirror rather than a backup job: a commit lands when a record changes, attributed to the person who changed it.
The point is that the record outlives the application. If you stop running GAdvisory tomorrow, what you are left with is a git history of every advisory you ever published, in a format that is readable without us.
Migrations apply before the restart
An upgrade applies database migrations and then restarts the processes, in that order. That ordering is deliberate and it is why schema changes here are always additive first: for the length of the deploy, the previous build is running against the new schema, so a column dropped in the same release as the code that stopped reading it takes the running instance down.
You do not have to think about that to operate it. It is stated because it is the reason upgrades are boring, and boring is the property you want from the thing holding your disclosure record.
Before you install
The deployment guide in the repository is the step-by-step. This page is what to know before you get there.