Firewall, ports & NAT

What ports the plugin uses (and which it doesn’t), how to expose a remote vault host across networks, and what to put in the firewall rules.

TL;DR

The plugin opens zero new network ports. The daemon binds a Unix socket only — no TCP listener. All traffic flows through your existing SSH connection. If ssh user@host reaches your remote, the plugin reaches your remote.

Why no extra port

The daemon uses net.Listen("unix", ~/.obsidian-remote/server.sock) per server/cmd/obsidian-remote-server/main.go:99. Unix sockets are filesystem objects, scoped to the local machine; they cannot be reached by network peers. The plugin connects to the socket via an SSH local stream forward (the openUnixStream call in tryReuseExistingDaemon), which tunnels socket bytes over the SSH session.

flowchart LR
  C[Plugin on laptop] -->|SSH on :22| sshd[sshd on remote]
  sshd -->|local stream forward| sock["/home/user/.obsidian-remote/server.sock<br/>(Unix socket — no TCP)"]
  sock --> D[Daemon process]

So the only port that needs to be open is the one your sshd already uses (typically 22, sometimes a custom port like 2222 for Docker).

Common topologies

Local network (same LAN)

No firewall changes needed. Your laptop connects directly:

laptop  ── LAN (192.168.x.0/24) ──  remote (192.168.x.50:22)

If the remote’s host firewall is on (ufw enable on Ubuntu, etc.), allow inbound SSH:

sudo ufw allow ssh                # allows port 22
# or for a custom sshd port
sudo ufw allow 2222/tcp

Behind home NAT (you’re on the road, vault is at home)

Three sane options, in increasing order of “effort but worth it”:

OptionEffortTrade-off
Tailscale / Headscale / WireGuard meshLow (one install per device)Best path — no router changes, no public exposure. See the Tailscale recipe.
Cloudflare Tunnel / ngrok / boringproxyMediumTLS-terminated reverse tunnel; the remote host dials out to the tunnel provider. No router config; depends on the provider.
Port-forward 22 on your home routerMedium-high (router config + harden sshd)Direct internet exposure. Acceptable IF you’ve got pubkey-only auth, fail2ban, non-22 port number, and no password logins. Easy to misconfigure.

For most users: just use Tailscale. It removes the entire NAT class of problems.

Cloud VPS / managed host

The host has a public IP. Allow inbound SSH at the cloud provider’s firewall layer (security group on AWS, firewall rule on Hetzner / DigitalOcean / OVH):

inbound TCP 22  from  0.0.0.0/0  → allow      (or restrict to your IP)

Stack a host-level firewall on top (ufw allow ssh) for defense in depth.

Behind corporate NAT / restrictive network

If port 22 outbound is blocked (some corporate networks, hotel WiFi, etc.):

  • SSH over a custom port — bind sshd to 443 or 8443; outbound 443 is almost universally allowed
  • SSH over WebSocketwstunnel / websocat wrap SSH in TLS; see the TLS-in-front section of the reverse-proxy recipe
  • Tailscale’s DERP relays — Tailscale falls back to TLS relays automatically when direct UDP can’t establish; works on most corporate networks

What to NOT firewall

The plugin doesn’t need:

  • Any inbound port other than SSH on your remote
  • Any outbound port from the daemon (it doesn’t make outbound network calls)
  • Any port on your laptop (the plugin is the SSH client, opens outbound only)

The Unix socket the daemon listens on (~/.obsidian-remote/server.sock) is filesystem-scoped — no iptables rule applies to it.

Verifying the wire

From your laptop:

# Can you SSH at all?
ssh -v user@remote-host echo OK
# Should print "OK" with verbose handshake. If not, fix SSH first.
 
# Can the plugin reach the socket via the SSH forward?
# (Plugin does this internally; manual test for paranoia.)
ssh user@remote-host 'test -S ~/.obsidian-remote/server.sock && echo socket-OK'
# Should print "socket-OK" once the daemon is running.

If both succeed, the network path is fine. Any plugin failure beyond this is in the auth / RPC layer, not the firewall.

Hardening sshd (since this is the only port)

Quick sanity on a non-trivially-exposed remote:

# /etc/ssh/sshd_config (or /etc/ssh/sshd_config.d/99-hardening.conf)
PasswordAuthentication no            # pubkey only
PermitRootLogin no                   # never login as root over SSH
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 60               # detect dropped clients

Reload: sudo systemctl reload ssh (or sshd on some distros).

Combined with fail2ban for brute-force defense and ufw allowing only your SSH port, this is sufficient for most home / personal-server scenarios.

See also