API Server Config


The Bencher API Server requires a JSON configuration at startup. The configuration can be provided three ways:

  • BENCHER_CONFIG environment variable: The value should be set to the JSON configuration
  • BENCHER_CONFIG_PATH environment variable: The value should be set to the path of a file containing the JSON configuration
  • /etc/bencher/bencher.json file: A file at this location containing the JSON configuration

If no configuration is found, then a default configuration is loaded.

Example JSON configuration:

{
"console": {
"url": "https://bencher.example.com"
},
"security": {
"issuer": "https://api.bencher.example.com",
"secret_key": "UJu7Cpxb-zFaJYqXD-3mDDSDyj-ZvfxZFZs-X58xjxPy"
},
"server": {
"bind_address": "0.0.0.0:6610",
"request_body_max_bytes": 1048576,
"tls": {
"type": "as_file",
"cert_file": "/path/to/cert.pem",
"key_file": "/path/to/key.pem"
}
},
"logging": {
"name": "Bencher API",
"log": {
"stderr_terminal": {
"level": "info"
}
},
},
"database": {
"file": "/var/lib/bencher/data/bencher.db",
"data_store": {
"service": "aws_s3",
"access_key_id": "ABC123DoRemMiABC123",
"secret_access_key": "AA3Chr-JSF5sUQqKwayx-FvCfZKsMev-5BqPpcFC3m7",
"access_point": "arn:aws:s3:some-region-1:123456789:accesspoint/my-bucket/path/to/backup/dir"
},
"busy_timeout": 5000,
"cache_size": 65536
},
"smtp": {
"hostname": "mailbonobo.com",
"port": 587,
"starttls": true,
"username": "bencher",
"secret": "WM3F2u9cqSNdBPLfy9sJ5kk9",
"from_name": "Bencher",
"from_email": "info@bencher.example.com"
},
"plus": {
"disaster_recovery": {
"replicas": [
{
"scheme": "s3",
"bucket": "my-bucket",
"path": "path/to/replicate",
"access_key_id": "ABC123DoRemMiABC123",
"secret_access_key": "AA3Chr-JSF5sUQqKwayx-FvCfZKsMev-5BqPpcFC3m7"
}
]
},
"registry": {
"url": "https://registry.bencher.example.com",
"data_store": {
"service": "aws_s3",
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"access_point": "arn:aws:s3:us-east-1:123456789012:accesspoint/my-access-point/registry",
"chunk_size": 5242880
},
"upload_timeout": 3600,
"max_body_size": 1073741824
},
"runners": {
"heartbeat_timeout": 90,
"job_timeout_grace_period": 60,
"update_base_url": "https://github.com/bencherdev/bencher/releases/download/"
},
"rate_limiting": {
"window": 86400,
"unclaimed_limit": 255,
"claimed_limit": 65536,
"public": {
"requests": {
"minute": 1024,
"hour": 4096,
"day": 8192
},
"attempts": {
"minute": 32,
"hour": 64,
"day": 128
},
"runs": {
"minute": 64,
"hour": 128,
"day": 256
}
},
"user": {
"requests": {
"minute": 2048,
"hour": 8192,
"day": 16384
},
"attempts": {
"minute": 2,
"hour": 4,
"day": 8
},
"credentials": {
"minute": 4,
"hour": 8,
"day": 16
},
"organizations": {
"minute": 2,
"hour": 4,
"day": 8
},
"invites": {
"minute": 8,
"hour": 16,
"day": 32
},
"runs": {
"minute": 64,
"hour": 1024,
"day": 4096
}
},
"project": {
"requests": {
"minute": 2048,
"hour": 8192,
"day": 16384
},
"runs": {
"minute": 64,
"hour": 1024,
"day": 4096
}
},
"runner": {
"requests": {
"minute": 16,
"hour": 256,
"day": 4096
}
},
"oci_bandwidth": {
"unclaimed": 1073741824,
"free": 10737418240,
"plus": 107374182400
}
},
"stats": {
"offset": 11242,
"enabled": true
}
}
}

console

Name Example Default Required Description
url https://bencher.example.com http://localhost:3000 Yes Specifies the URL for the Bencher Console host.

security

Name Example Default Required Description
issuer https://api.bencher.example.com “bencher.dev” No Specifies the JSON Web Token (JWT) issuer. WARNING Changing this value will cause all previously generated JWTs to no longer validate.
secret_key “UJu7Cpxb-zFaJYqXD-3mDDSDyj-ZvfxZFZs-X58xjxPy” Random UUID v4 Yes Specifies the the key used to generate all tokens. IT SHOULD BE VERY SECURE! The default value is a randomly generated UUID v4. Whenever logged, it will appear obfuscated as ************.

