Add 24 files
All checks were successful
Test and Publish Templates / test-and-publish (push) Successful in 14s

This commit is contained in:
j
2026-02-26 15:04:20 +13:00
parent 26b74f91a5
commit 1a61eec6ac
12 changed files with 423 additions and 0 deletions

20
tailscale-relay/backup.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME" "BACKUP_FILE" "TEMP_DIR"
if ! lxc info "${CONTAINER_NAME}" &>/dev/null; then
_die "Container ${CONTAINER_NAME} does not exist."
fi
mkdir -p "${TEMP_DIR}/backup"
# Export tailscale state from the container
echo "Backing up Tailscale state..."
lxc exec "${CONTAINER_NAME}" -- tar -czf /tmp/tailscale-state.tgz -C /var/lib/tailscale . 2>/dev/null || _die "Failed to archive tailscale state"
lxc file pull "${CONTAINER_NAME}/tmp/tailscale-state.tgz" "${TEMP_DIR}/backup/tailscale-state.tgz" || _die "Failed to pull backup from container"
lxc exec "${CONTAINER_NAME}" -- rm -f /tmp/tailscale-state.tgz
tar -czf "${BACKUP_FILE}" -C "${TEMP_DIR}/backup" .
echo "Backup completed successfully"

View File

@@ -0,0 +1,35 @@
# Service settings for Tailscale Relay (LXC)
# (can also override anything in the template_info.env file to make it specific to this server)
# REQUIRED: Your Tailscale authentication key
# Get this from: https://login.tailscale.com/admin/settings/keys
# Can be reusable or one-time use
TAILSCALE_AUTH_KEY=
# REQUIRED: Network settings for the LXC container's static IP
# The container gets its own real IP on the host's physical network.
HOST_INTERFACE=eth0
STATIC_IP=192.168.0.50/24
GATEWAY=192.168.0.1
# Optional: DNS servers (comma-separated)
DNS_SERVERS="8.8.8.8,8.8.4.4"
# REQUIRED: Peer relay UDP port
# This is the port used by Tailscale's peer relay feature.
# Forward this UDP port on your router to the container's STATIC_IP.
RELAY_PORT=3478
# Optional: Custom hostname for this node
# If not set, will use the container name
TAILSCALE_HOSTNAME=
# Optional: Additional Tailscale arguments
# Examples:
# TAILSCALE_EXTRA_ARGS="--advertise-exit-node"
# TAILSCALE_EXTRA_ARGS="--accept-routes"
# TAILSCALE_EXTRA_ARGS="--advertise-routes=10.0.0.0/24"
TAILSCALE_EXTRA_ARGS=
# Server Settings
SSH_USER="dropshell"

19
tailscale-relay/destroy.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME"
echo "Destroying Tailscale Relay service and all data..."
if lxc info "${CONTAINER_NAME}" &>/dev/null; then
lxc stop "${CONTAINER_NAME}" --force 2>/dev/null || true
lxc delete "${CONTAINER_NAME}" --force 2>/dev/null || true
echo "Container deleted."
else
echo "Container does not exist."
fi
echo ""
echo "Tailscale Relay has been completely destroyed."
echo "Note: You should also remove this node from your Tailscale admin console at:"
echo " https://login.tailscale.com/admin/machines"

155
tailscale-relay/install.sh Executable file
View File

