Skip to content

LAN Mode

Run the Tuitbot server on one machine (e.g., an OrangePi, Raspberry Pi, or NAS) and access the dashboard from any device on your local network.

Quick Start

# On the server machine
cargo run -p tuitbot-server -- --host 0.0.0.0

On first start the server generates a 4-word passphrase and prints it to the terminal:

  Web login passphrase: alpine cobra morning puzzle
  (save this — it won't be shown again)

  Dashboard: http://192.168.1.42:3001

Open that URL from any device on your network. You'll see a login screen — enter the passphrase and you're in.

First-Time Setup (Browser)

When the server starts on 127.0.0.1 (the default) without an existing passphrase, it does not generate one automatically. Instead, the browser-based onboarding wizard handles passphrase creation:

  1. Start the server: cargo run -p tuitbot-server
  2. Open http://localhost:3001 in your browser
  3. Complete the onboarding wizard
  4. On the final step, set your passphrase (a 4-word phrase is suggested)
  5. Save the passphrase — you'll need it to log in again after your session expires

The passphrase is created during POST /api/settings/init and a session cookie is set automatically, so you're logged in immediately after onboarding.

LAN mode (--host 0.0.0.0) still generates a passphrase at startup and prints it to the terminal, preserving backward compatibility for CLI users.

How It Works

Tuitbot has two authentication strategies that coexist:

Mode Who uses it How it works
Bearer token Tauri desktop app, dev mode, API/MCP clients Reads ~/.tuitbot/api_token file, sends as Authorization: Bearer header
Session cookie Web browsers over LAN Enter passphrase once, server sets an HttpOnly cookie valid for 30 days

When you open the dashboard in a browser without a bearer token on a fresh install, you're directed to the onboarding wizard. At the end of setup, you'll create a passphrase that protects future browser sessions. A session cookie is set automatically, so you're logged in immediately after onboarding. On subsequent visits, if your session has expired, you'll see a login screen where you enter the same passphrase. Sessions last 30 days.

CLI Flags

cargo run -p tuitbot-server -- --help
Flag Default Description
--host 127.0.0.1 Bind address. Use 0.0.0.0 for LAN access
--port 3001 Port number
--config ~/.tuitbot/config.toml Config file path
--reset-passphrase Reset passphrase and print the new one (no server restart needed)

Passphrase Management

The passphrase is generated once and its bcrypt hash is stored in ~/.tuitbot/passphrase_hash. The plaintext is only ever shown in the terminal at generation time.

Forgot your passphrase? Reset it:

tuitbot-server --reset-passphrase

This prints the new passphrase to stdout and exits. It works even while the server is already running — no port conflict, no startup noise. The running server detects the change automatically and accepts the new passphrase on the next login attempt. Existing browser sessions continue working until they expire.

The output is bare (just the passphrase, no formatting), so you can script it:

NEW_PASS=$(tuitbot-server --reset-passphrase)

Security Model

Concern Mitigation
Session theft via XSS Cookie is HttpOnly — JavaScript cannot read it
Cross-site request forgery (CSRF) Mutating requests (POST/PATCH/DELETE) require an X-CSRF-Token header that's returned at login
Brute-force passphrase guessing Rate limited to 5 attempts per minute per IP
Database compromise Sessions stored as SHA-256 hashes — a DB dump doesn't leak usable tokens
Passphrase exposure Only printed to terminal once; hash file has 0600 permissions
Network sniffing Use a reverse proxy with TLS for production (see below)

LAN mode transmits the passphrase and session cookie in plaintext over HTTP. On a trusted home network this is acceptable, but for anything more exposed, put Tuitbot behind a reverse proxy with TLS.

Caddy example (automatic HTTPS with Let's Encrypt):

tuitbot.local {
    reverse_proxy localhost:3001
}

nginx example:

server {
    listen 443 ssl;
    server_name tuitbot.local;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /api/ws {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Upgrading from a Previous Version

If you already have Tuitbot installed, the update is seamless — no manual steps required:

  1. git pull && cargo build (or update via your package manager)
  2. Start the server normally. On first start after the update:
  3. The sessions table migration runs automatically
  4. A passphrase is generated and printed to the terminal
  5. ~/.tuitbot/passphrase_hash is created with 0600 permissions
  6. Everything else works exactly as before — Tauri, dev mode, and CLI are unaffected

If you missed the passphrase in the terminal output, reset it:

tuitbot-server --reset-passphrase

This works even while the server is running — no restart needed.

To start using LAN mode, just add --host 0.0.0.0 to your server command.

Tauri Desktop + LAN Mode

The Tauri desktop app always uses bearer token auth (reads ~/.tuitbot/api_token directly). LAN mode doesn't affect it — the desktop app continues to work exactly as before, even when the server is bound to 0.0.0.0.

Content Sources

LAN mode users typically run in self_host deployment mode. Content source setup works through the browser dashboard:

  • Google Drive (recommended): Open Settings > Content Sources > Connect Google Drive. The browser-based OAuth flow works over LAN -- the popup redirects back to the server's address.

  • Local folder: Available under "Advanced: Local Server Folder" in Settings. Note that local_fs paths resolve relative to the server filesystem, not the client browser's machine. Point to a path that exists on the server (e.g., a mounted NAS share or synced folder).

Set deployment_mode = "self_host" in your config (or TUITBOT_DEPLOYMENT_MODE=self_host) so the dashboard defaults to the Google Drive connector flow instead of a local file picker.

Troubleshooting

"Connection refused" from another device - Verify the server is bound to 0.0.0.0, not 127.0.0.1 - Check firewall rules: port 3001 must be open for TCP

"Invalid passphrase" - Passphrase is case-sensitive and space-separated (4 words if auto-generated) - Reset from the terminal: tuitbot-server --reset-passphrase (no server restart needed) - Or from Settings → LAN Access → Reset Passphrase (requires an active session)

Session expired / redirected to login - Sessions last 30 days. Log in again with the same passphrase - If the server was restarted, existing sessions remain valid (they're stored in the database)

WebSocket not connecting in browser - The browser authenticates the WebSocket via the session cookie — no token needed - Ensure the browser allows cookies for the server's origin