Configuration
Every app.ini setting that Arbinel adds, and every Forgejo setting whose default or behaviour Arbinel changes.
All other settings are Forgejo’s, and Forgejo’s configuration cheat sheet documents them.
The defaults below are the values the code uses when a key is absent.
Some keys only take effect together with another one. The Needs column names it.
Several sections still carry the fork’s former name, such as [codefloe.ratelimit.<name>].
Write them as shown: the names are part of the configuration format.
Quotas
Section titled “Quotas”[quota.ci]
Section titled “[quota.ci]”CI time accounting on platform runners. See CI quota.
| Key | Default | Needs | Description |
|---|---|---|---|
ENABLED |
false |
[quota] ENABLED |
Record CI time and enforce the time: quota rules. |
PLATFORM_RUNNERS |
empty | Billed Forgejo Actions runners, by scope and name: instance:<name>, repo:<repository-id>:<name> or owner:<owner-id>:<name>. |
|
PLATFORM_RUNNER_IDS |
empty | Billed Forgejo Actions runners, by database ID. Re-registering a runner changes its ID. | |
RECORD_RETENTION_PERIODS |
12 |
Monthly periods of individual run records to keep. Monthly totals are never dropped. The minimum is 1. |
|
NOTIFY_THRESHOLDS |
80,100 |
[quota] ENABLED |
Percentages of a CI time limit at which the owner gets a mail. An empty value turns the mails off. |
When both runner lists are empty, no Actions runner is billed.
[quota.ci.default]
Section titled “[quota.ci.default]”| Key | Default | Needs | Description |
|---|---|---|---|
TOTAL |
-1 |
[quota.ci] ENABLED |
CI time limit for an owner whose quota groups have no time: rule, as a duration such as 600m. A negative value means unlimited. |
See CI quota.
[quota.ci.reporter.<name>]
Section titled “[quota.ci.reporter.<name>]”One section per external CI system that reports the time it spent.
The section name becomes the source of its usage records.
It may contain lower-case letters, digits, - and _, may not start with - or _, is at most 40 characters long, and may not be actions.
See CI quota.
| Key | Default | Needs | Description |
|---|---|---|---|
TOKEN_HASH |
none, required | [quota.ci] ENABLED |
Hex-encoded SHA-256 of the reporter’s token. |
DISPLAY_NAME |
the section name | Label shown in usage breakdowns. | |
PLATFORM_RUNNER_IDS |
empty | The reporter’s own IDs of its billed agents, comma-separated. |
Arbinel ignores a section with an invalid name or TOKEN_HASH, or one that repeats another reporter’s TOKEN_HASH, and logs an error.
[quota.storage]
Section titled “[quota.storage]”Mails that warn owners their storage quota is filling up. See Quotas.
| Key | Default | Needs | Description |
|---|---|---|---|
NOTIFY_THRESHOLDS |
80,100 |
[quota] ENABLED |
Percentages of a storage limit at which the owner gets a mail. An empty value turns the mails off. |
NOTIFY_HYSTERESIS |
5 |
Percentage points usage must fall below a threshold before that mail can be sent again, from 0 to 99. |
[quota.egress]
Section titled “[quota.egress]”The ledger of download traffic per owner and month. See Egress quota.
| Key | Default | Needs | Description |
|---|---|---|---|
RETENTION_PERIODS |
24 |
Monthly periods of traffic records to keep, counting the current one. The minimum is 1. |
[quota.grants]
Section titled “[quota.grants]”Extra quota that integrations add for an owner. See Quota grants.
| Key | Default | Needs | Description |
|---|---|---|---|
ENABLED |
false |
[quota] ENABLED, an [integration.<name>] with the quota.grants scope |
Apply stored grants and serve the grant API. |
[integration.<name>]
Section titled “[integration.<name>]”One section per external system that uses the integration API at /api/v1/integrations.
The section name follows the same rules as a CI reporter’s name.
See Quota grants.
| Key | Default | Needs | Description |
|---|---|---|---|
TOKEN_HASH |
none, required | Hex-encoded SHA-256 of the integration’s token. | |
SCOPES |
empty | What the integration may do, comma-separated. The only scope is quota.grants. |
Arbinel ignores a section with an invalid name or TOKEN_HASH, or one that repeats another integration’s TOKEN_HASH, and logs an error.
It drops scopes it does not know.
Billing
Section titled “Billing”See Billing.
[billing]
Section titled “[billing]”| Key | Default | Needs | Description |
|---|---|---|---|
ENABLED |
false |
[quota] ENABLED, [billing.creem] keys, at least one product |
Sell add-ons. A product with time: subjects also needs [quota.ci] ENABLED. |
[billing.creem]
Section titled “[billing.creem]”| Key | Default | Needs | Description |
|---|---|---|---|
TEST_MODE |
true |
Send every request to Creem’s test environment. | |
API_KEY |
empty | Creem API key. Required when [billing] ENABLED is true. |
|
WEBHOOK_SECRET |
empty | Secret of the Creem webhook for <ROOT_URL>/-/billing/creem/webhook. Required when [billing] ENABLED is true. |
[billing.product.<key>]
Section titled “[billing.product.<key>]”One section per add-on.
The key may contain lower-case letters, digits, - and _, and must start with a letter or digit.
The database stores the key, so a product can move to another Creem product without a migration.
| Key | Default | Description |
|---|---|---|
CREEM_PRODUCT_ID |
none, required | The Creem product. Two sections cannot use the same one. |
NAME |
the key | Name shown to customers. |
TYPE |
fixed |
fixed for add-ons sold in units, or metered for usage-based bandwidth. At most one product can be metered. |
SUBJECTS |
none, required for fixed |
Quota subjects each unit raises, comma-separated. All time: subjects or all size subjects. |
AMOUNT |
none, required for fixed |
What one unit adds: a duration such as 1000m for time subjects, a size such as 10GiB for size subjects. |
MAX_UNITS |
20 |
The most units an owner can buy. Only for fixed. |
A metered product takes these keys instead of AMOUNT and MAX_UNITS:
| Key | Default | Description |
|---|---|---|
SUBJECTS |
egress:all |
Must be egress:all. |
EVENT_NAME |
none, required | Event name of the Creem meter. |
PRICE_PER_GIB |
none, required | Price per GiB in cents, excluding VAT. |
DEFAULT_CAP |
1000 |
Default monthly cap in cents, excluding VAT. |
MAX_CAP |
100000 |
Highest monthly cap an owner can set, in cents, excluding VAT. |
MIN_CHARGE |
500 |
Usage in cents that builds up before Arbinel reports it to Creem. |
Arbinel checks product sections even while billing is off, and refuses to start when one is invalid.
Request budgets
Section titled “Request budgets”[codefloe.ratelimit.<name>]
Section titled “[codefloe.ratelimit.<name>]”One section per policy.
Arbinel uses four policy names: archive, code-search, compare-diff and issue-filters.
See Request budgets.
| Key | Default | Description |
|---|---|---|
ENABLED |
false |
Enforce the policy. |
OBSERVE_ONLY |
false |
Count requests without refusing any. |
AUTHENTICATED_REQUESTS |
60 |
Requests per account and window, from 1. |
ANONYMOUS_REQUESTS |
0 |
Requests per IP address and window for signed-out visitors. 0 sets no limit. |
WINDOW_SECONDS |
60 |
Length of the window, from 1 to 31536000. |
EXEMPT_ACCOUNTS |
empty | Account names the policy does not limit, comma-separated. Site administrators are always exempt. |
Arbinel refuses to start when a value is out of range or not a number.
Counters shared between nodes need a Redis-compatible [cache].
Operations
Section titled “Operations”[high_availability]
Section titled “[high_availability]”Several nodes behind a load balancer. See High availability.
| Key | Default | Description |
|---|---|---|
ENABLED |
false |
Run as one node of a cluster. Arbinel refuses to start unless the cache, sessions, queues, storage and indexers are shared or node-safe. |
NODE_ID |
<hostname>-<pid>-<random> |
Name of this node. |
LEASE_TTL |
30s |
How long the leader’s lease stays valid without renewal. |
RENEW_INTERVAL |
10s |
How often the leader renews its lease. If it is not below half of LEASE_TTL, Arbinel uses a third of LEASE_TTL. |
[realtime]
Section titled “[realtime]”Live updates on issue and pull request pages. See Live updates.
| Key | Default | Needs | Description |
|---|---|---|---|
ENABLED |
false |
Push updates to open pages. | |
CONN_STR |
empty | Redis connection string that carries events between nodes. Empty means one node, in memory. With [high_availability] ENABLED and [queue] TYPE = redis, it defaults to the queue’s CONN_STR. |
|
MAX_CONNECTIONS |
10000 |
Most open live connections per node. | |
HEARTBEAT_INTERVAL |
25s |
Interval of keep-alive messages. Values below 1s fall back to 25s. |
[ci_cancel.<name>]
Section titled “[ci_cancel.<name>]”One section per external CI system whose checks users can cancel from a pull request. The section name follows the same rules as a CI reporter’s name. See Cancel checks.
| Key | Default | Description |
|---|---|---|
TARGET_URL |
none, required | Prefix of the target URL of the checks this system reports. An http or https URL. |
URL |
none, required | Endpoint that receives cancel requests. An http or https URL. |
SECRET |
none, required | Secret that signs the requests, at least 16 characters. |
SECRET_URI |
none | A file: URI to read SECRET from, instead of SECRET. |
TIMEOUT |
10s |
Time limit of one request. |
Arbinel ignores a section with a missing or invalid value, and logs an error. Cancelling Forgejo Actions runs needs no section.
Keys Arbinel adds to Forgejo sections
Section titled “Keys Arbinel adds to Forgejo sections”| Section | Key | Default | Description | See |
|---|---|---|---|---|
[database] |
CONNECT_TIMEOUT |
10s |
Connection timeout for PostgreSQL, passed as connect_timeout in seconds. 0 leaves it out, and a connect_timeout in NAME wins. |
Database |
[indexer] |
ISSUE_INDEXER_TYPE |
bleve |
Also accepts typesense, with ISSUE_INDEXER_CONN_STR such as http://apikey@localhost:8108 and ISSUE_INDEXER_NAME. |
Search |
[ui] |
FILE_ICON_SET |
devicon |
Default icon set of the file list: basic, material or devicon. Users can choose their own. |
Appearance |
[picture] |
PLACEHOLDER_AVATAR |
identicon |
Generated avatar for accounts and repositories without one: identicon or monogram. |
Appearance |
[service] |
DEFAULT_WATCH_EVENTS |
7 |
Events a newly watched repository notifies about, as a sum: 1 issues, 2 pull requests, 4 releases, 8 only where the user takes part. Users can set their own default. |
Notifications |
[repository.pull-request] |
DEFAULT_ALLOWED_MERGE_STYLES |
all | Merge styles new repositories allow, comma-separated: merge, rebase, rebase-merge, squash, fast-forward-only, manually-merged. Unknown entries are dropped, and an empty result allows all. |
|
[repository.pull-request] |
DEFAULT_DELETE_BRANCH_AFTER_MERGE |
false |
Default of “Delete pull request branch after merge” in new repositories. | |
[repository.pull-request] |
DEFAULT_ALLOW_MAINTAINER_EDIT |
false |
Default of “Allow edits from maintainers” in new repositories. |
The three [repository.pull-request] keys apply only to repositories created after you set them.
After you change PLACEHOLDER_AVATAR, run forgejo doctor check --run regenerate-avatars --fix, because Arbinel caches generated avatars.
Forgejo keys with a different default or behaviour
Section titled “Forgejo keys with a different default or behaviour”| Section | Key | Forgejo | Arbinel | See |
|---|---|---|---|---|
[ui] |
DEFAULT_THEME |
forgejo-auto |
codefloe-tide-auto |
Appearance |
[ui] |
THEMES |
Forgejo’s themes | Forgejo’s themes, after the codefloe-*, codefloe-tide-* and codefloe-tide-ice-* themes in auto, light and dark |
Appearance |
[repository.issue] |
MAX_PINNED |
3 |
6 |
|
[database] |
HOST_REPLICA |
One connection per replica host | With PostgreSQL, all replica hosts in one multi-host connection, which skips a host that does not answer | Database |
[repository.signing] |
SIGNING_EMAIL |
Commits signed with the instance SSH key show a placeholder | Those commits link to the account that owns this address | Commit signing |
Settings outside app.ini
Section titled “Settings outside app.ini”The site administration stores these settings in the database, not in app.ini:
- Pages, described in Pages.
- Global announcements, described in Announcements.
Cron tasks
Section titled “Cron tasks”Arbinel adds these tasks.
Configure them in [cron.<task>] sections with Forgejo’s keys, such as ENABLED and SCHEDULE, as Forgejo’s cron settings describe.
With [high_availability] ENABLED, only the leader runs scheduled tasks.
| Task | Schedule | Registered when | Purpose |
|---|---|---|---|
cleanup_quota_ci_records |
@midnight |
[quota.ci] ENABLED |
Drop CI run records older than RECORD_RETENTION_PERIODS. |
quota_storage_notify |
@midnight |
always | Send storage quota mails. |
cleanup_quota_egress_usage |
@midnight |
always | Drop traffic records older than RETENTION_PERIODS. |
pages_teardown_sweep |
@every 10m |
always | Unpublish Pages sites whose repository was deleted, and retry failed removals. |
requeue_undelivered_hook_tasks |
@every 5m |
always, enabled with [high_availability] ENABLED |
Put undelivered webhook deliveries back on the queue, so a delivery the shared queue lost still goes out. |
billing_reconcile |
@midnight |
[billing] ENABLED |
Bring add-ons in line with Creem, in case a webhook got lost. |
billing_report_usage |
@every 1h |
[billing] ENABLED and a metered product |
Report metered bandwidth to Creem. |