@@ -0,0 +1,155 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME" "LXC_IMAGE" "TAILSCALE_AUTH_KEY" "HOST_INTERFACE" "STATIC_IP" "GATEWAY" "RELAY_PORT"
# Check LXC is available
if ! command -v lxc &>/dev/null; then
_die "LXC is not installed. Install it with: sudo snap install lxd --channel=latest/stable && sudo lxd init"
fi
# Check LXC daemon is accessible
if ! lxc list &>/dev/null; then
_die "Cannot connect to LXD. Ensure the LXD daemon is running and your user is in the 'lxd' group."
fi
echo "Installing Tailscale Relay (LXC)..."
# Stop and remove existing container if it exists
if lxc info "${CONTAINER_NAME}" &>/dev/null; then
echo "Removing existing container..."
lxc stop "${CONTAINER_NAME}" --force 2>/dev/null || true
lxc delete "${CONTAINER_NAME}" --force 2>/dev/null || true
fi
# Create the container (without starting)
echo "Creating LXC container from ${LXC_IMAGE}..."
lxc init "${LXC_IMAGE}" "${CONTAINER_NAME}" || _die "Failed to create LXC container"
# Configure bridged networking on the host interface
echo "Configuring bridged networking on ${HOST_INTERFACE}..."
lxc config device remove "${CONTAINER_NAME}" eth0 2>/dev/null || true
lxc config device add "${CONTAINER_NAME}" eth0 nic \
nictype=macvlan \
parent="${HOST_INTERFACE}" || _die "Failed to configure network device"
# Enable nesting (required when running LXC inside another LXC, e.g. Proxmox)
lxc config set "${CONTAINER_NAME}" security.nesting=true
# Allow TUN device inside the container (needed by tailscale's WireGuard interface)
lxc config set "${CONTAINER_NAME}" raw.lxc "lxc.cgroup2.devices.allow = c 10:200 rwm"
lxc config device add "${CONTAINER_NAME}" tun unix-char path=/dev/net/tun 2>/dev/null || true
# Start the container
echo "Starting container..."
lxc start "${CONTAINER_NAME}" || _die "Failed to start container"
# Wait for container to be ready
echo "Waiting for container to be ready..."
READY=false
for i in $(seq 1 30); do
if lxc exec "${CONTAINER_NAME}" -- test -d /etc/netplan 2>/dev/null; then
READY=true
break
fi
sleep 1
done
if [ "$READY" != "true" ]; then
_die "Container did not become ready in time"
fi
# Extract IP without CIDR for display
CONTAINER_IP="${STATIC_IP%%/*}"
# Configure static IP via netplan
echo "Configuring static IP ${STATIC_IP}..."
lxc exec "${CONTAINER_NAME}" -- bash -c "rm -f /etc/netplan/*.yaml"
lxc exec "${CONTAINER_NAME}" -- bash -c "cat > /etc/netplan/10-static.yaml << 'NETPLANEOF'
network:
version: 2
ethernets:
eth0:
dhcp4: false
addresses:
- ${STATIC_IP}
routes:
- to: default
via: ${GATEWAY}
nameservers:
addresses: [${DNS_SERVERS}]
NETPLANEOF"
lxc exec "${CONTAINER_NAME}" -- chmod 600 /etc/netplan/10-static.yaml
lxc exec "${CONTAINER_NAME}" -- netplan apply 2>/dev/null || true
# Wait for network to come up
sleep 3
# Verify network connectivity
echo "Verifying network connectivity..."
if ! lxc exec "${CONTAINER_NAME}" -- ping -c 1 -W 5 "${GATEWAY}" &>/dev/null; then
echo "Warning: Cannot reach gateway ${GATEWAY} from container. Check HOST_INTERFACE and network settings."
fi
# Install Tailscale inside the container
echo "Installing Tailscale inside the container..."
lxc exec "${CONTAINER_NAME}" -- bash -c "curl -fsSL https://tailscale.com/install.sh | sh" || _die "Failed to install Tailscale"
# Connect to Tailscale network
echo "Connecting to Tailscale network..."
TAILSCALE_UP_CMD="tailscale up --authkey=${TAILSCALE_AUTH_KEY}"
if [ -n "$TAILSCALE_HOSTNAME" ]; then
TAILSCALE_UP_CMD="${TAILSCALE_UP_CMD} --hostname=${TAILSCALE_HOSTNAME}"
fi
if [ -n "$TAILSCALE_EXTRA_ARGS" ]; then
TAILSCALE_UP_CMD="${TAILSCALE_UP_CMD} ${TAILSCALE_EXTRA_ARGS}"
fi
# Execute tailscale up with retries
RETRY_COUNT=0
MAX_RETRIES=5
RETRY_DELAY=10
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if lxc exec "${CONTAINER_NAME}" -- ${TAILSCALE_UP_CMD} 2>&1; then
echo "Successfully connected to Tailscale network!"
break
else
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
echo "Connection attempt $RETRY_COUNT failed. Retrying in ${RETRY_DELAY} seconds..."
sleep $RETRY_DELAY
else
echo "Warning: Failed to connect after $MAX_RETRIES attempts."
echo "You may need to connect manually using:"
echo " lxc exec ${CONTAINER_NAME} -- tailscale up"
fi
fi
done
# Enable peer relay on the configured port
echo "Enabling peer relay on port ${RELAY_PORT}/udp..."
lxc exec "${CONTAINER_NAME}" -- tailscale set --relay-server-port="${RELAY_PORT}" || echo "Warning: Failed to enable peer relay. You may need to enable it manually."
# Get the Tailscale IP
TAILSCALE_IP=$(lxc exec "${CONTAINER_NAME}" -- tailscale ip -4 2>/dev/null || echo "not yet available")
echo ""
echo "=========================================="
echo "Tailscale Relay installation complete!"
echo "=========================================="
echo ""
echo " LAN IP: ${CONTAINER_IP}"
echo " Tailscale IP: ${TAILSCALE_IP}"
echo " Relay port: ${RELAY_PORT}/udp"
echo " Container: ${CONTAINER_NAME}"
echo ""
echo "The container has its own IP (${CONTAINER_IP}) on your LAN."
echo "Forward ${RELAY_PORT}/udp on your router to ${CONTAINER_IP}."
echo ""
echo "You also need to add relay ACL grants in your tailnet policy."
echo "See: https://tailscale.com/kb/1403/peer-relay"
echo ""
echo "Manage at: https://login.tailscale.com/admin/machines"

