Skip to content
ConduitConduit

Tunnels — quickstart

You can have your on-prem systems reachable through Conduit in a few minutes. conduit-tunnel is a single static Go binary (~12 MB) that runs as a service, dials the WYRE relay over WSS (outbound only — no inbound ports), and comes online empty. Which connectors run and how they’re configured is set in Conduit — from your tunnel’s page under Connections → Tunnels (or by your Conduit operator) — and pushed down the tunnel; the Tunnel holds that config in memory only.

  • A Linux host with systemd, or a Windows host — the PowerShell installer sets the Tunnel up as a Windows service (optionally under a gMSA for zero-credential SQL auth).
  • Nothing to pre-download — the install script below pulls the binary from the public conduit-tunnel releases. (The Windows build in each release is Authenticode-signed.)
  • Two values from your Conduit operator: your RELAY_URL (a wss:// host) and your enrollment token — an identity-only JWT that binds your org and carries no capabilities.
Section titled “1. Install with the one-line script (recommended)”

Conduit itself serves the install command — it pins the currently supported release and bakes in the right relay URL server-side, so the only thing you supply is the token. It does steps 1–4 below in one command:

Terminal window
curl -fsSL https://conduit.wyre.ai/get/tunnel.sh | sudo ENROLLMENT_TOKEN=<identity-only JWT> bash

This is the same command the Add Tunnel panel shows with the token already filled in — copying it from there is the least-typing path.

  • The script downloads the release binary, installs a hardened systemd service, and starts it — settings come from the environment, so an RMM can run it unattended.

  • To pin a different version or install air-gapped, call the upstream installer directly:

    Terminal window
    curl -fsSL https://raw.githubusercontent.com/WYRE-AI/conduit-tunnel/v0.4.0/install.sh | \
    RELAY_URL=wss://conduit-wss.wyre.ai \
    ENROLLMENT_TOKEN=<identity-only JWT> \
    CONNECTOR_VERSION=v0.4.0 \
    bash

    (CONNECTOR_URL=<direct-url> points an air-gapped host at an internal mirror instead.)

  • If the one-liner worked, skip to step 5 — the service is already running. The manual steps below are for when you want to place the binary and unit yourself (air-gapped hosts, custom paths).

Same idea on Windows — Conduit’s install route pins the version and relay for you; the wrapper downloads the Authenticode-signed binary, installs it as a Windows service, and starts it:

Terminal window
& ([scriptblock]::Create((irm https://conduit.wyre.ai/get/tunnel.ps1))) -Token '<identity-only JWT>'

To run the service under a gMSA — required for SQL Server Windows Integrated Auth, the zero-stored-credential path — call the upstream installer directly, which takes the extra parameter:

Terminal window
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/WYRE-AI/conduit-tunnel/v0.4.0/install.ps1))) `
-EnrollmentToken '<identity-only JWT>' `
-RelayUrl 'wss://conduit-wss.wyre.ai' `
-Version 'v0.4.0' `
-ServiceAccount 'DOMAIN\gmsa$'

Both installers read their settings from parameters/environment so an RMM can run them unattended.

1b. (Manual alternative) Install the binary

Section titled “1b. (Manual alternative) Install the binary”

Download the Tunnel and drop it in place:

Terminal window
# Replace <download-url> with the release asset your operator/WYRE gives you.
sudo curl -fsSL <download-url> -o /usr/local/bin/conduit-tunnel
sudo chmod +x /usr/local/bin/conduit-tunnel

Create /etc/conduit-tunnel/env with your two required vars (plus an optional log level). Lock it down to 600 so the token isn’t world-readable:

Terminal window
sudo install -d -m 700 /etc/conduit-tunnel
sudo tee /etc/conduit-tunnel/env >/dev/null <<'EOF'
RELAY_URL=wss://conduit-wss.wyre.ai
ENROLLMENT_TOKEN=<identity-only JWT from your operator>
LOG_LEVEL=info
EOF
sudo chmod 600 /etc/conduit-tunnel/env
  • Production RELAY_URL is wss://conduit-wss.wyre.ai; staging is wss://staging-wss.conduit.wyre.ai. It must be wss://.
  • There is no CAPABILITIES variable. The Tunnel comes online empty and gets its connectors from Conduit. If you set CAPABILITIES, the Tunnel fails to boot on purpose (see the caution below).

Save this as /etc/systemd/system/conduit-tunnel.service:

/etc/systemd/system/conduit-tunnel.service
[Unit]
Description=Conduit Tunnel (dials out only; no inbound ports)
After=network-online.target
Wants=network-online.target
[Service]
EnvironmentFile=/etc/conduit-tunnel/env
ExecStart=/usr/local/bin/conduit-tunnel
Restart=always
RestartSec=5
DynamicUser=yes
NoNewPrivileges=yes
ProtectSystem=strict
[Install]
WantedBy=multi-user.target
Terminal window
sudo systemctl daemon-reload
sudo systemctl enable --now conduit-tunnel
sudo journalctl -u conduit-tunnel -f

You should see the Tunnel register:

tunnel registered (v2, zero capabilities until config push)

That’s the Tunnel online and empty — exactly as expected. It binds no inbound port; the outbound WSS is its only connection.

Enable and configure the connectors you need in Conduit — the config is encrypted at rest and pushed down the tunnel. Two ways:

  • Self-service (recommended): in Conduit, go to Connections → Tunnels — a list of every tunnel your org has registered (name, live status, last seen). Click into yours to reach its status and configure page, where you enable connectors — echo (connectivity proof), mssql/postgres/mysql (read-only SQL), or a Generic MCP server (front any local MCP server, e.g. Veeam) — filling in each one’s endpoint and credentials. The same list page is also where you mint a new enrollment token (the “Add Tunnel” panel) for a fresh deploy, rename a tunnel, or disable/delete one you’re retiring.
  • Operator / admin API: your Conduit operator can do the same via the admin API.

Within moments you’ll see:

config applied connectors=[echo, mssql]

The applied connectors are now reachable from /v1/mcp for any authenticated client whose primary org is yours. If the Tunnel restarts, Conduit re-pushes the stored config automatically (within ~60s) — no manual step.


Already-deployed sites run the v1 conduit-onprem-gateway Docker container, which is still supported. It uses the older model: capabilities come from a CAPABILITIES env var and are baked into the enrollment token (not pushed from Conduit). New deployments should use the Tunnel above; this section is here so existing sites can keep operating and redeploy the way they were set up.

The image is pinned to a specific @sha256:... digest — the supply-chain verification gate. Do not change it to :latest. The current digest is published in the latest GitHub release notes.

docker-compose.yml:

services:
onprem-gateway:
image: ghcr.io/WYRE-AI/conduit-onprem-gateway@sha256:ee80a6305df168e53a6e7c41b949bdacada021dd29a11b73c53c625e5e1e84d4
restart: unless-stopped
env_file:
- .env
# NO `ports:` clause — the gateway is outbound-only (assertNoInbound enforces zero LAN-listening).

.env (gitignore it — echo ".env" >> .gitignore):

RELAY_URL=wss://<your-WYRE-relay-host>
ENROLLMENT_TOKEN=<paste-the-JWT-your-Conduit-operator-gave-you>
CAPABILITIES=echo

Bring it up and watch the logs:

Terminal window
docker compose up -d
docker compose logs -f onprem-gateway

Ready line:

on-prem-gateway ready: dialing wss://<your-WYRE-relay-host> with capabilities=[echo]

The v1 container image is signed via cosign keyless GHA OIDC. To verify the image you pulled matches what WYRE published:

Terminal window
cosign verify ghcr.io/WYRE-AI/conduit-onprem-gateway@sha256:<digest> \
--certificate-identity-regexp 'https://github.com/WYRE-AI/conduit/.github/workflows/release-onprem-gateway.yml@.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

A successful verify confirms the image was built by WYRE’s published release workflow. Cosign image verification applies to the legacy container; the Tunnel’s Windows binary is Authenticode-signed in every release (verify the publisher is WYRE AI), and each release ships a SHA256SUMS for the Linux binaries. See Architecture Context — Image Verification.