All checks were successful
Test and Publish Templates / test-and-publish (push) Successful in 14s
156 lines
5.5 KiB
Bash
Executable File
156 lines
5.5 KiB
Bash
Executable File
#!/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"
|