Skip to content
Arbinel

Egress quota

The egress quota limits how much each user or organization may download per month, such as packages, container images and Git LFS objects. Arbinel does not see the traffic itself. Your edge proxy counts the bytes, an aggregator reports them to Arbinel, and the proxy blocks owners that Arbinel lists as over their limit. Read Quotas first, because egress limits are ordinary quota rules.

  1. The edge proxy serves downloads and logs the bytes of each response, together with the owner the request belongs to.
  2. An aggregator, a job you run next to the proxy, sums the bytes per owner and posts them to POST /api/v1/admin/egress/usage.
  3. Arbinel adds them to a ledger with one row per owner and calendar month, in UTC. The egress:all subject reads that ledger.
  4. The proxy, or the aggregator for it, fetches GET /api/v1/admin/egress/over-quota regularly and denies downloads for the owners it lists.

Arbinel never refuses a request because of egress. Pushes, uploads and the web interface keep working for an owner over their egress limit. The proxy decides which requests count and which are denied. Arbinel only decides which owners are over their limit.

Both endpoints are under the admin API, so the aggregator needs an access token of a site administrator with the admin scope.

Write egress limits as rules on the egress:all subject, in bytes.

curl -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
  https://forge.example.com/api/v1/admin/quota/groups \
  -d '{"name": "egress-free", "rules": [{"name": "egress-free", "limit": 10737418240, "subjects": ["egress:all"]}]}'
  • egress:all has a unit of its own. A rule cannot mix it with size: or time: subjects, and a group with only egress rules does not affect storage or CI time.
  • There is no instance-wide fallback. An owner whose groups have no egress:all rule has no egress limit.
  • Across groups, the most generous rule wins, as for every quota. To exempt one owner, add them to a group with an egress:all rule of -1 next to their other groups.
  • An owner exactly at their limit is within it.
  • Usage resets when a new UTC month starts.

The metered bandwidth add-on raises an owner’s egress:all rules by the traffic their monthly cap buys.

POST /api/v1/admin/egress/usage
Content-Type: application/json

{
  "run_id": "node-a-2026-11-11T10:00Z",
  "period": "2026-11",
  "deltas": [
    {"owner": "alice", "bytes": 52428800},
    {"owner": "acme", "bytes": 1073741824}
  ]
}
Field Meaning
run_id Identifies this aggregation run, 1 to 64 characters.
period The calendar month the bytes belong to, YYYY-MM, in UTC. Arbinel reads the current UTC month, so bytes filed under another month by a clock in another zone are never shown.
deltas[].owner User or organization name, matched without regard to case.
deltas[].bytes Bytes served since the previous run. Must not be negative.

Arbinel answers 204 on success.

  • The report is applied whole or not at all. A malformed field refuses it with 422 and nothing is written.
  • Posting the same run_id and period again changes nothing. The aggregator can retry a report until it gets 204, and only then move on to the next run. Arbinel remembers applied runs for 30 days.
  • A delta with an empty, unknown or deleted owner is dropped, because there is nobody to charge.
  • Several aggregators, for example one per node, can post independently, as long as their run IDs differ.
GET /api/v1/admin/egress/over-quota
{"period": "2026-11", "owners": ["alice", "acme"]}

owners holds lower-case names of every owner whose usage this month is above an egress:all rule that applies to them, add-ons and grants included. The owner’s Storage overview page uses the same calculation, so the proxy blocks the same owners that the page shows as over their limit.

  • Rebuild the deny list from this response on a schedule, for example hourly. Do not compute it in the proxy, or the proxy and the owner’s settings page can disagree.
  • While [quota] ENABLED is false, the list is always empty, so turning quota off lifts every block.
  • An owner can exceed their limit by the amount they download between two fetches of the list.
[quota.egress]
RETENTION_PERIODS = 24
Key Default Meaning
RETENTION_PERIODS 24 How many months of egress usage to keep, counting the current one. Values below 1 read as 1.

The cleanup_quota_egress_usage cron task runs every night. It deletes older months, and forgets applied run IDs older than 30 days.

Site administration → Download traffic at /admin/egress lists the 100 owners with the most download traffic in the current month. Use it to spot unusual traffic, since it shows all owners, not only those with a limit.