server

This section is based on the Dropshot server configuration.

Name Example Default Required Description
bind_address “0.0.0.0:6610” “0.0.0.0:6610” Yes Specifies that the server should bind to the given IP address and TCP port. In general, servers can bind to more than one IP address and port, but this is not (yet?) supported.
request_body_max_bytes 1048576 1048576 Yes Specifies the maximum number of bytes allowed in a request body. Larger requests will receive a 400 error.
tls.type “as_file” No Specifies if and how TLS certificate and key information is provided. Valid values include “as_file” and “as_bytes”.
tls.cert_file “/path/to/cert.pem” Only if tls.type = as_file Specifies the path to a PEM file containing a certificate chain for the server to identify itself with. The first certificate is the end-entity certificate, and the remaining are intermediate certificates on the way to a trusted CA. If specified, the server will only listen for TLS connections.
tls.key_file “/path/to/key.pem” Only if tls.type = as_file Specifies the path to a PEM-encoded PKCS #8 file containing the private key the server will use. If specified, the server will only listen for TLS connections.
tls.certs Only if tls.type = as_bytes Identical to tls.cert_file, but provided as an array of bytes of certificate data.
tls.key Only if tls.type = as_bytes Identical to tls.key_file, but provided as an array of bytes of key data.

logging

This section is based on the Dropshot logging configuration.

