SIMSY + Tailscale | Put your SIMs on your tailnet | SIMSY Developers
Back to tools
SIMSY + Tailscale

Put your SIMs on your tailnet

Run the SIMSY Tailscale bridge and every device on your SIMSY VSlice answers on your tailnet at its SIM address. People and services reach the devices through your existing Tailscale policy; the devices reach the services you allow. Nothing is installed on the devices, so locked-down modules, PLCs and sensors work the same as anything else.

Six things the integration delivers

Your whole fleet, one route

The bridge joins your tailnet as one tagged node and advertises your VSlice’s SIM range. Every device on the VSlice is reachable at its SIM address, whether you have five in a lab or thousands in the field, with no per-device set-up.

Real addresses, both ways

The bridge never rewrites addresses. A device sees the real tailnet address of whoever connects to it, and your services see the device’s real SIM address. Logs, firewall rules and audits on both sides tell the truth.

Governed by your policy file

Access is ordinary Tailscale grants on the SIM range: who may reach which devices, on which ports, and which of your services the devices may call. Your existing tags, grants and policy tests apply, reviewed the way you review everything else.

A record of every access

Every session to a device is recorded: who, from which machine, to which SIM, for how long and how much data. Events are sent to your systems, signed, kept on disk and retried for up to 24 hours: an evidence trail for NIS2, the EU Cyber Resilience Act and UK PSTI.

Uplink only, on demand

One API call stops anything on the tailnet opening connections to the devices, while the devices can still reach your services. It takes effect at once and survives restarts.

Runs itself

The bridge sets up SIMSY (a WireGuard routing target and one routing rule) and Tailscale (its node, tags and route approval) on its own, checks them every minute, and puts right anything that drifts. Restarts keep the same identity and reconnect in seconds.

Three steps from zero to online

  1. STEP 01

    Prepare your tailnet

    Add the bridge’s tags and your access grants to your policy file, and create a Tailscale OAuth client for the bridge. About ten minutes.

  2. STEP 02

    Run the bridge

    Run one container on a Linux host with a public IPv4 address, with your SIMSY API token, your VSlice and the OAuth client in its config. SIMSY dials the bridge over an encrypted WireGuard tunnel; the bridge joins your tailnet.

  3. STEP 03

    Your devices answer

    Within a minute or two the bridge reports online. From any machine on your tailnet with subnet routes enabled, your devices answer at their SIM addresses: SSH, web interfaces, MQTT, anything your grants allow.

your devices ── SIMSY SIMs ── SIMSY core ══ encrypted tunnel ══ bridge ══ your tailnet
config.yaml (example)
mode: tenant
state_dir: /var/lib/simsy-bridge
listen:
  public_address: 203.0.113.10      # your host's public IPv4 address
simsy:
  token: ${SIMSY_API_TOKEN}
  redundancy_zone: europe-primary
tenants:
  - name: fleet-a
    vslice: fleet-a                  # your VSlice
    sim_range: 10.20.0.0/24          # its SIM address range
    downlink_allowed: true           # false: uplink only
    tailscale:
      oauth_client_id: ${TS_OAUTH_CLIENT_ID}
      oauth_client_secret: ${TS_OAUTH_CLIENT_SECRET}

The full self-hosting walkthrough is in the bridge guide.

Grants on the SIM range, like any subnet

The devices appear on your tailnet as the SIM range the bridge advertises. Grants with the range as the destination decide who reaches the devices; grants with the range as the source decide what the devices may call. Policy tests catch accidental widening before it reaches the field.

policy.hujson (fragment)
{
  "tagOwners": {
    // The bridge's own tags; its OAuth client carries tag:simsy-provisioner.
    "tag:simsy-provisioner": ["autogroup:admin"],
    "tag:simsy":             ["tag:simsy-provisioner"],
    "tag:simsy-fleet-a":     ["tag:simsy-provisioner"],
    "tag:collector":         ["group:platform"],
  },
  "grants": [
    // Field ops can SSH and browse to the devices.
    {"src": ["group:field-ops"], "dst": ["10.20.0.0/24"], "ip": ["tcp:22", "tcp:443"]},
    // The devices post to the collector, and nothing else.
    {"src": ["10.20.0.0/24"], "dst": ["tag:collector"], "ip": ["tcp:8883"]},
  ],
  "tests": [
    {"src": "10.20.0.10", "accept": ["tag:collector:8883"], "deny": ["tag:collector:22"]},
  ],
}

The same syntax you already use. The destination 10.20.0.0/24 happens to be cellular devices in the field rather than servers in a rack, and everything reviewed at merge time treats it the same way.

Design decisions to fit into your set up.

No address translation

SIMSY routes your tailnet’s address space back to the bridge, so replies always find their way and nothing needs translating. Keep your VSlice’s SIM range out of Tailscale’s own 100.64.0.0/10; SIMSY support can renumber a VSlice if it overlaps.

Your other routing stays yours

The bridge adds one rule to your VSlice’s routing policy and leaves every other rule, including your devices’ internet route, exactly as it was. It checks the result and restores your policy if anything else changed.

Identity that survives restarts

The bridge keeps its WireGuard key and Tailscale identity in its state volume. Upgrades and restarts come back as the same node with the same route; nothing needs re-approving.

A small, locked-down container

One static binary in a distroless image, running as a non-root user with no added privileges, no /dev/net/tun and a read-only filesystem. Two UDP ports in. Every release is signed, with an SBOM and build provenance you can verify before you run it.

Health you can watch

A status API and Prometheus metrics report the tunnel’s health, the route, traffic and every access session. State changes such as degraded, with a reason, arrive as signed webhooks.

Throughput

The bridge is not the bottleneck: in testing, traffic through it ran close to the SIM’s own cellular speed in both directions.

On the roadmap

Devices by name

Each device as its own named machine on your tailnet, so ssh depot-router-3 works and machines can be shared individually.

SIMSY-run bridges

The bridge run for you by SIMSY, shared into your tailnet, with nothing to host.

Try it on a Launch SIM.

Grab a Launch SIM, put it on a VSlice, run the bridge on a small cloud instance and SSH to the device from your laptop by its SIM address. The whole exercise takes an afternoon.

Works with Tailscale and Headscale