14
tailscale-relay/logs.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME"
if ! lxc info "${CONTAINER_NAME}" &>/dev/null; then
_die "Container ${CONTAINER_NAME} does not exist."
fi
if ! lxc info "${CONTAINER_NAME}" 2>/dev/null | grep -q "Status: RUNNING"; then
_die "Container ${CONTAINER_NAME} is not running."
fi
lxc exec "${CONTAINER_NAME}" -- journalctl -u tailscaled --no-pager -n 100 "$@"

26
tailscale-relay/restore.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME" "BACKUP_FILE" "TEMP_DIR"
if ! lxc info "${CONTAINER_NAME}" 2>/dev/null | grep -q "Status: RUNNING"; then
_die "Container ${CONTAINER_NAME} must be running for restore. Run install.sh first."
fi
mkdir -p "${TEMP_DIR}/restore"
tar -xzf "${BACKUP_FILE}" -C "${TEMP_DIR}/restore"
echo "Restoring Tailscale state..."
# Stop tailscale before restoring state
lxc exec "${CONTAINER_NAME}" -- systemctl stop tailscaled 2>/dev/null || true
# Push state archive into container and extract
lxc file push "${TEMP_DIR}/restore/tailscale-state.tgz" "${CONTAINER_NAME}/tmp/tailscale-state.tgz" || _die "Failed to push backup to container"
lxc exec "${CONTAINER_NAME}" -- bash -c "rm -rf /var/lib/tailscale/* && tar -xzf /tmp/tailscale-state.tgz -C /var/lib/tailscale" || _die "Failed to extract state"
lxc exec "${CONTAINER_NAME}" -- rm -f /tmp/tailscale-state.tgz
# Restart tailscale
lxc exec "${CONTAINER_NAME}" -- systemctl start tailscaled
echo "Restore completed successfully"

13
tailscale-relay/ssh.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME"
if ! lxc info "${CONTAINER_NAME}" 2>/dev/null | grep -q "Status: RUNNING"; then
_die "Container ${CONTAINER_NAME} is not running. Start it first."
fi
echo "Entering Tailscale Relay container shell..."
echo "Type 'exit' to leave the container."
echo ""
lxc exec "${CONTAINER_NAME}" -- /bin/bash

