Skip to content

Installation

Install the Localport agent on macOS, Linux, or Windows. One binary, no dependencies, checksum verified. Homebrew, install script, manual download, or source.

Summary

The Localport agent is a single binary with no runtime and no dependencies. Install it with one command, verify it against the published checksums, or build it yourself from source. It runs on macOS, Linux, and Windows, on Intel and ARM.

Run the command for your operating system.

Install with Homebrew:

brew install localport/tap/localport

Or use the install script:

curl -fsSL https://localport.io/install.sh | sh

A mismatched checksum aborts the install. On macOS and Linux the binary lands in /usr/local/bin, falling back to ~/.local/bin when that is not writable, and sudo is used only when it is needed. The script changes nothing else: no shell profile, no background service, no telemetry. Both are short enough to read first, at install.sh and install.ps1.

The same command installs and upgrades. On a machine that already has the agent, the script replaces the binary at the path it already occupies, so you never end up with two copies. If that binary is already the release being installed, the script says so and downloads nothing.

An agent that a package manager put there is left alone. The script recognises Homebrew, Nix, Snap, apt, dnf, pacman and apk on macOS and Linux, and Scoop, Chocolatey and winget on Windows. It stops and prints that manager's own upgrade command. Overwriting files a package manager owns leaves it out of step, and its next upgrade puts its own build back.

After installing, the script checks which localport your shell resolves. If an older copy sits earlier on your PATH, it names that file so you can delete it.

An agent installed by an earlier version of the script is found and upgraded even when your PATH does not reach it. The one exception is an install you placed somewhere custom with LOCALPORT_INSTALL_DIR: set the same variable again to upgrade it, or the script treats the machine as a fresh install.

Three environment variables change what gets installed and where.

VariableEffect
LOCALPORT_VERSIONInstall a specific release tag instead of the latest stable
LOCALPORT_INSTALL_DIRInstall to a directory you choose, on macOS, Linux and Windows
LOCALPORT_FORCEReinstall even when the installed binary is already current
LOCALPORT_INSTALL_DIR="$HOME/bin" curl -fsSL https://localport.io/install.sh | sh

Pin the version on servers and in CI images

Set LOCALPORT_VERSION to a release tag. On a machine you rebuild often, an unexpected version change is worse than an old version.

Install manually from a release#

Every release publishes the binaries and a checksums.txt covering all of them.

Verify it against checksums.txt, then install it. macOS adds a quarantine flag to anything downloaded from a browser, which xattr clears:

shasum -a 256 --ignore-missing -c checksums.txt
chmod +x localport-darwin-*
xattr -d com.apple.quarantine localport-darwin-*
sudo mv localport-darwin-* /usr/local/bin/localport

Build it from source#

The agent is the only part of Localport that runs on your machine, and its source is public under the Apache 2.0 licence. Building it yourself takes two commands.

Requires Go 1.25 or newer.

git clone https://github.com/localport/agent.git
cd agent
make build
./bin/localport version

make build-all cross-compiles every published platform into bin/. Releases are built with -trimpath from the same targets, so a binary you build matches the one we publish in behaviour and origin.

Run the agent as a background service#

A tunnel is live only while the agent is running. On a laptop you leave it in a terminal. On a server, a device in the field, or a box at home, you want it started at boot and restarted if it stops.

The repository ships both service templates, already hardened.

Take deploy/localport.service from the repository.

sudo useradd --system --no-create-home --shell /usr/sbin/nologin localport
sudo install -d -m 0700 -o localport -g localport /etc/localport
printf '%s' 'tok_...' | sudo tee /etc/localport/token >/dev/null
sudo chmod 0600 /etc/localport/token
sudo cp localport.service /etc/systemd/system/
sudo systemctl enable --now localport

Edit the ExecStart= line to match the service you are forwarding, then check it with systemctl status localport and journalctl -u localport -f.

The token is never put on the command line. systemctl show, ps, and the unit file itself are readable by every local account, so a token in ExecStart= is a token every user on that machine has. The unit uses systemd's LoadCredential=, which places the token at a file readable only by the service user, and points LOCALPORT_TOKEN_FILE at it. The unit also runs unprivileged with ProtectSystem=strict, NoNewPrivileges=true, and a restricted set of address families.

Run the agent in a container#

Localport does not publish a container image. The agent is a self-contained binary, so a short Dockerfile is all it needs. The ca-certificates package matters: the agent verifies the Localport server against the system trust store, and a bare image has no roots to verify against.

Download and check the binary first, using the commands in the section above, then copy the verified file into the image. A build step that fetches a binary and does not check it breaks the chain everything else here maintains.

FROM alpine:3
RUN apk add --no-cache ca-certificates
COPY localport-linux-amd64 /usr/local/bin/localport
RUN chmod +x /usr/local/bin/localport
ENTRYPOINT ["localport"]

Pin the base image to whatever digest your policy requires.

