Run Nautilo on one trusted LAN
Deploy through SSH and connect a Desktop client over bounded, unencrypted LAN HTTP.
This is a bounded path for a Nautilo Desktop client and a Linux Docker host on the same trusted network. The Linux host may be a small local server or another machine on that LAN. The operator manages it over SSH; the client connects to the Server and identity endpoints over plain HTTP. Nautilo does not currently provide a supported HTTPS mode for this LAN route.
What this topology supports
Use a remote Compose profile even when the Linux host is beside you. That
profile advertises the SSH host name in the generated Server and Logto URLs.
A local profile advertises localhost; sharing its ports or replacing that
word later does not make its identity configuration valid for another device.
This guide supports:
- one stable LAN host name that every participating computer resolves to the same private host;
- remote Compose lifecycle management over a pre-authorized SSH key;
- protected config-mode first-owner creation through the trusted SSH loopback; and
- a Nautilo Desktop client configured with the exact HTTP Server URL from the deployment receipt.
It does not support browser claim, Mobile Web, production iOS or Android
clients, a browser-based Workbench on the LAN origin, or Internet exposure.
It also does not turn a macOS local profile into a shared Server by opening its
ports: that profile's identity endpoints remain bound to localhost.
Prepare the LAN and host
- Give the host a stable address through DHCP reservation or static network
configuration. Create a LAN DNS name such as
nautilo-lan.exampleand verify that the operator computer and Desktop client resolve it to the same host. Do not configure router port forwarding. - Install Docker Engine and the Docker Compose plugin on the Linux host. Give
a dedicated
operatoraccount permission to use Docker and write the chosen deployment directory. Have the host administrator create the path used below withsudo install -d -o operator -g operator -m 700 /srv/nautilo. - Pre-authorize a dedicated SSH public key for that account. Obtain the
server's SSH host-key fingerprint through a trusted channel before saving
it; an unverified
ssh-keyscanresult is not proof of identity. - Use a signed Nautilo CLI release whose
nautilo deploy --helplists--owner-mode,--owner-config, and--owner-result. If those options are absent, protected LAN first-owner creation is unavailable in that release. Do not substitute browser claim.
Record and install the verified SSH host key:
export NAUTILO_LAN_HOST='nautilo-lan.example'
export NAUTILO_SSH_IDENTITY_FILE="$HOME/.ssh/nautilo_lan_operator"
export NAUTILO_SSH_KNOWN_HOSTS_FILE="$HOME/.ssh/nautilo_lan_known_hosts"
ssh-keyscan -t ed25519 -H "$NAUTILO_LAN_HOST" > /tmp/nautilo-lan.known-hosts
ssh-keygen -lf /tmp/nautilo-lan.known-hostsCompare that fingerprint with the separately obtained value. Stop on any mismatch. Only after a match, install it and prove Docker access:
install -m 600 /tmp/nautilo-lan.known-hosts "$NAUTILO_SSH_KNOWN_HOSTS_FILE"
rm /tmp/nautilo-lan.known-hosts
ssh -o BatchMode=yes -o IdentitiesOnly=yes -l operator \
-i "$NAUTILO_SSH_IDENTITY_FILE" \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="$NAUTILO_SSH_KNOWN_HOSTS_FILE" \
"$NAUTILO_LAN_HOST" \
'docker info && docker compose version && test -w /srv/nautilo'Create a LAN profile
nautilo profile add lan-server \
--transport=remote \
--lifecycle=compose \
--instance-id=lan \
--ssh-host="$NAUTILO_LAN_HOST" \
--ssh-user=operator \
--ssh-identity-file="$NAUTILO_SSH_IDENTITY_FILE" \
--ssh-known-hosts-file="$NAUTILO_SSH_KNOWN_HOSTS_FILE" \
--remote-path=/srv/nautilo \
--https=off \
--yesDo not add a public domain, https=letsencrypt, or a hand-written base URL to
this LAN profile. Nautilo derives the HTTP Server and Logto endpoints from the
SSH host and the allocated Compose ports.
Contain the published ports before deployment
Docker-published ports can be reachable beyond host firewall rules, depending on the Docker and firewall configuration. Treat the router, VLAN, or provider firewall as the primary boundary and account for Docker's forwarding rules on the host.
- Permit SSH only from administrator devices.
- Begin with every published application port denied at the upstream boundary.
- After deployment reports
owner-bound, permit only the exact Server and Logto ports in its receipt, and only from the trusted LAN client range. - Deny those ports from guest networks and the Internet.
- Do not expose database or Logto administrator ports.
- Do not create public DNS records or router port-forwarding rules for this host.
The allocated ports are deployment output; do not copy port numbers from an example or guess them. Keep the upstream policy default-deny while the CLI deploys and creates the owner through SSH loopback. Add the exact LAN-only allow rules from the successful receipt before connecting Desktop.
Create the first owner without a browser claim
The browser claim endpoint rejects non-loopback HTTP. Prepare the protected Local / Docker Compose TOML on the operator computer, then use config mode: fill in the local setup file.
Choose a new result filename. It receives one-time recovery codes and must remain outside Server storage and backups.
nautilo deploy \
--profile lan-server \
--owner-mode config \
--owner-config "$HOME/.config/nautilo/deploy.toml" \
--owner-result "$HOME/.config/nautilo/lan-owner-result.json" \
--finish guide \
--json --no-open-browserRequire owner-bound, save the recovery codes and permanent owner credentials
in a password manager, and retain the exact deployment receipt. Continue in
Desktop only after that result; this command deliberately does not open a Web
page. Apply the two receipt-derived LAN port rules described above before
connecting it. Do not open /claim from another computer, change to claim mode
after interruption, or recreate an existing result file.
Connect a Desktop client
On a second computer on the same trusted LAN:
- Confirm that
NAUTILO_LAN_HOSTresolves to the prepared host. - Copy the exact Server URL from the deployment receipt. It begins with
http://and uses the LAN host name plus its allocated port. - In Nautilo Desktop, add that explicit Server URL. Review the plaintext HTTP warning and confirm that the displayed target is the host you prepared.
- Sign in with the existing owner account created by config mode. Do not look for a claim page.
- Confirm the expected Server identity and complete one useful model-backed action before inviting anyone else.
Diagnose without changing the topology
Run the DNS check for the client operating system. On macOS:
dscacheutil -q host -a name nautilo-lan.exampleOn Linux:
getent hosts nautilo-lan.exampleThen test the exact Server URL from the same computer:
curl --fail --silent --show-error 'http://nautilo-lan.example:<server-port>/health'Replace <server-port> with the receipt value. The health response's
logtoEndpoint must use the same resolvable LAN host, not localhost. Then
check the managed instance and SSH path from the operator computer:
nautilo status --profile lan-server
ssh -o BatchMode=yes -l operator \
-i "$NAUTILO_SSH_IDENTITY_FILE" \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="$NAUTILO_SSH_KNOWN_HOSTS_FILE" \
"$NAUTILO_LAN_HOST" 'docker info'If DNS differs between devices, the endpoint contains localhost, client
isolation blocks peers, or the Logto port is not reachable, stop and correct
that boundary. Do not disable host-key checking, browser security controls,
mobile cleartext policy, or claim-origin checks.
For Web, Mobile, public access, or transport confidentiality, choose an HTTPS deployment: choose a deployment.