Skip to main content

Phaze Relay Setup

Detailed instructions for setting up a Phaze Relay and testing it inside your network.

This guide covers the network side of a Phaze Relay deployment: which ports need to be open, in which direction, and where the relay should physically sit in your network. Installing the relay binary itself (systemd unit, user account, key provisioning) is covered by readme.txt in the relay archive — this document picks up after the binary is on the box and focuses on firewalls, NAT, and routing.

The traffic the relay needs

Three flows, in three directions:

  • Outbound TCP 443 — relay → Phaze signaling. The relay opens a single persistent WebSocket to the Phaze signaling host (by default relay.phaze.app) to receive connection requests. It is always the relay that initiates this connection; the signaling host never initiates anything inward.

  • Inbound UDP — peers → relay. All Phaze hosts and clients that need to use this relay send UDP packets to it on a single port (default 41000). This is the only inbound flow the relay accepts.

  • Outbound UDP — relay → peers. The relay forwards UDP packets back out the same socket to whichever peer is on the other end of a connection. Almost all firewalls let this through automatically as the reply side of the inbound flow, but it is worth being explicit when writing rules.

The relay never initiates a new connection into a peer's network. Peers always reach out first, and the relay replies. That asymmetry is the basis for most of the DMZ rules below.

Public address and port

In the Phaze admin panel, every relay has two fields that matter for networking:

  • Public address — the IP or hostname that hosts and clients will be told to send packets to. This is injected into the connection candidates the signaling server hands to each peer.

  • Public port — the UDP port on that address. Defaults to 41000.

The relay does not auto-discover these. Whatever you put in the admin panel is what peers will use, so it has to match the externally reachable address and port for the relay machine.

Two consequences worth calling out:

  • The public port and the relay's listen port do not have to match. The relay's --udp-port (default 41000) is the port the binary binds to locally. If your firewall does port translation — for instance, advertising UDP/443 publicly and forwarding it to the relay's UDP/41000 — then the admin panel's "public port" is 443 and the systemd --udp-port flag is 41000. Both peers will be told to use UDP/443; your firewall translates.

  • If the relay is reachable on different addresses from different networks (e.g. one IP from the internet, a different IP from inside your LAN), choose the address that both groups of peers can route to. In practice this almost always means the externally reachable address — internal hosts can usually route to a DMZ IP just fine, while internet clients can't route to a private one.

Standard configurations

Relay in a DMZ

The most common enterprise deployment: Phaze hosts (the workstations being remoted into) sit on the internal LAN, Phaze clients (the people doing the remoting) come in from the internet, and the relay sits in a DMZ segment between the two.

Place the relay VM/host in the DMZ segment. Give it a private IP in the DMZ subnet, and either a dedicated public IP or a NAT mapping on your external firewall.

External firewall (internet → DMZ):

  • Allow inbound UDP to the relay's public IP on port 41000, from any source. If you have a known set of client IP ranges, restrict to those; otherwise leave the source open.

  • Allow outbound TCP 443 from the relay to the signaling host (relay.phaze.app by default).

  • Deny everything else.

This is what lets Phaze clients on the WAN reach the relay, and lets the relay reach Phaze's signaling endpoint.

Internal firewall (LAN ↔ DMZ):

  • Allow outbound UDP from your Phaze host workstations to the relay's DMZ IP on port 41000.

  • Deny inbound DMZ → LAN by default.

The Phaze hosts initiate UDP outward to the relay, which means the internal firewall is permitting egress from LAN to DMZ. There is no need to allow DMZ → LAN traffic, because the relay never initiates connections into your network — return packets are part of the already-established UDP flow that the host opened.

Admin panel:

  • Public address: the relay's public IP (or DNS name).

  • Public port: 41000 (or whatever your external rule allows).

Cloud-hosted relay

The relay runs on a cloud VM (EC2, GCE, Azure VM, Hetzner, etc.) with a public IP. Both Phaze hosts and Phaze clients reach it over the internet. Useful when you don't have a DMZ, or when hosts are remote / WFH and there is no single "internal network" to put them on.

