---
title: "Remote Access"
canonical_url: https://www.superlogical.com/rex/docs/linux/remote-access
---

# Remote Access

A Rex server on Linux listens only on Unix sockets on that machine by
default. To use it from Rex for Mac or another computer, you must specify
a network listener. This page covers the listeners, who each one lets in,
and how to add the server to a client.

**Rex trusts a caller based only on how they connect today**, so it can't
check who someone is unless the network tells it. That's why servers listen
only locally by default and why every listener below is cautious about who
it lets in. This is a short-term limitation. A full authentication and
authorization system is planned, including support for existing SSH keys.

Until then, we recommend [Tailscale](https://tailscale.com). It tells Rex
who each caller is, which is how Rex decides who gets in, and for the
[login server](https://www.superlogical.com/rex/docs/linux/login-server.md), which account they get. Tailscale
has powerful ACLs that you can use to safely restrict access for multiple
users at the network level.

| Listener            | Needs                          | Works with                 | Identifies callers |
| ------------------- | ------------------------------ | -------------------------- | ------------------ |
| Built-in Tailscale  | A Tailscale account            | Personal and shared server | Yes                |
| Tailscale Serve     | Tailscale on the machine       | Shared and login server    | Yes                |
| Tailnet address     | Tailscale on the machine       | Shared and login server    | Yes                |
| Plain HTTP          | `--allow-anonymous`            | Every mode                 | No                 |

## Built-in Tailscale

With `--tailscale`, the server joins your tailnet as its own device, using
Tailscale built into Rex. The machine doesn't need Tailscale installed.

```sh
rex server start --tailscale
```

The first time, the server needs to sign in to Tailscale. Its sign-in link
appears in `rex server status` and the server's log. To sign in without a
browser, pass a one-time auth key with `--tailscale-auth-key-file FILE`, or
`-` to read it from standard input. The server keeps its login, so it needs
the key only once.

The device is named `rex` unless you choose another name with
`--tailscale-hostname`. Its address is `https://rex.<tailnet>.ts.net`. Your
tailnet must have MagicDNS and HTTPS certificates turned on.

To sign it in as a tagged device, add `--tailscale-advertise-tag tag:NAME`.
A tagged device has no owner, so this also needs
`--tailscale-allow-tailnet-members`. See [Who Can Connect](#who-can-connect).

For the shared server, add these options to the service's command line, as
in the next section.

## Tailscale Serve

If the machine already runs Tailscale, Tailscale Serve can forward HTTPS
connections to a socket that Rex listens on. This is the usual way to reach
the shared server or the login server.

Run `sudo systemctl edit rex.service` (or
`rex-login-server.service`) and add the socket to its command line. Package
upgrades keep this file. For the shared server:

```ini
[Unit]
After=tailscaled.service
Requires=tailscaled.service

[Service]
ExecStart=
ExecStart=/usr/bin/rex server run --listen /run/rex/server.sock \
  --state-dir /var/lib/rex --socket-mode 0660 --log-format text \
  --extra-listen tailnet-serve:///run/rex/serve.sock
```

For the login server, the command line is:

```ini
ExecStart=
ExecStart=/usr/bin/rex login-server --listen unix:///run/rex/login-server.sock \
  --accounts /etc/rex/accounts.jsonc --runtime-root /run/rex --log-format text \
  --pam-service rex-login-server --extra-listen tailnet-serve:///run/rex/serve.sock
```

On Alpine, set `command_args` in `/etc/conf.d/rex` (or
`/etc/conf.d/rex-login-server`) to the same command line, without
`/usr/bin/rex`. `rc_need` takes the place of `After=` and `Requires=`. For
the shared server:

```sh
command_args="server run --listen /run/rex/server.sock \
  --state-dir /var/lib/rex --socket-mode 0660 --log-format text \
  --extra-listen tailnet-serve:///run/rex/serve.sock"
rc_need="tailscale"
```

Then point Tailscale Serve at the socket:

```sh
sudo tailscale serve --bg --https=443 unix:/run/rex/serve.sock
```

The address is the machine's own tailnet name, such as
`https://build.<tailnet>.ts.net`.

Tailscale Serve doesn't tell Rex who a tagged device is, so tagged devices
such as CI runners can't connect this way. Use a tailnet address for them
instead.

## Tailnet Address

A server can also listen directly on the machine's tailnet addresses, using
the machine's own Tailscale to identify callers. Add this to the server's
command line, the same way as the Serve socket above:

```sh
--extra-listen tailnet://:7297
```

The port is required. The connection is plain HTTP, encrypted by Tailscale,
at `http://build.<tailnet>.ts.net:7297`.

## Who Can Connect

**A connection to a server can do anything that server can,** including
starting programs as its account. Control access with care.

For a personal server or the shared server, only the Tailscale user who
owns the machine (or the Rex device, with built-in Tailscale) is let in by
default. To let in other people:

| Listener           | Option                              | Lets in                                    |
| ------------------ | ----------------------------------- | ------------------------------------------ |
| Built-in Tailscale | `--tailscale-allow-tailnet-members` | Anyone on the tailnet your ACLs allow      |
| Serve or address   | `--tailnet-allow-identified`        | Anyone Tailscale can identify              |

A tagged machine or device has no owner, so it needs one of these options
to let anyone in.

The login server is different. It lets in everyone Tailscale can identify,
because its [accounts file](https://www.superlogical.com/rex/docs/linux/login-server.md#accounts-file) decides
which accounts each person may use.

To see who's connected to a server, run `rex client ls` on it. Its
`principal` column shows the identity of each client.

## Plain HTTP

A plain HTTP listener can't tell callers apart, so Rex refuses one unless
you also pass `--allow-anonymous`:

```sh
rex server start --extra-listen :7297 --allow-anonymous
```

**Every connection then has full access.** Only do this on a network you
completely control. The login server lets such callers use only accounts
whose principals include `anonymous`, and never root.

Again, this is **super dangerous** and you probably shouldn't do it.
This option exists because sophisticated users can pair this with their
own network options such as their own corporate VPN, ZeroTier, etc. to
provide stronger guarantees.

## Adding the Server to a Client

In Rex for Mac, choose **Add Remote Host…** and enter the server's address.

On the command line, pass the address with `-S`, or save it as a host and
use its label:

```sh
rex -S https://build.example.ts.net ls
rex hosts add build https://build.example.ts.net
rex -S build ls
```

A bare host name, such as `build.example.ts.net`, tries HTTPS on port 443,
then HTTPS on port 7297, then HTTP on port 7297.

To connect to the login server as a specific account, put it before the
host, such as `https://root@build.example.ts.net`. See
[Choosing an Account](https://www.superlogical.com/rex/docs/linux/login-server.md#choosing-an-account).

**Note: `rex hosts` today is CLI-only.** It doesn't sync to your GUI client
or across machines. This will change in the future.

## NixOS

The NixOS module has options for each listener:

| Option                                           | Sets up                                                     |
| ------------------------------------------------ | ----------------------------------------------------------- |
| `services.rex.tailscale.enable`                  | Built-in Tailscale, with `hostname`, `authKeyFile`, and `advertiseTags` |
| `services.rex.tailscaleServe.enable`             | Tailscale Serve for the shared server                       |
| `services.rex.loginServer.tailscaleServe.enable` | Tailscale Serve for the login server                        |
| `services.rex.allowAnonymous`                    | Plain HTTP for the shared server. `openFirewall` opens its `port`. |
| `services.rex.loginServer.allowAnonymous`        | Plain HTTP listeners for the login server                   |
