Settings reference
Every field on the two settings documents, what it controls, and what it reads
on a running host.
Who this is for. Whoever changes how benches are built and placed.
Before you start. Read the values here as measured, not as documented.
Every number below was read off a live site with the command in
How these values were read. A defaults table
copied out of a JSON file is wrong the first time somebody edits one in Desk.
The two documents, and the two places they are edited
BenchPress has two settings Singles. Neither is fully exposed in the app.
| Document | Holds | Edited in |
|---|---|---|
BenchPress Settings |
Docker, addressing, the bench network, container defaults, health probes, reconciliation, and the credits master switch | the app's Settings dialog (10 fields) and Desk (all 26) |
Credit Settings |
grants, charges, leases, caps, and self-serve signup | Desk only |
The app's Settings dialog is deliberately a subset — the ten fields an
operator changes while setting a host up. Everything else is a Desk form at
/app/benchpress-settings and /app/credit-settings.
[Screenshot to be added — docs/images/operator/settings-reference/01-settings-network.png: The BenchPress settings dialog, Bench network panel, showing Subnet base 10.20, Bridge count 16 and Slots per bridge 1000, each with a one-line explanation underneath.]
The dialog groups its ten fields into four panels — Domains, Docker, Bench
network and Container defaults — and prints who saved last and when at the
bottom. The Bench network panel above holds bench_subnet_base 10.20,
bench_bridge_count 16 and bench_slots_per_bridge 1000.
Steps
- Open
/app/benchpress-settingsin Desk for the full form, or Settings
in the app's account menu for the ten common fields. - Change one field.
- Save.
- Read What a change costs — some fields apply to the
next deploy, and some apply immediately to running benches.
Verify
Read the value back from the server rather than from the form you just saved.
A cached Single is the usual reason a change looks like it did not take.
bench --site <site> execute frappe.client.get_value \
--kwargs "{'doctype':'BenchPress Settings','fieldname':'bench_bridge_count'}"
BenchPress Settings
Docker configuration
| Field | On this host | Ships as | What it does |
|---|---|---|---|
docker_socket |
unix:///var/run/docker.sock |
same | Where BenchPress reaches the daemon |
default_image |
frappe/bench:latest |
same | The image a lab with no image of its own falls back to |
default_bench_runtime |
sysbox |
same | The container runtime for a new bench. sysbox gives the bench its own kernel view, so a lab user holds root inside it without holding root on the host |
enable_golden_images |
1 |
same | Whether a build bakes the finished site's database into the lab image |
restore_from_golden |
1 |
same | Whether a deploy restores that dump instead of creating the site through the ORM |
base_domain |
benchpress.cloud |
(none — required) | Sites resolve as <site>.<base domain>. The one field with no default, because no default could be right |
traefik_network |
traefik-public |
same | The Docker network bench containers join so the router can reach them |
The bench network
Bridge i is <subnet base>.<i × 16>.0/20. Bridges are created as they are
needed, not up front.
| Field | On this host | Ships as | What it does |
|---|---|---|---|
bench_subnet_base |
10.20 |
same | The first two octets of the bridge family |
bench_bridge_count |
16 |
same | The most bridges the family may grow to |
bench_slots_per_bridge |
1000 |
same | Benches a bridge takes before the next is preferred. A Linux bridge caps at 1024 ports, so 1000 leaves headroom |
On this host that arithmetic gives 15,985 free bench slots across three
created bridges — the number Diagnostics reports
as bridge_capacity.
Health probes
These configure the Docker healthcheck written into each bench container.
| Field | On this host | Ships as | What it does |
|---|---|---|---|
enable_bench_healthcheck |
1 |
same | Whether a bench container carries a healthcheck at all |
bench_health_interval_seconds |
30 |
same | Seconds between probes |
bench_health_timeout_seconds |
5 |
same | Seconds a probe may take before it counts as failed |
bench_health_retries |
3 |
same | Consecutive failures before the verdict turns unhealthy |
bench_health_start_period_seconds |
600 |
same | Grace after start. Failures inside it do not count against the retries |
traefik_health_interval_seconds |
10 |
same | Seconds between router health probes |
traefik_health_timeout_seconds |
3 |
same | Seconds a router probe may take |
Ten minutes of start period is not caution. A first deploy runs migrations
inside the container, and a shorter grace marks a healthy bench unhealthy
while it is still working.
Container defaults
Applied to a new lab unless the lab overrides them.
| Field | On this host | Ships as | What it does |
|---|---|---|---|
container_memory_limit |
512m |
same | Memory ceiling for a bench container |
container_cpu_quota |
100000 |
same | CPU quota in microseconds. 100000 is one core |
code_server_version |
4.96.4 |
same | The browser VS Code build installed into a bench |
stop_grace_seconds |
5 |
same | Seconds a container gets to exit cleanly before it is killed |
Reconciliation and events
Three fields on this host read 0, and 0 does not mean zero. Each is read
as cint(value) or DEFAULT, so a stored 0 means "use the built-in", and the
built-in is the number in the Falls back to column.
| Field | On this host | Falls back to | What it does |
|---|---|---|---|
bench_event_settle_seconds |
0 |
15 |
Seconds the Docker event listener waits for a container to settle before acting on it |
orphan_grace_minutes |
0 |
15 |
Minutes a container with no matching row is left alone before reconciliation treats it as an orphan |
deploy_log_cap |
0 |
50 |
Deploy Log rows kept per bench |
stats_poll_max_benches |
50 |
(used as-is) | Benches one stats sweep will poll. The sweep spends about two seconds per container on the Docker socket |
That fallback pattern is worth knowing before you clear a field to "turn it
off". Clearing it restores the built-in instead.
Credits
| Field | On this host | Ships as | What it does |
|---|---|---|---|
enable_credits |
0 |
0 |
The master switch for the whole optional metering half. See Credits and billing |
Leave this at 0 unless you are running BenchPress for a team. With it
on, every deploy is charged against a balance and capped by concurrency, and
users who have no Credit Account are refused. Nothing on the self-hosted
path needs it.
Credit Settings
Every field here is inert while enable_credits is 0. Each function in the
credits package checks the switch before it does anything, so with credits off
there are no accounts, no ledger rows and no extra queries.
Grants and charges
| Field | On this host | Ships as | What it does |
|---|---|---|---|
signup_grant_credits |
40 |
40 |
Credits posted once, ever, when an account is opened |
custom_build_credits |
40 |
40 |
Flat charge for building a custom lab image |
low_balance_warn_percent |
20 |
20 |
Balance percentage below which the account is warned |
Instance lifecycle
| Field | On this host | Ships as | What it does |
|---|---|---|---|
reap_after_days |
7 |
7 |
Days a stopped instance is kept before it is torn down. The Lab survives — its apps, branches, version and size are intact, so a reaped instance is one action to rebuild |
An email goes out two days before the teardown, so nobody loses work to a rule
they had forgotten.
Leases
| Field | On this host | Falls back to | What it does |
|---|---|---|---|
default_lease_plan |
30 minutes |
(none) | The plan a deploy buys when the caller names none |
lease_sweep_batch |
200 |
200 |
Expired leases one sweep may claim. This caps the stop queue, not the query |
lease_reclaim_seconds |
60 |
300 |
Seconds before a claimed but unfinished stop is reclaimed by another sweep |
lease_max_attempts |
0 |
5 |
Failed stops before a lease parks. Docker being down must not re-queue a job for a week |
lease_reclaim_seconds reads 60 here against a shipped 300, and
lease_max_attempts reads 0, which falls back to 5. Both are examples of
why this table is measured rather than copied.
Free but capped
| Field | On this host | Ships as | What it does |
|---|---|---|---|
max_concurrent_free |
2 |
2 |
Instances at once for an account that has never purchased |
max_concurrent_paid |
5 |
5 |
Instances at once once the account has any Purchase ledger row |
max_concurrent_uncredited |
0 |
0 |
Instances at once while credits are off. 0 means unlimited |
max_devices |
5 |
5 |
VPN devices one account may register |
max_builds_per_day |
3 |
3 |
Custom image builds per lab owner per day |
max_size_free |
(empty) | (empty) | Largest Instance Size a never-purchased account may deploy at. Empty means no ceiling |
max_concurrent_uncredited is the field most often read backwards. It applies
only while enable_credits is 0, and 0 there means unlimited, not
zero. Turning credits on does not engage it — the cap becomes
max_concurrent_free or max_concurrent_paid instead. See
Admission and limits.
Self-serve signup
| Field | On this host | Ships as | What it does |
|---|---|---|---|
waitlist_open |
1 |
1 |
On, the landing page collects waitlist entries. Off, it sends people to signup |
blocked_email_domains |
(empty) | (empty) | One domain per line, refused on the email signup path |
See Self-serve signup.
What a change costs
| Change | Applies to | Running benches |
|---|---|---|
base_domain |
new site addresses | existing addresses do not move |
default_bench_runtime |
the next deploy | untouched until redeployed |
enable_golden_images |
the next build | existing images keep the golden they already carry |
restore_from_golden |
the next deploy | untouched |
container_memory_limit, container_cpu_quota |
new labs | untouched. A lab that copied the old value keeps it |
bench_subnet_base, bench_bridge_count |
bridges created after the change | existing bridges and the benches on them stay |
| health probe fields | the next deploy, which writes a new healthcheck | untouched |
enable_credits |
immediately | every deploy, renewal and device add is gated from the next request |
reap_after_days |
the next daily sweep | a stopped instance already past the new figure is reaped on that sweep |
How these values were read
Off the live site, from the document rather than from the DocType JSON:
bench --site <site> execute frappe.client.get_value \
--kwargs "{'doctype':'BenchPress Settings','fieldname':'default_bench_runtime'}"
To dump every field with its stored value and its shipped default at once, use
bench console:
import frappe
d = frappe.get_cached_doc("BenchPress Settings")
for f in frappe.get_meta("BenchPress Settings").fields:
if f.fieldtype not in ("Section Break", "Column Break", "Tab Break", "HTML"):
print(f.fieldname, "=", d.get(f.fieldname), "| ships as", f.default)
A multi-line block fed to bench console on a pipe is truncated at the first
blank line, and it fails silently. Type it into an interactive console, or
wrap it in a single exec() call.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| A saved change has no effect | The Single is cached in another process | bench --site <site> clear-cache, then restart the workers |
| Settings will not save | base_domain is empty |
It is required. Sites are addressed under it |
| A field you cleared behaved as before | 0 falls back to the built-in for that field |
See Reconciliation and events. Set the number you want |
| Every user is refused a deploy | enable_credits was switched on and nobody has an account |
Switch it back to 0, or read Credits and billing |
| The Settings dialog does not show a field you read about | The dialog carries 10 of 26 fields | Edit it at /app/benchpress-settings |
| The Settings item is missing from the account menu | The screen is admin-only | See Users and roles |
Related
- Diagnostics — checks that read the host, not the settings.
- Admission and limits — what the caps do when credits are on.
- Credits and billing — the switch this page keeps telling you to leave alone.
- Golden images — the two settings that decide deploy speed.