Configuration

Every environment variable and settings file Link reads, the relay's flags, and the deploy scripts' flags and variables. Flags of lnk commands aren't here: run lnk <group> <command> --help.

Every lnk program

VariableDefaultWhat it does
HOME—Must be absolute, or commands that delete or trust a folder refuse.
XDG_CONFIG_HOME~/.configSettings go in $XDG_CONFIG_HOME/lnk (mode 700). A relative value is ignored.
LNK_EXEset by lnkThe lnk that started a plugin, which it runs for other commands.
LNK_KEYCHAINon, on a Macoff or 0: keep secrets in settings files, not the Keychain.
LNK_SERVICESonoff or 0: ask launchd or systemd nothing and start no model runtime; services read as stopped. Tests set it, since a service's name doesn't depend on HOME.
LNK_SECURITY/usr/bin/securityThe Keychain tool (tests). A stand-in turns the Keychain on anywhere.
NO_COLORunsetSet: no colors. Colors show only on a terminal.
CLICOLOR_FORCEunsetSet: colors even in a pipe or a file.
FileWhat it holds
~/.config/lnk/machine.toml (600)This machine's id and name; unsandboxed = false forbids running any agent without a sandbox here, whatever asks (a deployment's), and a file holding only that gets its id and name added; keep_moved is how long a moved agent's files stay ("30d", the default, or "never").

Agents (lnk agent)

lnk agent start passes each LNK_<NAME>_API, _CLI and _ENGINE variable it's run with (never one naming a key, token, secret, password or auth) to the agent's bridge service, for a channel plugin's tests.