Cloud security group / firewall:

  • Inbound UDP/41000 from 0.0.0.0/0 (or a tighter source range if you have one for both hosts and clients).

  • Outbound TCP/443 to the signaling host.

  • Outbound UDP allowed by default on most cloud providers; if your egress is locked down, allow outbound UDP from the relay back to arbitrary destinations (replies to peers).

Admin panel:

  • Public address: the VM's public IP (or its DNS name).

  • Public port: 41000.

The host-side firewall doesn't need any special inbound rules in this configuration — hosts initiate outbound to the relay's public IP, the same way a browser initiates outbound to a website. Most corporate egress firewalls block arbitrary outbound UDP though, so confirm outbound UDP/41000 (or whichever port you chose) is allowed.

Fully Internal Relay

The relay, hosts, and clients all sit on the same private network. No internet exposure. Used in air-gapped environments, or when both ends of the remote-desktop session are inside the same corporate network and the goal is just to give IT a single point of policy enforcement.

The relay still needs to reach Phaze's signaling host for the connection setup to work. If the network is genuinely air-gapped, talk to us — that's a different deployment model and not what this guide covers.

Place the relay on a network segment that both VLANs can reach (a dedicated services VLAN is the cleanest option; a DMZ also works).

Firewall:

  • Allow UDP/41000 from the Workstations VLAN to the relay's IP.

  • Allow UDP/41000 from the Contractors VLAN to the relay's IP.

  • No inter-VLAN host↔client rules are needed — they never talk to each other directly; everything flows via the relay.

  • Allow outbound TCP/443 from the relay to the signaling host.

Admin panel:

  • Public address: the relay's IP on a segment both VLANs can route to.

  • Public port: 41000.

Verifying reachability

After you wire up the firewall rules, the easiest end-to-end check is to look at the relay's status in the admin panel: it should show as "online" within a few seconds of starting the service. That confirms the outbound TCP/443 leg is working.

For the inbound UDP leg, the simplest test is to attempt a real Phaze connection from a representative host and client. The relay's journal (journalctl -u phaze-relay -f) will log incoming packets when --log-level debug is set on the ExecStart line.

If you want to confirm UDP reachability without involving a Phaze client, from a peer machine you can send a probe packet:

echo "probe" | nc -u -w1 <relay-public-address> 41000

You won't get a meaningful reply (the relay drops unrecognized packets silently), but the relay's debug log will show the packet arriving with its source address. If nothing arrives in the log, the path is blocked somewhere between the peer and the relay — check each firewall hop in order.

Choosing a UDP port

The default is 41000 because it's outside the well-known and ephemeral port ranges on every common OS, so it almost never collides with anything else. Pick a different port if:

  • 41000 conflicts with another service on the relay machine.

  • Your network policy requires a specific port (e.g. UDP/443 to look like QUIC, or a port that's already permitted by an existing firewall rule you can't change).

  • You're running multiple relays behind the same public IP — each needs its own externally-reachable port, mapped via NAT to each relay's listen port.

Change the relay's listen port by editing the --udp-port value on the ExecStart line in /etc/systemd/system/phaze-relay.service, then:

sudo systemctl daemon-reload sudo systemctl restart phaze-relay

If the externally-visible port differs from the relay's listen port (because of NAT), update the public port in the admin panel to match what peers will dial.

Notes on direction and trust

A few properties of the relay that affect how to think about firewall rules:

  • The relay only ever sends UDP to addresses it has already received UDP from. It does not initiate outbound UDP to peers it hasn't heard from. This is why a stateful firewall in front of the relay doesn't need an explicit outbound UDP rule for peer traffic — the replies match the inbound flow's state.

  • The relay does not terminate the encrypted session. Packets pass through it encrypted end-to-end between host and client; the relay routes by a connection ID embedded in each packet but cannot read the contents. From a data-exposure standpoint, a compromised relay can disrupt traffic but cannot read what's inside the streams.

  • The relay holds no persistent state. Restarting the service drops its in-memory routing table; connections re-establish naturally as hosts and clients reconnect. There is nothing on disk to encrypt or audit beyond the systemd unit and the binary itself.

  • The relay key (the phz_rk_... value in the systemd unit) is the only secret on the box. It authenticates the relay to the Phaze signaling backend. Rotate it by generating a new one in the admin panel and replacing the value in the unit file. There are no per-peer credentials on the relay.