Name Example Default Required Description
name “Bencher API” “Bencher API” Yes Specifies the name of the logger.
log.mode “stderr_terminal” “stderr_terminal” Yes Controls where server logging will go. Valid modes are “stderr-terminal” and “file”. If the mode is `“stderr-terminal”, human-readable output, with colors and other terminal formatting if possible, will be sent to stderr. If the mode is “file”, Bunyan-format output will be sent to the filesystem path given by log.path. See also log.if_exists, which controls the behavior if the destination path already exists.
log.level “info” “info” Yes Specifies what severity of log messages should be included in the log. Valid values include “trace”, “debug”, “info”, “warn”, “error”, and “critical”, which are increasing order of severity. Log messages at the specified level and more severe levels will be included in the log.
log.path Only if log.mode = “file” If log.mode is “file”, this property determines the path to the log file. See also log.if_exists.
log.if_exists Only if log.mode = “file” If log.mode is “file”, this property specifies what to do if the destination log file already exists. Valid values include “append” (which appends to the existing file), “truncate” (which truncates the existing file and then uses it as though it had just been created), and “fail” (which causes the server to exit immediately with an error).

database

Name Example Default Required Description
file “path/to/database.db” “/var/lib/bencher/data/bencher.db” Yes Controls where server database will go.
data_store.service “aws_s3” No Specifies the remote data store service. Valid values are “aws_s3”.
data_store.access_key_id “ABC123DoRemMiABC123” Only if data_store.service = “aws_s3” If data_store.service = “aws_s3”, this property specifies the AWS access key ID. See also data_store.service.
data_store.secret_access_key “AA3Chr-JSF5sUQqKwayx-FvCfZKsMev-5BqPpcFC3m7” Only if data_store.service = “aws_s3” If data_store.service = “aws_s3”, this property specifies the AWS secret access key. See also data_store.service. Whenever logged, it will appear obfuscated as ************.
data_store.access_point “arn:aws:s3:some-region-1:123456789:accesspoint/my-bucket/path/to/backup/dir” Only if data_store.service = “aws_s3” If data_store.service = “aws_s3”, this property specifies the AWS S3 accesspoint. See also data_store.service.
busy_timeout 5000 5000 No Specifies the busy timeout for the database in milliseconds. Prevents immediate SQLITE_BUSY errors under lock contention.
cache_size 65536 65536 No Specifies the page cache size in KiB for the writer database connection. A larger cache avoids re-reading evicted pages during large report ingests and deletions. Must be greater than 0.

smtp

This section specifies an SMTP service configuration. The entire section is optional. If not specified, all messages will be sent to logging instead.

Name Example Default Required Description
hostname “mailbonobo.com” Yes Specifies the SMTP hostname.
port 587 587 No Specifies the SMTP port.
insecure_host false No Controls whether the SMTP connection can allow invalid TLS certificates.
starttls true true No Controls whether the SMTP connection uses the STARTTLS protocol.
username “bencher” Yes Specifies the username at the SMTP host.
secret “WM3F2u9cqSNdBPLfy9sJ5kk9” Yes Specifies the secret for the username at the SMTP host. Whenever logged, it will appear obfuscated as ************.
from_name “Bencher” Yes Specifies the name that will appear in the from section of all emails.
from_email info@bencher.example.com Yes Spefifies the email that will appear in the from section of all emails.

plus

This section is for features that are covered by the Bencher Plus License.

plus.github

This section specifies the configuration for a GitHub App used for OAuth2 authentication. You must have a valid Bencher Plus Enterprise license for at least one organization on the server. The entire section is optional. If not specified, then authentication with GitHub will not be enabled.

Name Example Default Required Description
client_id Iv1.12864abcd1232048 Yes Specifies the client ID for your GitHub App. The client ID is different from the app ID. You can find the client ID on the settings page for your app. For more information about navigating to the settings page for your GitHub App, see Modifying a GitHub App registration.
client_secret 00000abcd12345wxyz123456789abcdefgh0000 Yes The client secret for your GitHub App. You can generate a client secret on the settings page for your app.

plus.google

This section specifies the configuration for a Google client used for OAuth2 authentication. You must have a valid Bencher Plus Enterprise license for at least one organization on the server. The entire section is optional. If not specified, then authentication with Google will not be enabled.

Name Example Default Required Description
client_id 0123456789-abcdefg0112358envs.apps.googleusercontent.com Yes Specifies the client ID for your Google OAuth2 Client.
client_secret GOCSPX-xyz987654321 Yes The client secret for your Google OAuth2 Client.

plus.disaster_recovery

This section specifies the disaster recovery configuration. Bencher supports continuously replicating all database changes. For running on demand or scheduled backups, see the database.data_store section of the configuration.

There are three replication schemes:

  • file: Replicate to a local file path
    • path: Path to replicate to
  • sftp: Replicate over SFTP
    • host: Target system hostname
    • port: Target system port number
    • user: Username on target system
    • password: (Optional) Password on target system
    • path: (Optional) Path on target system
    • key_path: (Optional) Path to SSH key
  • s3: Replicate to any S3 compatible blob storage
    • bucket: Bucket name
    • path: (Optional) Path in bucket
    • endpoint: (AWS: Optional | Non-AWS: Required) Replication endpoint
    • region: (Optional) Bucket region
    • access_key_id: S3 access key
    • secret_access_key: S3 secret access key

All three replica schemes have the following additional options:

  • snapshot.interval: (Optional) Specifies how often new snapshots will be created. This is used to reduce the time to restore since newer snapshots will have fewer WAL frames to apply. Retention still applies to these snapshots. If you do not set a snapshot interval then a new snapshot will be created whenever retention is performed. Retention occurs every 24 hours by default.
  • snapshot.retention: (Optional) The amount of time that snapshot & WAL files will be kept. After the retention period, a new snapshot will be created and the old one will be removed. WAL files that exist before the oldest snapshot will also be removed. Defaults to 24h.
  • validation.interval: (Optional) When specified, Bencher will automatically restore and validate that the data on the replica matches the local copy. Disabled by default. Enabling this may significantly increase the cost of running Bencher as most cloud services charge for downloads.
  • sync_interval: (Optional) Frequency in which frames are pushed to the replica. Defaults to 1s. Increasing frequency can increase cloud storage costs significantly.
  • checkpoint.interval: (Optional) How often Litestream performs a non-blocking PASSIVE checkpoint regardless of page count. Litestream skips the checkpoint if readers or writers are active. Defaults to 1m.
  • checkpoint.min_page_count: (Optional) Minimum number of WAL pages before a non-blocking PASSIVE checkpoint is triggered (~4KB per page). Litestream skips the checkpoint if readers or writers are active. Defaults to 1000 (~4MB).
  • checkpoint.truncate_page_n: (Optional) Page count threshold for a blocking TRUNCATE checkpoint. When this threshold is reached, Litestream performs a blocking checkpoint that waits for all readers and writers to complete, which can cause database is locked errors under load. Defaults to 0 (disabled). Only set this to a non-zero value if you need an upper bound on WAL file size and understand the blocking implications.
Name Example Default Required Description
replica { … } Yes Specifies a replica object.
replica.scheme “s3” Yes Specifies the replication scheme. For all other replica keys, see the list above.
snapshot.interval “1h” No How often new snapshots are created. Reduces restore time.
snapshot.retention “24h” 24h No How long snapshot & WAL files are kept before being replaced.
validation.interval “6h” No How often replica data is restored and validated against the local copy. Disabled by default.
checkpoint.interval “1m” 1m No How often a non-blocking PASSIVE checkpoint runs. Skipped if readers/writers are active.
checkpoint.min_page_count 1000 1000 No Minimum WAL pages (~4KB each) before a PASSIVE checkpoint triggers. Skipped if readers/writers are active.
checkpoint.truncate_page_n 0 0 No Page threshold for a blocking TRUNCATE checkpoint. 0 disables. Non-zero values may cause database is locked under load.

plus.registry

This section specifies the container registry storage configuration. Bencher can function as an OCI-compliant container/artifact registry.

If this section is not configured, Bencher will use local filesystem storage in a registry directory sibling to the database file. This is suitable for development and single-instance deployments.

For production deployments with multiple instances or for durability, configure S3-based storage.

There are two storage service options:

  • local: Store registry artifacts on the local filesystem (default)
  • aws_s3: Store registry artifacts in AWS S3
    • access_key_id: AWS access key ID
    • secret_access_key: AWS secret access key
    • access_point: S3 Access Point ARN with optional path prefix. Format: arn:aws:s3:<region>:<account-id>:accesspoint/<access-point-name>[/<path-prefix>]
    • chunk_size: Minimum chunk size in bytes for buffering upload data before storing to S3 (default: 5 MB). HTTP request bodies arrive as small network frames (typically 8–64 KB). Without batching, each frame becomes a separate S3 object, creating thousands of objects per layer. This value also matches the S3 multipart upload minimum part size.
Name Example Default Required Description
url https://registry.bencher.example.com http://localhost:6610 No The externally-reachable URL of the API server for OCI registry access.
data_store { … } No Specifies the registry storage backend. Local if omitted.
data_store.service “local” or “aws_s3” Yes Specifies the storage service type.
data_store.access_key_id “AKIAIOSFODNN7EXAMPLE” aws_s3 only AWS access key ID.
data_store.secret_access_key “wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY” aws_s3 only AWS secret access key.
data_store.access_point “arn:aws:s3:us-east-1:123456789012:accesspoint/my-access-point/registry” aws_s3 only S3 Access Point ARN. Optional path prefix after access point name.
data_store.chunk_size 5242880 5242880 aws_s3 only Minimum chunk size in bytes for buffering upload data before storing to S3. Defaults to 5 MB.
upload_timeout 3600 3600 No Upload session timeout in seconds. Stale uploads are cleaned up when new uploads start.
max_body_size 1073741824 1073741824 No Maximum body size in bytes for blob and manifest uploads. Requests exceeding this limit are rejected with 413 Payload Too Large. Defaults to 1 GiB.

plus.runners

This section configures the runner system for bare metal benchmark execution. Runners are server-scoped agents that claim and execute benchmark jobs.

If this section is not configured, Bencher will use the default values.

Name Example Default Required Description
heartbeat_timeout 90 90 No Time in seconds without a heartbeat before marking a job as failed.
job_timeout_grace_period 60 60 No Extra time in seconds beyond a job’s configured timeout before the server cancels it.
update_base_url https://example.com/downloads/ GitHub Releases No Base URL for runner self-update downloads. Defaults to the Bencher GitHub Releases download URL.

plus.rate_limiting

This section specifies the rate limiting for the API server. The entire section is optional. If not specified, the listed default values will be used.

To prevent unclaimed projects from being created, set the unclaimed_limit to 0.

Name Example Default Required Description
window 86400 86400 No Specifies the rate limiting window in seconds. Set to one day by default.
unclaimed_limit 255 255 No Controls the rate limiting for unclaimed projects. To prevent unclaimed projects from being created, set this value to 0.
claimed_limit 65536 65536 No Controls the rate limiting for claimed projects.

public

The public rate limiter applies per IP address for unauthenticated requests. Each sub-field contains minute, hour, and day limits. The entire section is optional. If not specified, the listed default values will be used.

Name Example Default Required Description
requests { … } No Specifies per-IP request rate limits.
requests.minute 1024 1024 No Maximum requests per minute per IP address.
requests.hour 4096 4096 No Maximum requests per hour per IP address.
requests.day 8192 8192 No Maximum requests per day per IP address.
attempts { … } No Specifies per-IP authentication attempt rate limits.
attempts.minute 32 32 No Maximum authentication attempts per minute per IP address.
attempts.hour 64 64 No Maximum authentication attempts per hour per IP address.
attempts.day 128 128 No Maximum authentication attempts per day per IP address.
runs { … } No Specifies per-IP benchmark run rate limits for unclaimed projects.
runs.minute 64 64 No Maximum benchmark runs per minute per IP address.
runs.hour 128 128 No Maximum benchmark runs per hour per IP address.
runs.day 256 256 No Maximum benchmark runs per day per IP address.

user

The user rate limiter applies per authenticated user. Each sub-field contains minute, hour, and day limits. The entire section is optional. If not specified, the listed default values will be used.

Name Example Default Required Description
requests { … } No Specifies per-user request rate limits.
requests.minute 2048 2048 No Maximum requests per minute per user.
requests.hour 8192 8192 No Maximum requests per hour per user.
requests.day 16384 16384 No Maximum requests per day per user.
attempts { … } No Specifies per-user authentication attempt rate limits.
attempts.minute 2 2 No Maximum authentication attempts per minute per user.
attempts.hour 4 4 No Maximum authentication attempts per hour per user.
attempts.day 8 8 No Maximum authentication attempts per day per user.
credentials { … } No Specifies per-user credential creation rate limits.
credentials.minute 4 4 No Maximum credential creations per minute per user.
credentials.hour 8 8 No Maximum credential creations per hour per user.
credentials.day 16 16 No Maximum credential creations per day per user.
organizations { … } No Specifies per-user organization creation rate limits.
organizations.minute 2 2 No Maximum organization creations per minute per user.
organizations.hour 4 4 No Maximum organization creations per hour per user.
organizations.day 8 8 No Maximum organization creations per day per user.
invites { … } No Specifies per-user invite rate limits.
invites.minute 8 8 No Maximum invites per minute per user.
invites.hour 16 16 No Maximum invites per hour per user.
invites.day 32 32 No Maximum invites per day per user.
runs { … } No Specifies per-user benchmark run rate limits.
runs.minute 64 64 No Maximum benchmark runs per minute per user.
runs.hour 1024 1024 No Maximum benchmark runs per hour per user.
runs.day 4096 4096 No Maximum benchmark runs per day per user.

project

The project rate limiter applies per project. Each sub-field contains minute, hour, and day limits. The entire section is optional. If not specified, the listed default values will be used.

Name Example Default Required Description
requests { … } No Specifies per-project request rate limits.
requests.minute 2048 2048 No Maximum requests per minute per project.
requests.hour 8192 8192 No Maximum requests per hour per project.
requests.day 16384 16384 No Maximum requests per day per project.
runs { … } No Specifies per-project benchmark run rate limits.
runs.minute 64 64 No Maximum benchmark runs per minute per project.
runs.hour 1024 1024 No Maximum benchmark runs per hour per project.
runs.day 4096 4096 No Maximum benchmark runs per day per project.

runner

The runner rate limiter applies per runner. Each sub-field contains minute, hour, and day limits. The entire section is optional. If not specified, the listed default values will be used.

Name Example Default Required Description
requests { … } No Specifies per-runner request rate limits.
requests.minute 16 16 No Maximum requests per minute per runner.
requests.hour 256 256 No Maximum requests per hour per runner.
requests.day 4096 4096 No Maximum requests per day per runner.

oci_bandwidth

The oci_bandwidth rate limiter specifies daily OCI registry bandwidth limits per organization tier. The entire section is optional. If not specified, the listed default values will be used.

Name Example Default Required Description
unclaimed 1073741824 1073741824 No Maximum bytes per day for unclaimed organizations (0 members). Defaults to 1 GiB.
free 10737418240 10737418240 No Maximum bytes per day for free (claimed, no paid plan) organizations. Defaults to 10 GiB.
plus 107374182400 107374182400 No Maximum bytes per day for Plus (Team/Enterprise) organizations. Defaults to 100 GiB.

plus.stats

This section specifies if and when server statistics are collected. The entire section is optional. If not specified, the listed default values will be used. That is, server statistics are opt-out. Set enabled to false to disable server statistics.

Name Example Default Required Description
offset 11242 11242 No Specifies the offset from midnight in seconds for server statistics collection. By default it runs at 03:07:22 UTC.
enabled true true No Controls whether server statistics are collected. Set to false to opt-out.


Published: Sat, August 12, 2023 at 4:07:00 PM UTC | Last Updated: Wed, July 8, 2026 at 12:00:00 AM UTC