VariableDefaultWhat it does
ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEYasked on the first lnk agent startThe provider's own key variable, read as --key is by lnk agent start, new and move. With no model yet, the one that is set (several set: --key); with a hosted model, its provider's, to renew the key. Never passed to a harness or to a box.
LNK_TELEGRAM_TOKENasked by lnk agent connect telegramThe bot token from BotFather.
LNK_TELEGRAM_APIhttps://api.telegram.orgTelegram's Bot API (tests).
LNK_SLACK_BOT_TOKEN, LNK_SLACK_APP_TOKENasked by lnk agent connect slackBot token (xoxb-...) and app-level token (xapp-...); both or neither.
LNK_SLACK_APIhttps://slack.com/apiSlack's Web API (tests).
LNK_DISCORD_TOKENasked by lnk agent connect discordThe Discord bot's token.
LNK_DISCORD_APIhttps://discord.com/api/v10Discord's HTTP API (tests); the Gateway's address comes from it.
LNK_WHATSAPP_NUMBER, LNK_WHATSAPP_OWNERasked by lnk agent connect whatsappThe agent's number and yours, with country code. The same twice for your own WhatsApp.
LNK_WHATSAPP_ENGINElnk-whatsapp engineOn Link Harness, the program that holds the WhatsApp device and speaks JSON lines (tests).
LNK_SIGNAL_NUMBER, LNK_SIGNAL_OWNERasked by lnk agent connect signalThe agent's number and yours, with country code; two different numbers.
LNK_SIGNAL_CLIthe signal-cli Link installsOn Link Harness, a signal-cli of your own to carry Signal with (tests); the account stays in ~/.config/lnk/agents/<agent>/channels/signal.
LNK_NO_BROWSERunsetSet: lnk agent connect opens no browser pages.
LNK_PORTset by lnk-harnessThe agent's base port, for harness adapters. Unset for main.
LNK_AGENTset by lnk-harnessThe agent's name, for harness adapters.
LNK_AGENT_IDset by lnk-harnessThe agent's ID, for harness adapters.
LNK_OWNERset by lnk-harnessThe agent's owner, for harness adapters.
LNK_MEASURESset by lnk-harnessFor harness adapters: the file in the harness's home it may append its own measures to, as OTLP (.link/measures.jsonl), which lnk measure reads.
LINK_FILESset by lnk-harnessThe agent's files folder, for harness adapters.
LNK_MEMORYset by lnk-harnessIn the harness's environment: its memory's address, an MCP server on its proxy.
LNK_MEMORY_MODELset by lnk-harnessIn a memory engine's environment: the address of the embedding model Link serves for it outside its sandbox, empty when no runtime here has it.
LNK_TOOL_<NAME>set by lnk sandbox wrapIn the harness's environment: each tool it may call, an MCP server on its proxy. Link Harness calls these and LNK_MEMORY.
FileWhat it holds
~/.config/lnk/agents/<name>.toml (600)An agent's settings (below). This machine's is main.
~/.config/lnk/agents/<name>/agent.toml (600)Its own spec, from lnk agent start --spec.
~/.config/lnk/agents/<name>/way-in.sock (600)The bridge's way in: messages for the agent from its schedules and subagents.
~/Link/Agents/<name>/Scheduler/Its scheduler's jobs, written by its tool, fired by its bridge.
~/.config/lnk/agents/<name>/owed/ (700)Where an answer to a message from others goes (its chat, another conversation, or nowhere), kept by the bridge until it went, so an answer finished after a crash goes there too; a subagent's conversation's is kept for its own subagents' answers.
~/.config/lnk/teams/<team>.tomlA team's file: its members, and the opinions they share (agent spec).
~/.config/lnk/agents/<name>/ (700)Its log, its foreground lock and its proxy's sockets.
~/.config/lnk/agents/<name>/sandbox.toml (600)What you grant the agent, whichever harness runs it (below).
~/.config/lnk/harnesses/<harness>.toml (600)What a harness said it needs here and you allowed, for every agent that runs it (below).
~/.config/lnk/agents/.net/<id>/url.secret (600)The agent's proxy secret, in its tool and local model URLs, by the agent's ID.
~/.config/lnk/agents/.net/<id>/<harness> (700)Sockets between the harness's network and its proxy; <harness>-<step> for a setup step's (install, configure, health, ...).
~/.config/lnk/agent-defaults.toml (600)The proxy upstream each new agent here starts with.
~/.config/lnk/moved/<id>.toml (600)A note left when an agent moved away.
~/Link/Agents/.moved/<name>-<date>A moved agent's files folder, kept 30 days, or as machine.toml's keep_moved says.
~/Link/Agents/.incoming (700)An arriving agent, before it's put in place.
~/.config/lnk/agents/<name>/bridge.json (600)For a harness with an endpoint, such as Link Harness: its endpoint, key, proof and channels. Made at each start.
~/.config/lnk/agents/<name>/bridge.logThe log of the channels Link carries.
~/Link/Agents/<name>/Harnesses/link/config.json (600)Link Harness's model and endpoint key, read at each message; written at each start.
<files>/Instructions.mdOptional: what Link Harness is told to be, read at each message.
<files>/Conversations/<thread>/Link Harness's conversations: a file per message, conversation.md, and window.json (where the model's window starts).
~/Link/Agents/<name>/Memory/<engine>/ (700)Its memory engine's state and HOME, such as Link Memory's index.sqlite.
~/.config/lnk/sandbox/tools/memory-<id>.json (600)Its memory, as a tool (lnk agent memory use), by the agent's ID. Defined again at a start only when something it's made from changed.
~/.config/lnk/agents/<name>/memory.jsonWhat the memory tool was last defined from, so a start with nothing changed leaves it as it is.
~/.config/lnk/agents/<name>/ports.jsonThe harness's ports at its last start, which lnk agent status shows.
<harness home>/.lnk-configuredA hash of the settings, versions and files the last configure left, so a start with nothing changed skips it. Delete it to configure again.
<harness home>/...What a harness from outside Link keeps there: its repository's README says.

An agent's settings (agents/<name>.toml)

Each key is changed by an lnk agent command (start, connect, exit, use, memory); edit them there, not in the file.

KeyWhat it holds
idThe agent's ID, which never changes and moves with it.
ownerWhose it is: the account signed in (github-<user id>), or before you sign in, <user>@<machine>, which the account replaces at its next start. Left out, the latter.
port, blockIts first port and how many from there are its harness's (left out: 200); none for main.

An agent's grants (agents/<name>/sandbox.toml)

What you grant the agent, whichever harness runs it. Changed by lnk agent allow and deny, or written whole by lnk agent start --sandbox <file>; lnk agent permissions shows them. An agent without a file has Link's defaults. A key or permission Link doesn't know is an error.

KeyWhat it holds
permissionsIts permissions; left out, network and developer-tools.
hostsThe only hosts its proxy lets it reach; none, any.
tcpEndpoints beyond HTTPS and HTTP, host:port.
toolsTools that run outside it may call.
callsThe most calls a minute on its proxy; none, no limit.

A harness's grants (harnesses/<harness>.toml)

What the harness said it needs (lnk-<harness> needs) and you allowed, held while it runs, for every agent here that runs it. Changed by answering what it asks, by lnk agent <harness> allow and deny (only for what it asks for), and by repermit; lnk agent <harness> permissions shows them. A harness without a file needs nothing.

