Archived as of 2026-02-07 - use the official tailscale install script from JetKVM
This project installs and configures Tailscale on a JetKVM device (BusyBox/dropbear) using Terraform provisioners.
It follows the approach described by Brandon Tuttle @tutman96 in his tutorial Installing Tailscale on JetKVM and automates the end-to-end procedure including upload, extraction, init script installation, daemon start, and tailscale up through Terraform.
Note: Per the tutorial,
/etc/init.dcontents are not persistent across OS updates. After a JetKVM OS upgrade, re-apply this Terraform to restoreS22tailscale.
Features include:
- Pulls and uploads Tailscale static tar via SSH pipe (no
scprequired on JetKVM) - Installs binaries under
/userdata/tailscale/ - Creates
/etc/init.d/S22tailscaleto starttailscaledon boot - Starts
tailscaledand runstailscale upwith optional auth key and flags - Idempotent guards and Terraform triggers to re-run when inputs change
Note: JetKVM set up normally with Developer Mode enabled and your SSH public key added (see JetKVM docs). Your workstation has
terraform,ssh,curl, andgzipavailable (macOS & Linux works well).
-
Configure variables via a
.tfvarsfile or environment variables. Exampleterraform.tfvars:device_ip = "10.10.0.6" ssh_private_key_file = pathexpand("~/.ssh/id_ed25519") tailscale_version = "1.88.3" tailscale_auth_key = null # or "tskey-auth-..." if using key auth tailscale_extra_args = "--advertise-tags=tag:jetkvm"
Alternatively export secrets safely:
export TF_VAR_tailscale_auth_key="tskey-auth-..."
-
Initialize and apply:
terraform init terraform plan -out plan.out terraform apply plan.out
-
Verify on the device:
ssh root@$JETKVM_IP \ -i $SSH_PRIVATE_KEY_FILE \ "/userdata/tailscale/tailscale status || true"
If no auth key is provided,
tailscale upwill prompt for interactive device auth. Follow the URL to add the JetKVM to your Tailnet.
The module is located in modules/tailscale-jetkvm.
Key inputs (see variables.tf for all):
device_ip(string): JetKVM IP, for example10.10.0.6.ssh_user(string): SSH user, defaults toroot.ssh_private_key_file(string): Path to your private key.
Key inputs (see variables.tf for all):
device_ip(string): JetKVM IP, for example10.10.0.6.ssh_user(string): SSH user, defaults toroot.ssh_private_key_file(string): Path to your private key.tailscale_version(string): Tailscale version, e.g.,1.88.3.tailscale_arch(string): Architecture, defaults toarm.tailscale_dir(string): Defaults to/userdata/tailscale.tailscale_state_dir(string): Defaults to/userdata/tailscale-state.tailscale_auth_key(sensitive string or null): Auth key for non-interactive setup.tailscale_extra_args(string): Extra flags fortailscale up.nftables_mode(bool): EnablesTS_DEBUG_FIREWALL_MODE=nftables.
device_iptailscale_dirtailscale_state_dir
- Upgrade Tailscale: change
tailscale_versionand re-apply. - Change args (tags, routes): update
tailscale_extra_argsand re-apply. - OS update on JetKVM: re-apply to restore
/etc/init.d/S22tailscale.
-
Connectivity: ensure you can SSH to the device IP as
root. -
Auth key issues: export
TF_VAR_tailscale_auth_keyto avoid committing secrets. -
Verify running:
ssh root@<ip> -i <key> "/userdata/tailscale/tailscale status"
-
If
tailscaledfails on boot but works when run later, check/tmp/ts.logon the device and ensure/dev/net/tunexists. The init script now attemptsmodprobe tunand retries for up to ~10s. See: Getting Tailscale to work on my JetKVM
Some JetKVM firmware versions may assign a new MAC on reboot, causing DHCP to issue new IPs. Track firmware issues and consider DHCP reservations that match the current MAC or a firmware update as fixes emerge. See discussion mentioned in Getting Tailscale to work on my JetKVM.
Run Terraform formatting and basic validation before applying:
terraform fmt -recursive
terraform validateOptional: run tflint:
tflint --init || true
tflint- Installing Tailscale on JetKVM by Brandon Tuttle (@tutman96)
- Getting Tailscale to work on my JetKVM by Shane McDonald (@shanemcd)
Copyright (C) 2025 Lukas 'dotWee' Wolfsteiner lukas@wolfsteiner.media
Licensed under the Do What The fuck You Want To public license.