Skip to content

Tunnel (Tailscale)

Remote access to Dagu via embedded Tailscale node. No port forwarding, firewall rules, or VPN setup required.

Architecture

How it works:

  1. Dagu starts an embedded Tailscale node using tsnet
  2. The node joins your Tailscale network (tailnet)
  3. A reverse proxy forwards requests to the local Dagu server
  4. Access via http://dagu.<your-tailnet>.ts.net

Quick Start

bash
dagu server --tunnel

First run:

To start this tsnet server, go to: https://login.tailscale.com/a/abc123

Click the URL to authorize. Credentials are saved for subsequent runs.

Access:

http://dagu.<your-tailnet>.ts.net

CLI Flags

FlagTypeDefaultDescription
--tunnel, -tboolfalseEnable tunnel mode
--tunnel-tokenstring""Tailscale auth key for headless login
--tunnel-funnelboolfalseEnable public internet access
--tunnel-httpsboolfalseUse HTTPS (requires admin setup)

Configuration File

yaml
# ~/.config/dagu/config.yaml
tunnel:
  enabled: true

  tailscale:
    # Auth key for headless authentication (optional)
    # Generate at: https://login.tailscale.com/admin/settings/keys
    authKey: "tskey-auth-xxxxx"

    # Machine name in tailnet (default: "dagu")
    hostname: "dagu"

    # Enable Tailscale Funnel for public access
    funnel: false

    # Use HTTPS for tailnet-only access
    https: false

    # State directory (default: ~/.dagu_data/tailscale)
    stateDir: ""

  # Allow terminal access via tunnel (default: false)
  allowTerminal: false

  # IP allowlist (empty = allow all)
  allowedIPs: []

  # Rate limiting for authentication
  rateLimiting:
    enabled: false
    loginAttempts: 5        # Max attempts per window
    windowSeconds: 300      # 5 minutes
    blockDurationSeconds: 900  # 15 minutes

Environment Variables

VariableConfig Key
DAGU_TUNNEL_ENABLEDtunnel.enabled
DAGU_TUNNEL_TAILSCALE_AUTH_KEYtunnel.tailscale.authKey
DAGU_TUNNEL_TAILSCALE_HOSTNAMEtunnel.tailscale.hostname
DAGU_TUNNEL_TAILSCALE_FUNNELtunnel.tailscale.funnel
DAGU_TUNNEL_TAILSCALE_HTTPStunnel.tailscale.https
DAGU_TUNNEL_TAILSCALE_STATE_DIRtunnel.tailscale.stateDir
DAGU_TUNNEL_ALLOW_TERMINALtunnel.allowTerminal
DAGU_TUNNEL_RATE_LIMITING_ENABLEDtunnel.rateLimiting.enabled
DAGU_TUNNEL_RATE_LIMITING_LOGIN_ATTEMPTStunnel.rateLimiting.loginAttempts
DAGU_TUNNEL_RATE_LIMITING_WINDOW_SECONDStunnel.rateLimiting.windowSeconds
DAGU_TUNNEL_RATE_LIMITING_BLOCK_DURATION_SECONDStunnel.rateLimiting.blockDurationSeconds

Modes

Default: HTTP (Tailnet Only)

bash
dagu server --tunnel
PropertyValue
URLhttp://dagu.<tailnet>.ts.net
Port80
EncryptionWireGuard (network layer)
AccessTailnet devices only
SetupNone

Traffic is encrypted by WireGuard. HTTP is used because TLS on top of WireGuard is redundant.

HTTPS (Tailnet Only)

bash
dagu server --tunnel --tunnel-https
PropertyValue
URLhttps://dagu.<tailnet>.ts.net
Port443
EncryptionWireGuard + TLS
AccessTailnet devices only
SetupEnable HTTPS in Tailscale admin

Setup:

  1. Go to https://login.tailscale.com/admin/dns
  2. Enable "HTTPS Certificates"

Funnel: Public Internet

bash
dagu server --tunnel --tunnel-funnel
PropertyValue
URLhttps://dagu.<tailnet>.ts.net
Port443
EncryptionTLS
AccessAnyone on internet
SetupEnable Funnel in Tailscale admin

Setup:

  1. Go to https://login.tailscale.com/admin/acls
  2. Add to policy:
json
{
  "nodeAttrs": [
    {
      "target": ["*"],
      "attr": ["funnel"]
    }
  ]
}

Authentication Required

When using Funnel, ensure authentication is enabled:

yaml
server:
  auth:
    mode: builtin  # or oidc

Authentication Flow

Interactive Login (Default)

1. Start server
   $ dagu server --tunnel

2. Server prints login URL
   To start this tsnet server, go to: https://login.tailscale.com/a/abc123

3. Click URL → Authorize in browser

4. State saved to ~/.dagu_data/tailscale/tailscaled.state

5. Subsequent runs auto-connect (no login needed)

Headless Login (Auth Key)

For automated deployments without interactive login:

bash
# Generate auth key at https://login.tailscale.com/admin/settings/keys
dagu server --tunnel --tunnel-token=tskey-auth-kxxxxxxx

Or via environment:

bash
export DAGU_TUNNEL_TAILSCALE_AUTH_KEY=tskey-auth-kxxxxxxx
dagu server --tunnel

File Locations

~/.dagu_data/
├── tailscale/
│   └── tailscaled.state   # Persistent auth credentials
└── tunnel_url             # Last known tunnel URL

API Endpoint

GET /api/v2/services/tunnel

Response:

json
{
  "enabled": true,
  "provider": "tailscale",
  "status": "connected",
  "publicUrl": "http://dagu.tail01cbab.ts.net",
  "mode": "direct",
  "isPublic": false,
  "startedAt": "2024-01-27T12:45:44Z"
}

Status values: disabled, connecting, connected, reconnecting, error

Mode values: direct (tailnet), funnel (public)

Technical Details

  • Connection timeout: 60 seconds
  • Status poll interval: 100ms
  • Graceful degradation: Tunnel failure does not stop the server
  • Proxy target: Connects to 127.0.0.1:<port> (auto-converts 0.0.0.0)

See Also

Released under the MIT License.