KeyWhat it holds
permissionsThe permissions it asked for that you allowed.
unsandboxedtrue: it runs with no sandbox at all.
risksRisks of its own it named that you allowed (browser).
answeredThe needs it asked for that you answered, not asked again until repermit.

Sandbox (lnk sandbox)

A program run by lnk sandbox run keeps only PATH, HOME, TERM, COLORTERM, LANG, LC_ALL, LC_CTYPE, TZ, USER, LOGNAME and SHELL from your shell.

VariableDefaultWhat it does
LNK_MCP_HEADER_<n>set by lnk sandbox tool add --headerIn a tool at a URL's environment, outside: a header it sends, Name: value.
LNK_TEST_ON_CLOUDunset1: the sandbox takes this machine for a cloud's, refusing [lan] what it refuses there (tests). Nothing makes a cloud's machine not one.
LNK_SANDBOX_LEARN_FDset by lnk sandbox learnInto the sandbox, for its first program, which removes it: the descriptor it writes each program started to. A program inside that sets it only records what it runs itself.
FileWhat it holds
~/.config/lnk/sandbox/ (700)The rules, one Seatbelt profile per policy.
~/.config/lnk/sandbox/<name>.model.json (600)A proxied policy's model provider and key, which its proxy adds.
~/.config/lnk/sandbox/<name>.secret-<secret>.json (600)A proxied policy's secret (a Telegram bot's token) and its rule, which its proxy adds.
~/.config/lnk/sandbox/<name>.url-secret (600)The secret a proxied policy's tool and local model URLs carry, which its proxy requires.
~/.config/lnk/sandbox/wire.log (600)lnk sandbox log: one JSON object per proxied call.
~/.config/lnk/sandbox/traffic/<pid>.json (600)lnk sandbox traffic: the bytes a running proxy has carried each way, written every 5 seconds while it changes; removed once its proxy is gone.
~/.config/lnk/sandbox/asks/<id>.json (600)A question a proxy is waiting on (lnk sandbox asks).
~/.config/lnk/sandbox/tools/<name>.json (600)A tool that runs outside (lnk sandbox tool add): its command, or mcp-remote and its URL, and its environment, headers included.
~/.config/lnk/sandbox/settings.tomlThe sandbox plugin's settings, over Link's: ask_wait, how long a question waits for your answer ("120s"; silence is no), tool_starts, the tool servers starting at once (2), and tool_sessions, the tool sessions one sandbox keeps (8). A file that can't be read is said, and Link's are used.
~/.config/lnk/sandbox/stoppedWhile it exists, every proxy refuses every call.
~/.config/lnk/sandbox/paused/<sandbox> (600)While it exists, that sandbox's proxy refuses every call.
~/.config/lnk/sandbox/placeholders.json (600)Linux: the empty placeholders made where a project's dot file isn't, while sandboxes run, and which runs hold each; removed with the last.
~/.config/lnk/sandbox/bwrap-versionLinux: whether this machine's bubblewrap can refuse user namespaces inside, so a sandbox doesn't ask it each run.
~/.config/lnk/sandbox/guests.toml (600)lnk sandbox guest: each guest's settings, or their spec (--spec), its paths absolute.
~/.config/lnk/specs/sandbox.toml (600)The sandbox specs run here, each by its path and a hash of what it opens (spec).

Models (lnk model)

No environment variables. The models plugin finds runtimes at their default ports and at the addresses you add, each time; --upstream points one command at any other.

FileWhat it holds
~/.config/lnk/models.toml (600)lnk model add: each added runtime's name and base_url.
~/.config/lnk/model-facts.tomlYours, optional: models you describe or correct ([model."<name>"]: window, answer, thinking, price), over Link's own, field by field (lnk model facts).

Accounts (lnk auth)

