Environment Variables
Every environment variable the Localport agent reads, how flags and files take precedence, and how to keep tokens off the command line.
Summary
Which environment variables does the agent read?#
| Variable | Applies to | What it does |
|---|---|---|
LOCALPORT_TOKEN | Tunnels, devices | Tunnel or fleet token, instead of --token |
LOCALPORT_TOKEN_FILE | Tunnels, devices | File to read that token from |
LOCALPORT_SETUP_TOKEN | setup | Setup key, instead of the positional argument |
LOCALPORT_SETUP_TOKEN_FILE | setup | File to read the setup key from |
LOCALPORT_IDENTITY | access, identity | Which stored credential to present |
LOCALPORT_HOME | all | Where credentials are stored. Defaults to ~/.localport |
LOCALPORT_P12_PASSWORD | access | Password for a PKCS#12 file. Point --p12-pass-env at a different variable to rename it |
LOCALPORT_OIDC_AUDIENCE | access | OIDC audience, instead of --audience |
LOCALPORT_OIDC_TOKEN | access | A workload token from a CI platform the agent does not detect. Checked first when present |
LOCALPORT_ALLOW_COREDUMP | all | 1 keeps the process dumpable on Linux, for a debugger. See below |
NO_COLOR | Live view | Set to anything to turn colour off |
COLORTERM | Live view | truecolor or 24bit for 24-bit colour in the live panel |
TERM | Live view | dumb forces plain output |
Which source wins#
The flag, then the variable, then the file. Every secret resolves in that order.
--token highest
LOCALPORT_TOKEN
LOCALPORT_TOKEN_FILE lowest
So a systemd unit can set LOCALPORT_TOKEN_FILE for normal operation, and you can still override it once on the command line without editing the unit.
--identity follows the same shape, with one addition. When no selector is given and a person is at the terminal, the agent shows a picker. A selector that matches nothing, or matches several credentials, is an error and never a prompt.
--identity > LOCALPORT_IDENTITY > interactive picker
How to keep a token out of the process list#
Use the _FILE form. An argument on the command line appears in shell history, in ps output and in /proc, where every other account on the machine can read it.
export LOCALPORT_TOKEN_FILE=/etc/localport/token
localport http 3000
The variable itself is second best on a shared machine, since /proc/<pid>/environ exposes it to root and to anything running as the same user. The file form is what systemd's LoadCredential= and Docker secrets produce, and what the service templates use.
A file holding a secret is held to the same rules as a private key. It must be a regular file, mode 0600 or stricter, and owned by the account running the agent. Anything else is refused, with the mode it actually had:
/etc/localport/token has too-open permissions 0644 (want 0600 or stricter)
Secret values are stripped from error messages before they are printed, so a failure path cannot put a token in a log.
What stops a token leaving the process#
The agent holds its token for as long as it runs, because reconnecting presents
it again. Two paths take a secret out of a running process without its
cooperation, and on Linux both are closed at startup: the agent marks itself
non-dumpable, so the kernel writes no core dump for it and only root may attach a
debugger or read its memory. macOS and Windows have no portable equivalent, so
there the file modes and the service account are what bound it.
Set LOCALPORT_ALLOW_COREDUMP=1 to keep the process dumpable while debugging.
The service templates also set LimitCORE=0, which refuses the dump from the
other side.
A token passed as --token is readable by every account on the machine through
ps and /proc, and the agent says so once at startup when you do it. The
_FILE form keeps it in a 0600 file instead.
How to use a variable inside a config file#
Write ${VAR}. References are substituted when the file is read, so a config file you commit holds no secrets.
version: 1
tunnels:
- name: api
token: ${LOCALPORT_TOKEN}
upstream: http://localhost:3000
export LOCALPORT_TOKEN=tok_...
localport connect --config localport.yaml
Three forms are recognised, plus $$ for a literal $.
| Written as | Resolves to |
|---|---|
${VAR} | The value. Unset or empty stops the run. |
${VAR:-default} | The value, or default when unset or empty. |
${VAR:?message} | The value, or a refusal carrying your message. |
An unresolved reference stops the run before anything connects, and the error names every one that was missing:
LOCALPORT_TOKEN is not set; DB_PORT is not set
Substitution runs on the file's text before the YAML is parsed, so a value may hold any character. An access config is the exception: localport access --config does no substitution, and the PKCS#12 password comes from p12_pass_env or p12_pass_file instead. The full file format is on the Configuration page.
Where credentials are stored#
Under ~/.localport, with directories at mode 0700 and files at 0600. Set LOCALPORT_HOME to move that somewhere else.
A system account usually has no home directory to write to. The service templates set LOCALPORT_HOME explicitly for that reason. A tunnel that authenticates with a token alone stores nothing.
Frequently asked questions#
Can I use environment variables instead of flags for everything?
For secrets and credential selection, yes. Tunnel and fleet tokens, setup keys, PKCS#12 passwords, OIDC audiences and the identity selector all have a variable. Options that shape a single run, such as the protocol, the device name and the region, are flags or config file fields. The CLI reference lists every flag.
What happens if I set both the flag and the environment variable?
The flag wins. Resolution runs flag, then variable, then _FILE variable, and stops at the first one with a value. This lets a service set the variable permanently while you override it for one run.
Why does the agent refuse to read my token file?
The file has to be a regular file, mode 0600 or stricter, and owned by the account running the agent. A symlink is refused, and so is a file owned by somebody else, even at 0600. The error names the file and the mode it actually had. Fix it with chmod 0600 and chown.
Is the environment safer than the command line?
Better, and not by much. The command line is visible to every account on the machine through ps and /proc. The environment is visible to root and to anything running as the same user through /proc/<pid>/environ. On a shared machine, point a _FILE variable at a 0600 file.
Can I put an environment variable inside a config file?
Yes, with ${VAR} in an agent config. It is substituted when the file is read, so the token stays in the environment and the file stays committable. An unset variable stops the run, and ${VAR:-default} or ${VAR:?message} control what happens instead. An access config does no substitution, so a PKCS#12 password there is named with p12_pass_env.
How do I turn off the colours in the live panel?
Set NO_COLOR to any value, or set TERM=dumb for plain output. In the other direction, COLORTERM=truecolor gives the panel 24-bit colour. The agent also drops to plain log lines on its own when nothing is attached to a terminal.
Where does the agent store credentials, and can I move them?
Under ~/.localport, with directories at 0700 and files at 0600. Set LOCALPORT_HOME to move them. That is the setting to use for a system account with no home directory. Only localport setup and localport login write anything, and a token-authenticated tunnel stores nothing.
Which variable does a CI job need?
Usually none. On a platform the agent recognises, localport access --audience uses the token the platform already mints and no secret is stored anywhere. On a platform it does not recognise, put that token in LOCALPORT_OIDC_TOKEN. See CI/CD with OIDC.
What to read next#
- CLI. Every command and flag.
- Configuration. The YAML format for running several tunnels and devices at once.
- Installation. Service templates that use the file form.
- Setup Keys. Give a machine its own renewing credential.
- CI/CD with OIDC. Reach a fleet from a pipeline with no stored secret.