Environment variables

Reading time 5 min

Set variables on the process that reads them. A static host environment does not create a writing server. Ordinary editor configuration is read at process start; restart it deliberately after changing these values and verify actual Security/listener state.

Long variable names are separate headings so comparable defaults remain readable on phones. Examples below contain no credentials and are not production deployment certification.

Process map

Process Settings it reads
Editor Listener, hosts, body, users, sessions, cookie, proxies
Account commands Users file
Builder Data selectors and progress events
Local preview Preview port
Static reader Generated files, not server environment

The editor has fixed installed-engine content/static/dist paths in ordinary CLI. Builder --content/--out do not move them. No general PORT, editor data-root, TLS-certificate or content-directory environment selector is supplied at this pin.

MARKSTACK_EDITOR_PORT

Default 3001. Editor uses decimal parseInt(value, 10) || 3001, not preview’s stricter integer parser. Missing, empty, nonnumeric or zero value falls back. Numeric-prefix text such as 3100junk parses to 3100. Negative/out-of-range values are not deliberately normalized by this expression; listener can fail. Use an explicit integer 1-65535 and verify binding/Host allow-list after restart. Port 0 does not request ephemeral allocation here.

MARKSTACK_EDITOR_HOST

Default 127.0.0.1 when unset/empty. This is the listening interface, not accepted browser Host or a TLS setting. A broader bind can expose the writer to the network. Choose deliberate loopback/private binding, external gate and no direct bypass. Changing it requires restart; validate actual listener from both expected and disallowed network contexts.

MARKSTACK_EDITOR_ALLOWED_HOSTS

Default empty additional list. Comma-separated entries are trimmed/lowercased; blank entries removed. Built-in accepted Host values are localhost, IPv4 loopback and bracketed IPv6 loopback with configured editor port.

Additional entries are exact Host header values, including nonstandard port when browser sends it. No scheme/path, wildcard or CIDR match is implemented. This does not bind DNS, add TLS or authorize reader access. Origin, when supplied, must have the same parsed host as Host; POST requires JSON. Incorrect proxy-preserved Host can yield Host not allowed even with working credentials.

MARKSTACK_EDITOR_MAX_BODY

Default 2097152 bytes (2 MiB). Same parseInt then truthy fallback pattern as editor port. It bounds collected request body, not a per-page route quota, upload contract or maximum whole-site size. Invalid/zero values can fall back; negative values are not a sensible limit. Use positive reviewed byte count. Exceeded body yields request failure; verify intended size rather than retrying larger text indefinitely.

MARKSTACK_USERS_FILE

Default engine .markstack/users.json. Editor and create/reset account commands read this path. Relative paths depend on process working directory; use deliberate absolute path for supervised service. Builder also uses its resolved parent as data fallback, not to read passwords into output.

Editor derives links/settings/icons/history and publish marker beside users file. Keep accounts private, outside repository/publishable roots and aligned across server/account commands. Changing this variable can select an empty/different account set; restarting against wrong path is not account recovery. MARKSTACK_DATA_DIR does not move the editor users file.

MARKSTACK_SESSION_IDLE_MINUTES

Default 480 minutes (8 hours). Parsed with parseInt and truthy fallback. The session store requires positive resulting milliseconds, so negative duration causes initialization failure rather than a useful signed-in state. Idle expiry compares elapsed time since last session access. Requests that access session can refresh idle; administrative session summaries do not.

MARKSTACK_SESSION_MAX_MINUTES

Default 10080 minutes (7 days). Same parsing and positive-store requirement. Absolute expiry is measured from session creation, independently of idle refresh. Cookie Max-Age follows this configured maximum. No parser check requires maximum to exceed idle; set a coherent policy and verify actual expiration behavior.

Sessions are in memory. Restart ends them regardless of cookie lifetime. Changing durations requires new process; it is not editing persisted session rows.

Enabled only by exact string 1; unset, true, yes or 0 leave secure mode off. Enabled mode uses __Host-ms_session, Secure, HttpOnly, SameSite=Strict, Path=/ and no Domain. Local insecure mode uses ms_session; cookie helper clears the alternate mode’s name.

Enable only with working HTTPS. Plain HTTP can prevent browser accepting/sending secure cookie, producing sign-in loops. This setting does not create HTTPS or certificate. Check real response cookie attributes privately without copying token values into support output.

MARKSTACK_TRUSTED_PROXIES

Default empty: forwarded address ignored. Comma-separated entries are trimmed; mapped IPv4 prefix is removed and addresses lowercased. Literal loopback expands to 127.0.0.1 and ::1. Other entries are exact normalized strings, not subnet/CIDR ranges.

Forwarded address is used only when socket peer is in this list. Server walks X-Forwarded-For right to left, skipping trusted entries and taking first other value. This affects login-limiter client identity; it is not a TLS, Host or authentication override. Trust only actual controlled proxy peers and check spoofed/untrusted forwarding denial. Configuring arbitrary clients as trusted undermines that boundary.

MARKSTACK_DATA_DIR

Builder-only data selector. Precedence is --data, then this nonempty variable, then parent of resolved users file, then engine .markstack. Relative value is resolved from working directory. Selects saved settings, header links and cached icons used by reader generation, not permission-filtered pages.

Ordinary editor ignores it as a data-root override: editor runtime derives from users file. Editor publication explicitly snapshots runtime and passes builder --data; do not infer a build environment variable redirects its account/runtime store.

MARKSTACK_PREVIEW_PORT

Default 3000. Preview uses Number(value || 3000) then requires integer 1-65535. Empty string uses default; whitespace can convert to zero and fail. Numeric-prefix junk and fractions fail. Preview binds loopback and serves engine dist only. It does not affect editor port or earlier custom builder output.

MARKSTACK_BUILD_EVENTS

Builder emits machine progress lines only when exact value is 1. Lines begin @@MS followed by JSON events for total/page/stage progress. Ordinary readable logs continue. Editor child sets this for publication progress; it is not a remote telemetry or hosting integration. Do not treat its log label “pages” as only article count when discussing search entries.

Safe syntax example

Unix local development, after confirming installed project and unused port:

MARKSTACK_EDITOR_HOST=127.0.0.1 MARKSTACK_EDITOR_PORT=3101 npm run editor

PowerShell local development:

$env:MARKSTACK_EDITOR_HOST = '127.0.0.1'
$env:MARKSTACK_EDITOR_PORT = '3101'
npm.cmd run editor

These set loopback/plain-local mode, not a production HTTPS service. Account commands still need the same selected users file. Windows service supervision/permissions require separate operational verification.

Verify after change

Layer Check
Process Intended restart/environment/working directory
Listener Actual interface/port, no unintended exposure
Host Exact intended value accepted, wrong value denied
Account Intended private runtime/account set
Session Reported durations and actual behavior
Cookie HTTPS/mode works with intended browser
Proxy Trusted peer handling; spoofing denied
Builder Correct effective data and output

Defaults and parsers describe implementation, not safe production policy. Private team editor and Security and privacy own infrastructure gates. Commands separates builder/preview/account syntax.