VariableDefaultWhat it does
LINK_RELAYthe relay you logged in to (login: https://local.link)Relay to use (--relay), e.g. http://localhost:7080.
LINK_TOKENyour login'sToken for the relay, from which lnk bucket share gets a short-lived one.
LNK_CONFIG~/.config/lnk/config.tomlWhere the saved login lives.
LNK_NO_BROWSERunsetSet: lnk auth login prints the URL without opening it.
LNK_LOGIN_TICKETunsetA confirmation given ahead by a machine signed in (lnk auth ticket --json): lnk auth login, once approved in the browser, needs no lnk auth approve. lnk box start sets it on the box.
FileWhat it holds
~/.config/lnk/config.toml (600)The relay, username, token and GitHub user_id from lnk auth login. Only the accounts plugin reads it.

Tunnel (lnk tunnel)

VariableDefaultWhat it does
LINK_RELAYthe relay you logged in to, else https://local.linkRelay to use (--relay), e.g. http://localhost:7080.
LINK_TOKENyour login's (lnk auth)Token for the relay (--token).
LINK_AUTHnoneuser:password visitors must give (lnk tunnel open --auth).
RUST_LOGlink=infoLog level of lnk tunnel open, e.g. link=debug.

Buckets (lnk bucket)

VariableDefaultWhat it does
LNK_PERSONAL_DIR~/Link/PersonalYour files folder, an absolute path.
LNK_RCLONEthe pinned rclone in ~/.config/lnk/bucket/engineRun this rclone instead, unchecked (tests).
RCLONE_*—Removed before running rclone.
AWS_*, GOOGLE_APPLICATION_CREDENTIALS—Removed before running rclone on a bucket that signs in as a lnk cloud account (aws, gcp).
GOOGLE_APPLICATION_CREDENTIALS~/.config/gcloud/application_default_credentials.jsonAlso read, for such a gcp bucket set up with env_auth: the key file it signs in with.
LINK_AUTHnoneuser:password for lnk bucket share --auth and lnk bucket pull <link>.
FileWhat it holds
~/.config/lnk/bucket/clouds.tomlThe connected clouds and each folder's bucket.
~/.config/lnk/bucket/rclone.conf (600)Each cloud's settings and encryption passwords, and the keys of those that don't sign in as a lnk cloud account (s3, rclone types, a box's key for one agent).
~/.config/lnk/bucket/rclone-keychain.tomlOn a Mac: which settings of which section of rclone.conf are in the Keychain.
~/.config/lnk/bucket/manifest-personal.json, manifest-<agent id>.json (600)What went where: a cache tree reads, and what clean proved of S3 copies, so it reads each back once.

Boxes (lnk cloud, lnk box)

VariableDefaultWhat it does
AWS_PROFILE, AWS_REGION, AWS_DEFAULT_REGION—Read once by lnk cloud connect aws: the login to reuse and its region.
CLOUDSDK_CONFIG~/.config/gcloudgcloud's own settings, as gcloud reads them: lnk cloud connect gcp asks gcloud where its login is.
LNK_AWS, LNK_GCLOUDaws, gcloud on the PATH, else the ones lnk cloud connect installedThe cloud CLIs the adapters run (tests).
LNK_SSH, LNK_SSH_KEYGENssh, ssh-keygen on the PATHWhat lnk box runs (tests).
LNK_BOXset by lnk box setupIn a setup script's environment: the box it sets up.
FileWhat it holds
~/.config/lnk/cloud/accounts.toml (600)The connected accounts, and what each cloud's CLI needs to act as them.
~/.config/lnk/aws/, ~/.config/lnk/gcp/ (700)The AWS CLI and gcloud, when lnk cloud connect installed them.
~/.config/lnk/gcp/credentials/<name>.json (600)A Google Cloud account's credential file: a service account's key, or your login's application default credentials.
~/.config/lnk/box/ (700)The boxes, Link's SSH key for them, their host keys, and lock files.
~/.config/lnk/box/boxes.toml (600)This computer's boxes, each with the spec it was made from (lnk box spec).
~/.config/lnk/box/mux/ (700)The sockets of the SSH connections to boxes kept open for a minute after a lnk box run.
~/.config/lnk/machine.toml on a boxIts machine ID and name, written by lnk box start.

In the cloud, each box's machine is named lnk-<machine id> and tagged (labelled on Google Cloud) lnk-box=<name>, lnk-machine=<machine id> and lnk-owner=github-<your GitHub user id>. The host keys pinned at its first boot are kept on it: metadata lnk-host-keys on Google Cloud, a lnk-host-key tag on AWS. A spec's own tags are added to those, at most 40; on AWS its disk has them too, and a spot box's request.

An image lnk box image save makes is named lnk-<name> in the box's account and tagged (labelled) lnk-image=<name> and lnk-owner=github-<your GitHub user id>, and lnk-hash=<hash> when saved with --hash; on AWS its snapshot has them too. Nothing about images is kept on your computer.

A box spec's every field and default: box spec.

VPN (lnk vpn)

No environment variables.

FileWhat it holds
~/.config/lnk/vpn/exits.toml (600)The exits this computer keeps: each machine, how it's reached, who holds it, and who takes it on the socket rather than the port.
~/.config/lnk/vpn/<machine>.log (600)Each exit's log.
~/.config/lnk/vpn/exit.sock (600), on the machineThe exit's SOCKS proxy, while it's up; left behind when it drops, and removed when it connects again.

Measures (lnk measure)

No environment variables.

FileWhat it holds
~/.config/lnk/measure/settings.toml (600)Your settings (lnk measure settings): every, fine and minutes, each a duration (10s, 1d), processes (whether each agent's processes are kept too), and [export], your endpoint's url and its headers. What it leaves out is Link's: a look every 10s, each kept 1d, a minute's summary kept 30d, processes not kept.
~/.config/lnk/measure/fine/<yyyy-mm-dd-hh>.jsonl (600)Each look in that hour (UTC): the machine and each agent, a line each look.
~/.config/lnk/measure/minutes/<yyyy-mm-dd>.jsonl (600)A summary of each minute of that day.
~/.config/lnk/measure/offsets.json (600)Where the watcher stopped reading each harness's file.
~/.config/lnk/measure/watch.log, watch.lockThe watcher's log, and the lock that keeps it to one.
.link/measures.jsonl in a harness's homeWhat the harness reports of itself (LNK_MEASURES); moved aside to measures.jsonl.1 past 1 MiB.

The core (lnk) and install.sh

VariableDefaultWhat it does
LNK_RELEASES_URLhttps://github.com/woodpav/link-releases/releasesWhere releases are downloaded from (tests). Signatures are still checked.
LNK_GITHUB_URLhttps://github.comWhere a plugin from outside Link is downloaded from in place of GitHub (tests). Its pinned key is still checked.
FileWhat it holds
~/.config/lnk/plugins.toml (600)Each plugin added from outside Link (lnk plugin add <url>): its source, the repository, and the key its releases must be signed with. Also noted: programs beside lnk that lnk upgrade has said once how to keep updated.

install.sh also reads:

VariableDefaultWhat it does
LNK_INSTALL_DIR~/.local/binWhere lnk goes; plugins go next to it.
LNK_VERSIONlatestA version, e.g. 0.11.0. Below 0.11 gives an lnk without plugins.
LNK_INSECUREunset1: install without ssh-keygen, so without checking the signature.

The relay and its deploy

Each setting is a flag, and most can also come from a variable. On a server, bootstrap.sh writes them to /etc/link/relay.env (root-only), which the systemd unit loads. Change one with bootstrap's flag, or edit the file and run systemctl restart link-relay.

VariableFlagDefaultWhat it does
LINK_DOMAIN--domainlocalhost:7080Public base domain, with a port if non-standard. Tunnels are <app>.<user>.<domain>.
LINK_USERS_FILE--users-filenoneFile of <username> <token> lines. Required unless GitHub login is on, or the relay runs locally (a localhost domain on a loopback address).
LINK_STATE_DIR--state-dirnoneWhere login users, blocks, share links and the hosts approved for certificates are saved.
LINK_GITHUB_CLIENT_ID--github-client-idnone (login off)A GitHub OAuth app with device flow. Turns on lnk auth login.
LINK_GITHUB_CLIENT_SECRET--github-client-secretnone (device flow)The app's secret: web flow and the relay's approval page.
LINK_GITHUB_ALLOW--github-allowempty (nobody)GitHub usernames who may log in, comma-separated, or *.
LINK_GITHUB_MIN_AGE_DAYS--github-min-age-days30Minimum GitHub account age for signups through *. 0: off.
LINK_SIGNUPS_PER_DAY--signups-per-day100Signups through * per 24 hours, for everyone. 0: off.
LINK_WEBSITE--websitenone (404)Where browsers on the bare domain go, e.g. https://www.local.link.
LINK_NOTICE--noticenoneA message shown to every lnk that connects.
LINK_TOKEN--tokendev-tokenLocal development only: the single user dev's token.
LINK_GITHUB_API--github-apihttps://api.github.comFor tests (hidden).
LINK_GITHUB_URL--github-urlhttps://github.comFor tests (hidden).
—--listen127.0.0.1:7080Address to listen on. Keep it on loopback behind Caddy.
—--public-schemehttps, or http for localhostScheme of public URLs.
RUST_LOG—link=infoLog level, e.g. link=debug.

On a server, the systemd unit (src/server/deploy/files/link-relay.service) also limits the relay's open files, memory, threads, system calls and sockets: the server's security. Bootstrap installs it; re-run bootstrap after changing it.

Off-site backups (/etc/link/backup.env)

Read by link-state backup, which runs nightly. Without this file, snapshots stay only on the server, in /var/backups/link. On your Mac, the same file is what fetch-backup.sh --env reads. Setup is in the runbook.

VariableDefaultWhat it is
LINK_BACKUP_URL—<S3 endpoint>/<bucket>, e.g. https://storage.googleapis.com/backups
LINK_BACKUP_REGIONautoThe bucket's region: auto for Google Cloud Storage, us-east-1 for AWS, ...
LINK_BACKUP_KEY_ID—Access key id, for that bucket only.
LINK_BACKUP_SECRET—Its secret.

Uploads are encrypted to the public keys in /etc/link/backup-recipients, one ssh-ed25519 …, ssh-rsa … or age1… key per line. Without a key there, the backup refuses to upload.

Deploy scripts

The scripts in src/server/deploy. When to run each is in the runbook.

bootstrap.sh, on the server as root, piped from your checkout (ssh root@host 'bash -s -- <flags>' < src/server/deploy/bootstrap.sh). Settings marked "kept" are saved in /etc/link/relay.env and stay on later runs.

FlagWhat it does
--domain DPublic domain. Required on the first run; kept.
--email ELet's Encrypt contact for Caddy. Required on the first run, and to install a changed Caddyfile.
--user NAMECreate this user if there's no users file yet; prints its token once.
--github-client-id IDTurn on lnk auth login with this GitHub OAuth app; kept.
--github-allow LISTGitHub usernames who may log in, comma-separated, or *; kept.
--website URLRedirect browsers on the bare domain to this site; kept.
--state FILERestore a link-state export snapshot (users, settings, certificates) first. It keeps the server's release key and version floor.
--min-version VRefuse a release whose relay is older than V, and keep the highest given in /etc/link/min-relay-version as the updater's floor.
--from DIRInstall the deploy files in this folder on the server, a copy of src/server/deploy/files, with no signature check.

create-droplet.sh, on your Mac. Needs doctl, logged in, and an SSH key on the DigitalOcean account. It creates a droplet and runs this checkout's bootstrap on it, with --min-version set to the checkout's version.

FlagDefaultWhat it does
--domain Dlocal.linkPublic domain.
--email E—Let's Encrypt contact. Required unless --state.
--user NAME—First user; its token is printed. Required unless --state.
--state FILE—Restore users, settings and certificates from a snapshot.
--reserved-ip IP—Point this DigitalOcean reserved IP at the new droplet.
--name Nlink-relay-<date>Droplet name.
--region Rnyc1Droplet region.
--size Ss-1vcpu-512mb-10gbDroplet size.
--ssh-keys IDSevery key on the accountComma-separated key ids or fingerprints.

rebuild.sh, on your Mac: --old IP (the droplet to replace) and --reserved-ip IP, both required. Any other flag goes to create-droplet.sh.

fetch-backup.sh, on your Mac. Needs age.

FlagDefaultWhat it does
--env FILE—The same settings as /etc/link/backup.env. Required.
--identity FILE~/.ssh/id_ed25519Private key matching a line of backup-recipients.
--name NAMEstate-latest.tar.gz.ageA specific backup, e.g. state-20260926T031500Z.tar.gz.age.

Environment variables, mostly for testing the scripts:

VariableUsed byDefaultWhat it does
LINK_RELEASES_URLbootstrap.sh, create-droplet.sh (passes it on), link-relay-updatethe relay-latest release of woodpav/link-releasesWhere relay builds and deploy files come from. They must still be signed by the release key.
LINK_RELEASE_SIGNERSlink-relay-update/etc/link/release-signersPublic keys a release must be signed with.
LINK_RELAY_BINlink-relay-update/usr/local/bin/link-relayThe binary it replaces.
LINK_UPDATE_STATElink-relay-update/var/lib/link-updateReleases it skips: failed health checks (bad), older ones (older).
LINK_ALLOW_DOWNGRADElink-relay-updateunset1: install relay-latest even if older than the installed relay or the floor, or if the installed version can't be read.
LINK_MIN_RELAY_VERSIONlink-relay-update/etc/link/min-relay-versionFile with the oldest relay version it installs, written by bootstrap.
LINK_STATE_ROOTlink-state/Root the state paths are relative to.
LINK_NO_RESTARTlink-state, link-relay-updateunset1: don't stop and start Caddy and the relay.