Configuration
ermite serve reads its settings from the environment.
Required
| Variable |
Notes |
ERMITE_DATA_DIR |
absolute path of the data root |
ERMITE_PUBLIC_URL |
http(s) base URL, no path |
ERMITE_ADMIN_TOKEN |
at least 32 characters; the root credential |
export ERMITE_DATA_DIR=/var/lib/ermite
export ERMITE_PUBLIC_URL=https://git.example.com
export ERMITE_ADMIN_TOKEN=$(head -c 32 /dev/urandom | base64)
ermite serve
Server
| Variable |
Default |
Notes |
ERMITE_ADDR |
:7341 |
listen address |
ERMITE_TRUSTED_PROXIES |
empty |
comma-separated CIDRs of your TLS proxy, so login rate limits see the real client (X-Forwarded-For) |
ERMITE_OWNER |
owner |
owner login: web header, passkey name, and <owner> in CI (github.repository). Same rules as repository names |
ERMITE_SOURCE_URL |
$ERMITE_PUBLIC_URL/ermite |
link to the source (AGPL) |
ERMITE_VIDEO_HOSTS |
github.com,user-images.githubusercontent.com,private-user-images.githubusercontent.com,github-production-user-asset-6210df.s3.amazonaws.com |
comma-separated exact external video hostnames, replacing the defaults; no URLs, wildcards or ports. The S3 host receives GitHub user-attachment redirects. |
ERMITE_LOG_LEVEL |
info |
trace, debug, info, warn, error |
ERMITE_LOG_FORMAT |
json |
json or console |
Git
| Variable |
Default |
Notes |
ERMITE_GIT |
git |
git 2.45 or newer |
ERMITE_GIT_READER |
ermite-git |
ermite-git reads with the ermite-git library where it is faster, and falls back to git. cli uses git for every read: set it and restart if a read looks wrong |
ERMITE_COMMITTER_NAME |
ermite |
committer of squash and merge commits |
ERMITE_COMMITTER_EMAIL |
ermite@<public host> |
committer email of squash and merge commits |
CI
| Variable |
Default |
Notes |
ERMITE_SECRETS_KEY |
empty |
32 random bytes in base64. Encrypts CI secrets and the OIDC key. See below |
ERMITE_CI_LOG_RETENTION |
90d |
how long runs, jobs, checks and logs are kept. Nd or a Go duration (720h), at least 1h |
ERMITE_CI_POLL_TIMEOUT |
50s |
how long a runner's FetchJob call is held when no job is queued, 1s to 55s. Keep it below your proxy's response timeout (25s behind a proxy that cuts at 30 s) |
ERMITE_CI_ARTIFACTS |
1 |
0 turns artifacts off |
ERMITE_CI_ARTIFACT_RETENTION |
90d |
default and maximum retention-days, at least one day |
ERMITE_CI_ARTIFACT_QUOTA |
10GiB |
artifact space per repository, uploads in progress included. Bytes or KiB, MiB, GiB, TiB |
ERMITE_CI_ARTIFACT_MAX |
5GiB |
size of one artifact |
ERMITE_SECRETS_KEY
head -c 32 /dev/urandom | base64
- Store it like the admin token.
- Without it,
ermite secret set fails, jobs get no secrets and OIDC is off. Variables and environments still work.
- The server refuses to start with a different key than the one the secrets were sealed with.
- Losing the key loses every secret. A backup without the key reveals none.
Blob storage and releases
| Variable |
Default |
Notes |
ERMITE_S3_BUCKET |
empty |
selects S3 when nonempty; otherwise disk under $ERMITE_DATA_DIR/blobs |
ERMITE_S3_ENDPOINT |
empty |
http(s) endpoint; empty uses AWS region resolution; no credentials, path, query or fragment |
ERMITE_S3_REGION |
empty |
required with a bucket, including custom endpoints |
ERMITE_S3_ACCESS_KEY_ID |
empty |
explicit key, required with a bucket |
ERMITE_S3_SECRET_ACCESS_KEY |
empty |
explicit secret, required with a bucket |
ERMITE_S3_FORCE_PATH_STYLE |
0 |
0/1 or false/true; 1 for MinIO without wildcard DNS |
ERMITE_S3_PREFIX |
empty |
ASCII key prefix, normalized to a trailing /; no empty, . or .. segments |
ERMITE_RELEASE_ASSET_MAX |
2GiB |
one release asset |
ERMITE_RELEASE_ASSETS_MAX |
1000 |
positive integer, per release |
ERMITE_RELEASE_QUOTA |
20GiB |
per repository, including uploads in progress |
Sizes accept bytes or KiB, MiB, GiB, TiB, from 1 MiB to 1 PiB.
See storage for AWS, Scaleway, R2, MinIO, permissions and backups,
and releases for publishing.
Secret files
ERMITE_ADMIN_TOKEN, ERMITE_SECRETS_KEY, ERMITE_S3_ACCESS_KEY_ID and
ERMITE_S3_SECRET_ACCESS_KEY each support a _FILE variant, for example
ERMITE_ADMIN_TOKEN_FILE=/run/secrets/admin-token. Set either the direct value
or its file, never both. Files are read once at startup; trailing CR/LF is
removed. Empty or unreadable files fail validation. Secret contents and file
paths are not included in file-resolution errors. No AWS credential chain is used.
Runtime files
The hook socket and scripts git calls on each push live in $ERMITE_DATA_DIR/run/. The socket path must stay under about 100 bytes, so keep ERMITE_DATA_DIR short.
Storage schema
This build uses storage schema 6. Once it has run on your data, an older ermite refuses to start. To downgrade, restore the backup taken before the upgrade.
Trusted Markdown renders video images (, also .webm, .mov,
.m4v and .ogv) as native players. Repository-relative destinations use the raw
route of the viewed ref; external HTTP(S) destinations require an
ERMITE_VIDEO_HOSTS host. A standalone link or autolink to an allowed host
renders as a player only when its path has a supported video extension or is an
extensionless GitHub github.com/user-attachments/assets/<id> URL. Repository,
issue and other ordinary URLs stay links.
Other images show their alt text; other links keep the existing link policy.
Raw HTML stays disabled. Untrusted public issue Markdown never loads videos.
Raw video types are detected by bytes, not extensions. Seeking supports single
byte ranges; it streams and discards the preceding bytes, so small clips work
best. Multipart ranges are ignored.
source
1# Configuration
2
3`ermite serve` reads its settings from the environment.
4
5## Required
6
7| Variable | Notes |
8|---|---|
9| `ERMITE_DATA_DIR` | absolute path of the data root |
10| `ERMITE_PUBLIC_URL` | `http(s)` base URL, no path |
11| `ERMITE_ADMIN_TOKEN` | at least 32 characters; the root credential |
12
13```sh
14export ERMITE_DATA_DIR=/var/lib/ermite
15export ERMITE_PUBLIC_URL=https://git.example.com
16export ERMITE_ADMIN_TOKEN=$(head -c 32 /dev/urandom | base64)
17ermite serve
18```
19
20## Server
21
22| Variable | Default | Notes |
23|---|---|---|
24| `ERMITE_ADDR` | `:7341` | listen address |
25| `ERMITE_TRUSTED_PROXIES` | empty | comma-separated CIDRs of your TLS proxy, so login rate limits see the real client (`X-Forwarded-For`) |
26| `ERMITE_OWNER` | `owner` | owner login: web header, passkey name, and `<owner>` in CI (`github.repository`). Same rules as repository names |
27| `ERMITE_SOURCE_URL` | `$ERMITE_PUBLIC_URL/ermite` | link to the source (AGPL) |
28| `ERMITE_VIDEO_HOSTS` | `github.com,user-images.githubusercontent.com,private-user-images.githubusercontent.com,github-production-user-asset-6210df.s3.amazonaws.com` | comma-separated exact external video hostnames, replacing the defaults; no URLs, wildcards or ports. The S3 host receives GitHub user-attachment redirects. |
29| `ERMITE_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` |
30| `ERMITE_LOG_FORMAT` | `json` | `json` or `console` |
31
32## Git
33
34| Variable | Default | Notes |
35|---|---|---|
36| `ERMITE_GIT` | `git` | git 2.45 or newer |
37| `ERMITE_GIT_READER` | `ermite-git` | `ermite-git` reads with the [ermite-git](https://github.com/bnema/ermite-git) library where it is faster, and falls back to `git`. `cli` uses `git` for every read: set it and restart if a read looks wrong |
38| `ERMITE_COMMITTER_NAME` | `ermite` | committer of squash and merge commits |
39| `ERMITE_COMMITTER_EMAIL` | `ermite@<public host>` | committer email of squash and merge commits |
40
41## CI
42
43| Variable | Default | Notes |
44|---|---|---|
45| `ERMITE_SECRETS_KEY` | empty | 32 random bytes in base64. Encrypts CI secrets and the OIDC key. See below |
46| `ERMITE_CI_LOG_RETENTION` | `90d` | how long runs, jobs, checks and logs are kept. `Nd` or a Go duration (`720h`), at least `1h` |
47| `ERMITE_CI_POLL_TIMEOUT` | `50s` | how long a runner's `FetchJob` call is held when no job is queued, `1s` to `55s`. Keep it below your proxy's response timeout (`25s` behind a proxy that cuts at 30 s) |
48| `ERMITE_CI_ARTIFACTS` | `1` | `0` turns artifacts off |
49| `ERMITE_CI_ARTIFACT_RETENTION` | `90d` | default and maximum `retention-days`, at least one day |
50| `ERMITE_CI_ARTIFACT_QUOTA` | `10GiB` | artifact space per repository, uploads in progress included. Bytes or `KiB`, `MiB`, `GiB`, `TiB` |
51| `ERMITE_CI_ARTIFACT_MAX` | `5GiB` | size of one artifact |
52
53### `ERMITE_SECRETS_KEY`
54
55```sh
56head -c 32 /dev/urandom | base64
57```
58
59- Store it like the admin token.
60- Without it, `ermite secret set` fails, jobs get no secrets and OIDC is off. Variables and environments still work.
61- The server refuses to start with a different key than the one the secrets were sealed with.
62- Losing the key loses every secret. A backup without the key reveals none.
63
64## Blob storage and releases
65
66| Variable | Default | Notes |
67|---|---|---|
68| `ERMITE_S3_BUCKET` | empty | selects S3 when nonempty; otherwise disk under `$ERMITE_DATA_DIR/blobs` |
69| `ERMITE_S3_ENDPOINT` | empty | http(s) endpoint; empty uses AWS region resolution; no credentials, path, query or fragment |
70| `ERMITE_S3_REGION` | empty | required with a bucket, including custom endpoints |
71| `ERMITE_S3_ACCESS_KEY_ID` | empty | explicit key, required with a bucket |
72| `ERMITE_S3_SECRET_ACCESS_KEY` | empty | explicit secret, required with a bucket |
73| `ERMITE_S3_FORCE_PATH_STYLE` | `0` | `0`/`1` or `false`/`true`; `1` for MinIO without wildcard DNS |
74| `ERMITE_S3_PREFIX` | empty | ASCII key prefix, normalized to a trailing `/`; no empty, `.` or `..` segments |
75| `ERMITE_RELEASE_ASSET_MAX` | `2GiB` | one release asset |
76| `ERMITE_RELEASE_ASSETS_MAX` | `1000` | positive integer, per release |
77| `ERMITE_RELEASE_QUOTA` | `20GiB` | per repository, including uploads in progress |
78
79Sizes accept bytes or `KiB`, `MiB`, `GiB`, `TiB`, from 1 MiB to 1 PiB.
80See [storage](storage.md) for AWS, Scaleway, R2, MinIO, permissions and backups,
81and [releases](releases.md) for publishing.
82
83### Secret files
84
85`ERMITE_ADMIN_TOKEN`, `ERMITE_SECRETS_KEY`, `ERMITE_S3_ACCESS_KEY_ID` and
86`ERMITE_S3_SECRET_ACCESS_KEY` each support a `_FILE` variant, for example
87`ERMITE_ADMIN_TOKEN_FILE=/run/secrets/admin-token`. Set either the direct value
88or its file, never both. Files are read once at startup; trailing CR/LF is
89removed. Empty or unreadable files fail validation. Secret contents and file
90paths are not included in file-resolution errors. No AWS credential chain is used.
91
92## Runtime files
93
94The hook socket and scripts git calls on each push live in `$ERMITE_DATA_DIR/run/`. The socket path must stay under about 100 bytes, so keep `ERMITE_DATA_DIR` short.
95
96## Storage schema
97
98This build uses storage schema 6. Once it has run on your data, an older ermite refuses to start. To downgrade, restore the backup taken before the upgrade.
99
100## README media
101
102Trusted Markdown renders video images (``, also `.webm`, `.mov`,
103`.m4v` and `.ogv`) as native players. Repository-relative destinations use the raw
104route of the viewed ref; external HTTP(S) destinations require an
105`ERMITE_VIDEO_HOSTS` host. A standalone link or autolink to an allowed host
106renders as a player only when its path has a supported video extension or is an
107extensionless GitHub `github.com/user-attachments/assets/<id>` URL. Repository,
108issue and other ordinary URLs stay links.
109Other images show their alt text; other links keep the existing link policy.
110Raw HTML stays disabled. Untrusted public issue Markdown never loads videos.
111Raw video types are detected by bytes, not extensions. Seeking supports single
112byte ranges; it streams and discards the preceding bytes, so small clips work
113best. Multipart ranges are ignored.