45
tailscale-relay/start.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME" "RELAY_PORT"
# Check LXC is available
if ! command -v lxc &>/dev/null; then
_die "LXC is not installed."
fi
echo "Starting Tailscale Relay container..."
# Check container exists
if ! lxc info "${CONTAINER_NAME}" &>/dev/null; then
_die "Container ${CONTAINER_NAME} does not exist. Run install.sh first."
fi
# Start if not already running
if lxc info "${CONTAINER_NAME}" 2>/dev/null | grep -q "Status: RUNNING"; then
echo "Container is already running."
else
lxc start "${CONTAINER_NAME}" || _die "Failed to start container"
sleep 3
fi
# Wait for tailscaled to be ready
echo "Waiting for Tailscale daemon..."
for i in $(seq 1 15); do
if lxc exec "${CONTAINER_NAME}" -- tailscale status &>/dev/null; then
break
fi
sleep 1
done
# Ensure relay is enabled
lxc exec "${CONTAINER_NAME}" -- tailscale set --relay-server-port="${RELAY_PORT}" 2>/dev/null || true
CONTAINER_IP="${STATIC_IP%%/*}"
TAILSCALE_IP=$(lxc exec "${CONTAINER_NAME}" -- tailscale ip -4 2>/dev/null || echo "not yet available")
echo ""
echo "Tailscale Relay started."
echo " LAN IP: ${CONTAINER_IP}"
echo " Tailscale IP: ${TAILSCALE_IP}"
echo " Relay port: ${RELAY_PORT}/udp"

26
tailscale-relay/status.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME"
if ! command -v lxc &>/dev/null; then
echo "Unknown"
exit 0
fi
if ! lxc info "${CONTAINER_NAME}" &>/dev/null; then
echo "Unknown"
exit 0
fi
if ! lxc info "${CONTAINER_NAME}" 2>/dev/null | grep -q "Status: RUNNING"; then
echo "Stopped"
exit 0
fi
# Container is running - check if tailscale is connected
if lxc exec "${CONTAINER_NAME}" -- tailscale status &>/dev/null; then
echo "Running"
else
echo "Error"
fi

23
tailscale-relay/stop.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME"
echo "Stopping Tailscale Relay container..."
if ! lxc info "${CONTAINER_NAME}" &>/dev/null; then
echo "Container ${CONTAINER_NAME} does not exist."
exit 0
fi
if lxc info "${CONTAINER_NAME}" 2>/dev/null | grep -q "Status: RUNNING"; then
# Gracefully disconnect from Tailscale network before stopping
echo "Disconnecting from Tailscale network..."
lxc exec "${CONTAINER_NAME}" -- tailscale down 2>/dev/null || true
sleep 2
lxc stop "${CONTAINER_NAME}" || _die "Failed to stop container"
echo "Tailscale Relay container stopped."
else
echo "Container is not running."
fi

View File

@@ -0,0 +1,30 @@
# DO NOT EDIT THIS FILE FOR YOUR SERVICE!
# This file is replaced from the template whenever there is an update.
# Edit the service.env file to make changes.
# Template to use - always required!
TEMPLATE=tailscale-relay
REQUIRES_HOST_ROOT=false
REQUIRES_DOCKER=false
REQUIRES_DOCKER_ROOT=false
# Service settings
CONTAINER_NAME=tailscale-relay
# LXC image to use
LXC_IMAGE="ubuntu:24.04"
# Tailscale defaults (to be overridden in service.env)
TAILSCALE_AUTH_KEY=""
TAILSCALE_HOSTNAME=""
TAILSCALE_EXTRA_ARGS=""
# Relay port - the UDP port for the peer relay feature
# Forward this port on your router to the container's STATIC_IP
RELAY_PORT="3478"
# Network defaults (to be overridden in service.env)
HOST_INTERFACE=""
STATIC_IP=""
GATEWAY=""
DNS_SERVERS="8.8.8.8,8.8.4.4"

17
tailscale-relay/uninstall.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# shellcheck disable=SC1091
source "${AGENT_PATH}/common.sh"
_check_required_env_vars "CONTAINER_NAME"
echo "Uninstalling Tailscale Relay service..."
if lxc info "${CONTAINER_NAME}" &>/dev/null; then
bash ./stop.sh 2>/dev/null || true
echo "Stopping container..."
lxc stop "${CONTAINER_NAME}" --force 2>/dev/null || true
fi
echo "Tailscale Relay service has been stopped."
echo "The container has been preserved. To completely remove it, run destroy.sh"
echo ""
echo "You may also want to remove this node from your Tailscale admin console."