docker run --rm -e LOCALPORT_TOKEN=tok_... my-localport \
  http 3000 --local http://host.docker.internal:3000 --region eu

Pass the token as an environment variable or a Docker secret. An argument shows up in docker inspect and in a process listing. A container reaching a service on the host needs host.docker.internal on macOS and Windows, or --network host on Linux.

Verify, upgrade, and remove#

localport version

That prints the version, the commit it was built from, and the build date. localport --version does the same. If your shell says the command was not found, the install directory is not on your PATH: /usr/local/bin on macOS and Linux, ~/.local/bin when the script fell back to it, and %LOCALAPPDATA%\Programs\localport on Windows.

Upgrading is the same command you installed with. Homebrew uses brew upgrade localport. The install script finds the binary your shell resolves, compares it against the release you asked for, and replaces it only if the two differ. Set LOCALPORT_FORCE=1 to reinstall a binary that is already current. Running tunnels keep going on the version they started with until you restart the agent.

Removing it is deleting the binary. brew uninstall localport for Homebrew, otherwise sudo rm /usr/local/bin/localport, or delete the folder under %LOCALAPPDATA%\Programs on Windows.

If this machine holds credentials from localport setup or localport login, clear them too: localport identity remove <selector> for one, or delete ~/.localport for all of them.

Deleting a credential does not revoke it

The certificate stays valid until you revoke it in the dashboard. If the machine is being decommissioned or has been lost, revoking is the step that matters. See Certificates.

Frequently asked questions#

Which operating systems and processors does the agent support?

macOS on Apple Silicon and Intel, Linux on x86_64 and ARM64, and Windows on x86_64. Those five builds are published for every release. Other platforms that Go targets can be built from source.

Do I need administrator or root access to install it?

No. On Windows the script installs to your user profile and needs no elevation at all. On macOS and Linux it uses sudo only to write to /usr/local/bin, and falls back to ~/.local/bin in your home directory when that is not available. You can also set LOCALPORT_INSTALL_DIR to any directory you can write to.

How do I check the binary I downloaded has not been tampered with?

Every release publishes a checksums.txt listing the SHA-256 of each binary. The install script compares it automatically and aborts on a mismatch. To check a manual download, run sha256sum --ignore-missing -c checksums.txt on Linux, shasum -a 256 --ignore-missing -c checksums.txt on macOS, or Get-FileHash on Windows.

Does the agent install a background service or a system extension?

No. Installing puts one binary on disk and nothing else. There is no daemon, no launch item, no kernel extension, and no telemetry agent. It runs when you run it. Setting it up to start at boot is a separate, deliberate step covered above.

Can I install it without a package manager or an install script?

Yes. Download the binary for your platform from the releases page, verify its checksum, make it executable, and put it somewhere on your PATH. It has no dependencies to resolve, so nothing else is required.

Does it run on a Raspberry Pi or another single-board computer?

Yes, on a 64-bit operating system, using the linux-arm64 build. That covers a Raspberry Pi 3 or newer running current Raspberry Pi OS. A 32-bit image needs to be reimaged or the agent built from source for that target.

Where does the agent store its files?

Only credentials, and only if you create some. localport setup and localport login write to ~/.localport, with directories at mode 0700 and files at 0600. Set LOCALPORT_HOME to move that elsewhere. The service templates set it so a system account has somewhere to write. A tunnel that authenticates with a token alone writes nothing.

How do I upgrade to a new version?

Run the install script again, or brew upgrade localport if you installed with Homebrew. The script upgrades the binary where it already sits, and exits without downloading when that binary is already the version being installed. Nothing is migrated and no configuration is rewritten. A running agent keeps using the version it started with until you restart it.

Why did the install script refuse to upgrade my Homebrew copy?

Because Homebrew owns that file. Replacing it would point Homebrew's records at a build that is no longer there, and brew upgrade would put its own build back the next time it ran. Run brew upgrade localport to update it. If you want a copy the install script manages, set LOCALPORT_INSTALL_DIR to a directory you own and install there. The same applies to Nix, Snap, apt, dnf, pacman, apk, Scoop, Chocolatey and winget.

Can I pin a specific version instead of the latest?

Yes. Set LOCALPORT_VERSION to a release tag before running the install script, on both macOS and Linux and Windows. This is what to do on production machines and in CI images, where an unexpected version change is worse than an old version.

Can I audit what the agent does before running it on a work machine?

Yes, and this is the intended path for anyone who has to justify it. The agent's full source is on GitHub under Apache 2.0, builds with make build on Go 1.25, and is the only Localport component that runs inside your network. Its wire protocol is documented in the same repository.

  • Quick Start. Create a tunnel and reach it from the internet.
  • CLI. Every command, flag, and environment variable.
  • Configuration. Run several tunnels from one YAML file.
  • HTTP Tunnels. Web apps, APIs, and webhook endpoints.
  • Remote Access. Require a client certificate to connect.