Skip to content

Configuration ​

Natscope runs with zero configuration. Every key below has a working default. Override only what you need.

How settings resolve ​

Two sources, environment wins:

  1. A YAML config file, passed with --config (or -c) or the CONFIG_FILE environment variable. CONFIG_FILE takes precedence over the flag. Natscope fails to start if the path does not exist.
  2. Environment variables, which override anything in the file.

Nested YAML keys map to environment variables with double underscores. logger.level becomes LOGGER__LEVEL, storage.local.dataDir becomes STORAGE__LOCAL__DATA_DIR.

The config file must end in .yaml or .yml, and an unknown or misspelled key fails the load. An environment variable set to an empty string counts as unset. Boolean values accept true/false, yes/no, on/off and y/n in both sources.

A $NAME inside the file is replaced with that environment variable, and a reference to an undefined variable fails the load. Write a literal $ (for example in a password) as $$.

A .env file in the working directory is loaded only when NATSCOPE_DOTENV=1 is set.

bash
natscope --config /etc/natscope/config.yaml
CONFIG_FILE=/etc/natscope/config.yaml natscope

Commented templates for every section live in configs/ in the repository.

Env prefix

Environment keys carry a prefix that is set at build time. Released binaries ship with no prefix, so the names below are used as written. A build with prefix QA reads QA_GRPC_WEB_ADDRESS, QA_LIB_DIR and so on. Run natscope version --full to print the active prefix.

Keys ​

Listener ​

KeyEnvDefaultWhat it does
grpcWebAddressGRPC_WEB_ADDRESS127.0.0.1:4280Address serving the API and the embedded UI
allowRemoteALLOW_REMOTEfalsePermit a non-loopback bind
allowInsecureALLOW_INSECUREfalsePermit a non-loopback bind with no basic auth
allowedHostsALLOWED_HOSTSunsetComma-separated host names accepted in the Host header besides localhost and IP addresses
webAuth.usernameWEB_AUTH__USERNAMEunsetHTTP basic auth username for the whole listener
webAuth.passwordWEB_AUTH__PASSWORDunsetHTTP basic auth password

One listener speaks Connect, gRPC-Web and gRPC, and serves the SPA. There is no separate gRPC port. See Remote access before binding beyond loopback.

Storage ​

KeyEnvDefaultWhat it does
storage.local.dataDirSTORAGE__LOCAL__DATA_DIR~/.natscope/dataDirectory holding natscope.bolt and the file vault

Secrets ​

KeyEnvDefaultWhat it does
secrets.backendSECRETS__BACKENDautoVault backend: auto, keyring or file
secrets.fileKeySECRETS__FILE_KEYunsetAES-256 key for the file vault, 64 hex characters; prefer the env var

See Secrets.

MCP ​

KeyEnvDefaultWhat it does
mcp.enabledMCP__ENABLEDtrueServe the MCP endpoint at /mcp
mcp.allowWritesMCP__ALLOW_WRITESfalseRegister publish_message, the only tool that writes to NATS

See AI agents (MCP).

Logging ​

KeyEnvDefaultValues
logger.levelLOGGER__LEVELwarning in a terminal, info otherwiseerror, warning, info, debug, none
logger.outputLOGGER__OUTPUTstderrstdout, stderr
logger.outputFormatLOGGER__OUTPUT_FORMATconsole in a terminal, text otherwiseconsole, text, json
logger.colorizedLOGGER__COLORIZEDtrueColor for console and text, ignored for json
logger.outputSourceLOGGER__OUTPUT_SOURCEfalseAdd file and line to each entry

"In a terminal" means stderr is a TTY. The --log-level and --log-format flags override both the environment and the config file for those two keys.

Service directories ​

EnvDefaultWhat it does
VAR_DIR/varBase directory for variable runtime data
LIB_DIR<VAR_DIR>/lib/natscope, so /var/lib/natscopeService instance id file and the TLS certificate cache (<LIB_DIR>/certs)

When neither variable is set and the system paths are not writable, Natscope falls back to ~/.natscope/var and ~/.natscope/lib on its own. Set either variable and that fallback stops: if Natscope cannot create the directory you named, it fails to start.

Internal HTTP server ​

Off by default. With no http section in the config, it never starts. Enable it for health, readiness and metrics endpoints under /internal, plus opt-in pprof.

yaml
http:
  listenAddress: "127.0.0.1:9080"
  pprof:
    enabled: true

Keep it on loopback (127.0.0.1:port or [::1]:port). These endpoints expose runtime internals and carry no authentication. A non-loopback bind here, including a bare :port, needs both ALLOW_REMOTE=true and ALLOW_INSECURE=true, and pprof stays off on it regardless of configuration.

Memory ​

EnvDefaultWhat it does
NATSCOPE_MEMORY_LIMIT_BYTES512 MiBSoft heap limit; a byte count or a 256MiB/1GiB value. GOMEMLIMIT wins when set

Example ​

yaml
logger:
  level: debug
  outputFormat: json

grpcWebAddress: "127.0.0.1:4280"

storage:
  local:
    dataDir: /var/lib/natscope/data

secrets:
  backend: file

Docker defaults ​

The published image sets its own environment, so port mapping works in a container with no extra flags:

GRPC_WEB_ADDRESS=0.0.0.0:4280
ALLOW_REMOTE=true
ALLOW_INSECURE=true
SECRETS__BACKEND=file
STORAGE__LOCAL__DATA_DIR=/data
LIB_DIR=/data/lib
VAR_DIR=/data/var

The container binds all its interfaces so -p works. Publish on 127.0.0.1 to keep it host-local, or set WEB_AUTH__USERNAME and WEB_AUTH__PASSWORD when it is reachable from elsewhere.

Released under the MIT License.