← Back to Guides

    VPN vs bastion host vs outbound-only: choosing a remote access pattern

    There are three common patterns for accessing devices behind NAT: VPNs, bastion hosts, and outbound-only agents. Each has different tradeoffs around operational overhead, network topology, and security posture. This guide compares them to help you choose.


    Quick comparison

    VPNBastion hostOutbound-only
    Inbound ports requiredYes (or relay)YesNo
    Network-level accessFullVia jumpPer-session
    Operational overheadMedium-highMediumLow
    Works behind CGNATSometimesNoYes
    Identity managementRequiredRequiredIncluded
    Scales to fleetComplexComplexSimple

    VPN-based access

    How it works

    Devices join a virtual private network by exchanging keys with a coordination server or directly with peers. Once connected, each device gets an IP on the VPN subnet and can reach other peers as if they were on the same LAN — any port, any protocol. The VPN client handles encryption and routing transparently.

    WireGuard, OpenVPN, Tailscale, and ZeroTier all follow this model, though they differ in key management and NAT traversal strategies.

    Pros

    • Full network access: reach any port/service once connected
    • Peer-to-peer possible: some VPNs establish direct connections between peers without routing through a central server

    Cons

    • Key lifecycle management: WireGuard keys don't expire; OpenVPN certs require PKI. Revoking access means updating allowlists or regenerating keys across peers
    • Lateral movement surface: once authenticated, a device can reach any peer/service on the VPN subnet unless you add firewall rules per-peer
    • NAT traversal: WireGuard requires at least one peer with a public endpoint; hole-punching fails behind symmetric NAT. Tailscale/ZeroTier use DERP/relay servers as fallback, adding latency

    Best for

    • Teams with existing VPN infrastructure
    • Scenarios requiring broad network-level access
    • Environments where you control network topology

    Bastion host (jump box)

    How it works

    A bastion host is a hardened server with a public IP that acts as the single entry point to your private network. Users SSH to the bastion first, then "jump" to internal devices using ProxyJump or manual tunneling. The bastion never stores credentials for internal hosts — it just forwards the SSH connection.

    This pattern assumes your devices can accept inbound connections from the bastion's IP, either directly or via reverse tunnels they initiate.

    Pros

    • Single ingress point: all SSH traffic funnels through one IP, simplifying firewall rules and IDS placement
    • Native SSH tooling: ProxyJump (-J), scp, and port forwarding (-L/-R) work without additional client software
    • Session logging: tools like auditd or sshrc capture commands; combined with ProxyCommand, you get per-hop logging

    Cons

    • Exposed attack surface: port 22 must be reachable from the internet; requires SSH hardening (key-only auth, fail2ban, rate limiting)
    • Availability dependency: bastion downtime blocks all device access; HA requires load-balanced bastions with shared authorized_keys
    • Patch burden: OpenSSH CVEs require immediate patching on an internet-facing host; missed patches mean exposed vulnerabilities
    • Requires device-to-bastion reachability: devices must initiate reverse tunnels (ssh -R) or have routable IPs; pure CGNAT environments need additional tunneling

    Best for

    • Enterprise environments with existing bastion infrastructure
    • Compliance requirements mandating centralized access control
    • Scenarios where devices have predictable network paths

    Outbound-only agent

    How it works

    An agent running on the device opens a persistent outbound connection to a broker — the device reaches out, not the other way around. The broker authenticates users and routes their session requests to the appropriate device over the existing tunnel. Because the device initiated the connection, no inbound ports or NAT configuration are required.

    With m87, this tunnel uses QUIC (UDP 443, TLS 1.3). Shell sessions, command execution, and port forwards are multiplexed as separate QUIC streams over the single connection.

    Pros

    • No inbound ports: device initiates outbound UDP 443; no firewall changes or port forwarding required
    • Works behind NAT/CGNAT: QUIC handles connection migration; works as long as UDP egress is allowed
    • Per-session streams: shell, exec, and port forwards are separate QUIC streams; no persistent network membership
    • Fleet scaling without topology changes: each device maintains its own tunnel; adding devices doesn't require VPN mesh updates or bastion config changes
    • Centralized access control: OAuth/SSO authentication with role-based access control (RBAC) — define who can deploy containers, forward ports, or access shells per device or fleet

    Cons

    • Requires an agent: m87 runtime must run on the device (systemd service or foreground process)
    • Broker adds latency: all traffic routes through the broker; no direct peer-to-peer path (yet)
    • Application-layer access only: you get shell, exec, port forwarding, and Docker API — not raw Layer 3 access to the device's subnet

    Best for

    • Devices behind NAT, CGNAT, or restrictive networks
    • Fleets where you don't control network infrastructure
    • Teams that want access without managing VPN/bastion infrastructure

    Decision guide

    Choose VPN if:

    • You already run VPN infrastructure
    • You need persistent, network-level access to many services
    • Your devices have stable, controllable network paths

    Choose bastion if:

    • You have compliance requirements for centralized access logging
    • You're in an enterprise environment with existing jump box patterns
    • Your devices can reliably reach a central server

    Choose outbound-only if:

    • Your devices are behind NAT, CGNAT, or networks you don't control
    • You want to avoid managing VPN or bastion infrastructure
    • You need to scale from one device to many without network changes
    • You want per-session access rather than persistent network membership

    Combining approaches

    These patterns aren't mutually exclusive:

    • Use outbound-only for initial reachability, then forward ports to access services
    • Use VPN for broad network access in controlled environments, outbound-only for field devices
    • Use bastion for compliance logging, with outbound-only agents connecting to it

    Access control with make87

    make87 provides centralized user management through OAuth/SSO. Beyond simple authentication, you can configure role-based access control (RBAC) to define granular permissions:

    • Shell access: who can open interactive sessions
    • Docker operations: who can deploy, restart, or remove containers
    • Port forwarding: who can tunnel to device services
    • Device management: who can approve, reject, or remove devices

    Permissions are managed at the platform level — no per-device configuration files. When team members join or leave, update their access in one place.


    FAQ

    Which is most secure?

    All three can be secure if implemented correctly. The question is which security model fits your operational reality:

    • VPN: security depends on key management and membership lifecycle
    • Bastion: security depends on hardening a public-facing server
    • Outbound-only: security depends on the broker and agent implementation

    Which is easiest to set up?

    For devices behind NAT/CGNAT, outbound-only is typically easiest — no network changes required. For devices on networks you control, VPN or bastion may be simpler if you already have that infrastructure.

    Can I switch later?

    Yes. These are access patterns, not permanent architectural decisions. Many teams start with one approach and evolve as their fleet grows.

    What about Tailscale / ZeroTier?

    These are VPN solutions with managed coordination servers. They reduce operational overhead compared to self-hosted VPN, but still involve network membership and identity management.

    What does make87 use?

    make87 uses the outbound-only pattern. The m87 runtime maintains a persistent QUIC tunnel (UDP 443, TLS 1.3) to the make87 platform. Sessions (shell, port forwarding, Docker API) are multiplexed as QUIC streams over this connection.


    Next