Merge pull request #16 from buildplan/test

tailscale/headscale now configureable in the setup script
This commit is contained in:
buildplan
2025-06-29 00:07:58 +01:00
committed by GitHub
2 changed files with 233 additions and 28 deletions

View File

@@ -1,8 +1,8 @@
# Debian & Ubuntu Server Setup & Hardening Script
**Version:** 4.0
**Version:** 4.1
**Last Updated:** 2025-06-28
**Last Updated:** 2025-06-29
**Compatible With:**
@@ -22,6 +22,7 @@ This script automates the initial setup and security hardening of a fresh Debian
- **Automated Security Updates**: Enables `unattended-upgrades` for automatic security patches.
- **System Stability**: Configures NTP time synchronization with `chrony` and optional swap file setup for low-RAM systems.
- **Remote rsync Backups**: Configures automated `rsync` backups over SSH to any compatible server (e.g., Hetzner Storage Box), with SSH key automation (`sshpass` or manual), cron scheduling, ntfy/Discord notifications, and a customizable exclude file.
- **Tailscale VPN**: Installs Tailscale and connects to the standard Tailscale network (pre-auth key required) or a custom server (URL and key required). Configures optional flags (`--ssh`, `--advertise-exit-node`, `--accept-dns`, `--accept-routes`).
- **Safety First**: Backs up critical configuration files before modification, stored in `/root/setup_harden_backup_*`.
- **Optional Software**: Offers interactive installation of:
- Docker & Docker Compose
@@ -37,6 +38,7 @@ This script automates the initial setup and security hardening of a fresh Debian
- Root or `sudo` privileges.
- Internet access for package downloads.
- For remote backups: An SSH-accessible server (e.g., Hetzner Storage Box) with credentials or SSH key access.
- For Tailscale: A pre-auth key from https://login.tailscale.com/admin (standard, starts with `tskey-auth-`) or from a custom server (e.g., `https://ts.mydomain.cloud`).
### 1. Download the Script
@@ -59,7 +61,7 @@ sudo ./setup_harden_debian_ubuntu.sh --quiet
> **Warning**: The script pauses to verify SSH access on the new port before disabling old access methods. **Test the new SSH connection from a separate terminal before proceeding!**
>
> Ensure your VPS providers firewall allows the custom SSH port and the backup servers SSH port (e.g., 23 for Hetzner Storage Box).
> Ensure your VPS providers firewall allows the custom SSH port, backup servers SSH port (e.g., 23 for Hetzner Storage Box), and Tailscale traffic (UDP 41641 for direct connections).
## What It Does
@@ -71,11 +73,11 @@ sudo ./setup_harden_debian_ubuntu.sh --quiet
| **SSH Hardening** | Disables root login, enforces key-based auth, and sets a custom port. |
| **Firewall Setup** | Configures UFW to deny incoming traffic by default, allowing specific ports. |
| **Remote Backup Setup** | Configures `rsync` backups to an SSH server (e.g., `u457300-sub4@u457300.your-storagebox.de:23`). Creates `/root/run_backup.sh`, `/root/rsync_exclude.txt`, and schedules a cron job. Supports ntfy/Discord notifications. |
| **Tailscale Setup** | Installs Tailscale and connects to the standard Tailscale network (pre-auth key starting with `tskey-auth-`) or a custom server (any valid key). Configures optional flags (`--ssh`, `--advertise-exit-node`, `--accept-dns`, `--accept-routes`). |
| **System Backups** | Saves timestamped configuration backups in `/root/setup_harden_backup_*`. |
| **Swap File Setup** | Creates an optional swap file (e.g., 2G) with tuned settings. |
| **Timezone & Locales** | Configures timezone and system locales interactively. |
| **Docker Install** | Installs Docker Engine and adds the user to the `docker` group. |
| **Tailscale Install** | Installs the Tailscale client for Mesh VPN. |
| **Final Cleanup** | Removes unused packages and reloads daemons. |
## Logs & Backups
@@ -96,6 +98,11 @@ After rebooting, verify the setup:
- **Hostname**: `hostnamectl`
- **Docker Status** (if installed): `docker ps`
- **Tailscale Status** (if installed): `tailscale status`
- **Tailscale Verification** (if configured):
- Check connection: `tailscale status`
- Test Tailscale SSH (if enabled): `tailscale ssh <username>@<tailscale-ip>`
- Verify exit node (if enabled): Check Tailscale admin console
- If not connected, run the `tailscale up` command shown in the script output
- **Remote Backup** (if configured):
- Verify SSH key: `cat /root/.ssh/id_ed25519.pub`
- Copy key (if not done): `ssh-copy-id -p <backup_port> -s <backup_user@backup_host>`
@@ -109,6 +116,7 @@ After rebooting, verify the setup:
- Ubuntu 22.04, 24.04, 24.10 (experimental)
- Cloud providers: DigitalOcean, Oracle Cloud, Hetzner, Netcup
- Backup destinations: Hetzner Storage Box, custom SSH servers
- Tailscale: Standard network, custom self-hosted servers
## Important Notes
@@ -117,6 +125,7 @@ After rebooting, verify the setup:
- Test in a non-production environment (e.g., staging VM) first.
- Maintain out-of-band console access in case of SSH lockout.
- For Hetzner Storage Box, ensure `~/.ssh/` exists on the remote server: `ssh -p 23 <backup_user@backup_host> "mkdir -p ~/.ssh && chmod 700 ~/.ssh"`.
- For Tailscale, generate a pre-auth key from https://login.tailscale.com/admin (standard, must start with `tskey-auth-`) or your custom server (any valid key). Ensure UDP 41641 is open for Tailscale traffic.
## Troubleshooting
@@ -172,6 +181,33 @@ If backups fail:
6. **Summary Errors**:
- If summary shows `Remote Backup: Not configured`, verify: `ls -l /root/run_backup.sh`
### Tailscale Issues
If Tailscale fails to connect:
1. **Verify Installation**:
- Check: `command -v tailscale`
- Service status: `systemctl status tailscaled`
2. **Check Connection**:
- Run: `tailscale status`
- Verify server: `tailscale status --json | grep ControlURL`
- Check logs: `sudo journalctl -u tailscaled`
3. **Test Pre-Auth Key**:
- Re-run the command shown in the script output (e.g., `sudo tailscale up --auth-key=<key> --operator=<username>` or with `--login-server=<url>`).
- For custom servers, ensure the key is valid for the specified server (e.g., generated from `https://ts.mydomain.cloud`).
4. **Additional Flags**:
- Verify SSH: `tailscale ssh <username>@<tailscale-ip>`
- Check exit node: Tailscale admin console
- Verify DNS: `cat /etc/resolv.conf`
- Check routes: `tailscale status`
5. **Network Issues**:
- Ensure UDP 41641 is open: `nc -zvu <tailscale-server> 41641`
- Check VPS firewall for Tailscale traffic.
## [MIT](https://github.com/buildplan/setup_harden_server/blob/main/LICENSE) License
This script is open-source and provided "as is" without warranty. Use at your own risk.

View File

@@ -1,8 +1,9 @@
#!/bin/bash
# Debian 12 and Ubuntu Server Hardening Interactive Script
# Version: 4.0 | 2025-06-28
# Version: 4.1 | 2025-06-29
# Changelog:
# - v4.1: Added tailscale config to connect to tailscale or headscale server
# - v4.0: Added automated backup config. Mainly for Hetzner Storage Box but can be used for any rsync/SSH enabled remote solution.
# - v3.*: Improvements to script flow and fixed bugs which were found in tests at Oracle Cloud
#
@@ -82,7 +83,7 @@ print_header() {
echo -e "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}"
echo -e "${CYAN}║ v4.0 | 2025-06-28${NC}"
echo -e "${CYAN}║ v4.1 | 2025-06-29${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}"
echo
@@ -902,33 +903,181 @@ EOF
}
install_tailscale() {
if ! confirm "Install Tailscale VPN (Optional)?"; then
if ! confirm "Install and configure Tailscale VPN (Optional)?"; then
print_info "Skipping Tailscale installation."
log "Tailscale installation skipped by user."
return 0
fi
print_section "Tailscale VPN Installation"
print_section "Tailscale VPN Installation and Configuration"
if command -v tailscale >/dev/null 2>&1; then
print_info "Tailscale already installed."
if systemctl is-active --quiet tailscaled && tailscale status >/dev/null 2>&1; then
print_success "Tailscale service is active and connected."
return 0
else
print_warning "Tailscale installed but service is not active or not connected."
fi
else
print_info "Installing Tailscale..."
curl -fsSL https://tailscale.com/install.sh -o /tmp/tailscale_install.sh
chmod +x /tmp/tailscale_install.sh
if ! grep -q "tailscale" /tmp/tailscale_install.sh; then
print_error "Downloaded Tailscale install script appears invalid."
rm -f /tmp/tailscale_install.sh
log "Tailscale installation failed: Invalid install script."
return 0
fi
if ! /tmp/tailscale_install.sh; then
print_error "Failed to install Tailscale."
rm -f /tmp/tailscale_install.sh
log "Tailscale installation failed."
return 0
fi
rm -f /tmp/tailscale_install.sh
print_success "Tailscale installation complete."
log "Tailscale installation completed."
fi
# --- Configure Tailscale Connection ---
if systemctl is-active --quiet tailscaled && tailscale status >/dev/null 2>&1 && tailscale status | grep -q "^[^ ]* \+${SERVER_NAME} \+"; then
print_info "Tailscale is already connected (hostname: $SERVER_NAME)."
return 0
fi
print_info "Installing Tailscale..."
curl -fsSL https://tailscale.com/install.sh -o /tmp/tailscale_install.sh
chmod +x /tmp/tailscale_install.sh
# Simple sanity check on the downloaded script
if ! grep -q "tailscale" /tmp/tailscale_install.sh; then
print_error "Downloaded Tailscale install script appears invalid."
rm -f /tmp/tailscale_install.sh
exit 1
print_info "Configuring Tailscale connection..."
echo -e "${CYAN}Choose Tailscale connection method:${NC}"
echo -e " 1) Standard Tailscale (requires pre-auth key from https://login.tailscale.com/admin)"
echo -e " 2) Custom Tailscale server (requires server URL and pre-auth key)"
read -rp "$(echo -e "${CYAN}Enter choice (1-2) [1]: ${NC}")" TS_CONNECTION
TS_CONNECTION=${TS_CONNECTION:-1}
local AUTH_KEY LOGIN_SERVER=""
if [[ "$TS_CONNECTION" == "2" ]]; then
while true; do
read -rp "$(echo -e "${CYAN}Enter Tailscale server URL (e.g., https://ts.mydomain.cloud): ${NC}")" LOGIN_SERVER
if [[ "$LOGIN_SERVER" =~ ^https://[a-zA-Z0-9.-]+(:[0-9]+)?$ ]]; then break; else print_error "Invalid URL. Must start with https://. Try again."; fi
done
fi
if ! /tmp/tailscale_install.sh; then
print_error "Failed to install Tailscale."
rm -f /tmp/tailscale_install.sh
exit 1
while true; do
read -rp "$(echo -e "${CYAN}Enter Tailscale pre-auth key: ${NC}")" AUTH_KEY
if [[ "$TS_CONNECTION" == "1" && "$AUTH_KEY" =~ ^tskey-auth- ]]; then break
elif [[ "$TS_CONNECTION" == "2" && -n "$AUTH_KEY" ]]; then
print_warning "Ensure the pre-auth key is valid for your custom Tailscale server ($LOGIN_SERVER)."
break
else
print_error "Invalid key format. For standard connection, key must start with 'tskey-auth-'. For custom server, key cannot be empty."
fi
done
local TS_COMMAND="tailscale up"
if [[ "$TS_CONNECTION" == "2" ]]; then
TS_COMMAND="$TS_COMMAND --login-server=$LOGIN_SERVER"
fi
rm -f /tmp/tailscale_install.sh
print_warning "ACTION REQUIRED: Run 'sudo tailscale up' after script finishes."
print_success "Tailscale installation complete."
log "Tailscale installation completed."
TS_COMMAND="$TS_COMMAND --auth-key=$AUTH_KEY --operator=$USERNAME"
print_info "Connecting to Tailscale with: $TS_COMMAND"
if ! $TS_COMMAND; then
print_warning "Failed to connect to Tailscale. Possible issues: invalid pre-auth key, network restrictions, or server unavailability."
print_info "Please run the following command manually after resolving the issue:"
echo -e "${CYAN} $TS_COMMAND${NC}"
log "Tailscale connection failed: $TS_COMMAND"
else
# Verify connection status with retries
local RETRIES=3
local DELAY=5
local CONNECTED=false
for ((i=1; i<=RETRIES; i++)); do
if tailscale status 2>/dev/null | grep -q "^[^ ]* \+${SERVER_NAME} \+.*[^offline]$"; then
CONNECTED=true
break
fi
print_info "Waiting for Tailscale to connect ($i/$RETRIES)..."
sleep $DELAY
done
if $CONNECTED; then
print_success "Tailscale connected successfully (hostname: $SERVER_NAME)."
log "Tailscale connected: $TS_COMMAND"
# Store connection details for summary
echo "${LOGIN_SERVER:-https://controlplane.tailscale.com}" > /tmp/tailscale_server
echo "None" > /tmp/tailscale_flags
else
print_warning "Tailscale connection attempt succeeded, but hostname ($SERVER_NAME) not found in 'tailscale status'."
print_info "Please verify with 'tailscale status' and run the following command manually if needed:"
echo -e "${CYAN} $TS_COMMAND${NC}"
log "Tailscale connection not verified: $TS_COMMAND"
tailscale status > /tmp/tailscale_status.txt 2>&1
log "Tailscale status output saved to /tmp/tailscale_status.txt for debugging"
fi
fi
# --- Configure Additional Flags ---
print_info "Select additional Tailscale options to configure (comma-separated, e.g., 1,3):"
echo -e "${CYAN} 1) SSH (--ssh) - WARNING: May restrict server access to Tailscale connections only${NC}"
echo -e "${CYAN} 2) Advertise as Exit Node (--advertise-exit-node)${NC}"
echo -e "${CYAN} 3) Accept DNS (--accept-dns)${NC}"
echo -e "${CYAN} 4) Accept Routes (--accept-routes)${NC}"
echo -e "${CYAN} Enter numbers (1-4) or leave blank to skip:${NC}"
read -rp " " TS_FLAG_CHOICES
local TS_FLAGS=""
if [[ -n "$TS_FLAG_CHOICES" ]]; then
if echo "$TS_FLAG_CHOICES" | grep -q "1"; then
TS_FLAGS="$TS_FLAGS --ssh"
fi
if echo "$TS_FLAG_CHOICES" | grep -q "2"; then
TS_FLAGS="$TS_FLAGS --advertise-exit-node"
fi
if echo "$TS_FLAG_CHOICES" | grep -q "3"; then
TS_FLAGS="$TS_FLAGS --accept-dns"
fi
if echo "$TS_FLAG_CHOICES" | grep -q "4"; then
TS_FLAGS="$TS_FLAGS --accept-routes"
fi
if [[ -n "$TS_FLAGS" ]]; then
TS_COMMAND="tailscale up"
if [[ "$TS_CONNECTION" == "2" ]]; then
TS_COMMAND="$TS_COMMAND --login-server=$LOGIN_SERVER"
fi
TS_COMMAND="$TS_COMMAND --auth-key=$AUTH_KEY --operator=$USERNAME $TS_FLAGS"
print_info "Reconfiguring Tailscale with additional options: $TS_COMMAND"
if ! $TS_COMMAND; then
print_warning "Failed to reconfigure Tailscale with additional options."
print_info "Please run the following command manually after resolving the issue:"
echo -e "${CYAN} $TS_COMMAND${NC}"
log "Tailscale reconfiguration failed: $TS_COMMAND"
else
# Verify reconfiguration status with retries
local RETRIES=3
local DELAY=5
local CONNECTED=false
for ((i=1; i<=RETRIES; i++)); do
if tailscale status 2>/dev/null | grep -q "^[^ ]* \+${SERVER_NAME} \+.*[^offline]$"; then
CONNECTED=true
break
fi
print_info "Waiting for Tailscale to connect ($i/$RETRIES)..."
sleep $DELAY
done
if $CONNECTED; then
print_success "Tailscale reconfigured with additional options."
log "Tailscale reconfigured: $TS_COMMAND"
# Store flags for summary
echo "${TS_FLAGS// --/}" > /tmp/tailscale_flags
else
print_warning "Tailscale reconfiguration attempt succeeded, but hostname ($SERVER_NAME) not found in 'tailscale status'."
print_info "Please verify with 'tailscale status' and run the following command manually if needed:"
echo -e "${CYAN} $TS_COMMAND${NC}"
log "Tailscale reconfiguration not verified: $TS_COMMAND"
tailscale status > /tmp/tailscale_status.txt 2>&1
log "Tailscale status output saved to /tmp/tailscale_status.txt for debugging"
fi
fi
else
print_info "No valid Tailscale options selected."
log "No valid Tailscale options selected."
fi
else
print_info "No additional Tailscale options selected."
log "No additional Tailscale options applied."
fi
print_success "Tailscale setup complete."
print_info "Verify status: tailscale status"
log "Tailscale setup completed."
}
setup_backup() {
@@ -1409,11 +1558,18 @@ generate_summary() {
print_error "Service docker is NOT active."
fi
fi
local TS_COMMAND=""
if command -v tailscale >/dev/null 2>&1; then
if systemctl is-active --quiet tailscaled; then
print_success "Service tailscaled is active."
if systemctl is-active --quiet tailscaled && tailscale status >/dev/null 2>&1 && tailscale status | grep -q "^[^ ]* \+${SERVER_NAME} \+.*[^offline]$"; then
print_success "Service tailscaled is active and connected."
local TS_SERVER=$(cat /tmp/tailscale_server 2>/dev/null || echo "https://controlplane.tailscale.com")
local TS_FLAGS=$(cat /tmp/tailscale_flags 2>/dev/null || echo "None")
else
print_error "Service tailscaled is NOT active."
print_error "Service tailscaled is NOT active or not connected."
local TS_SERVER="Not connected"
local TS_FLAGS="None"
TS_COMMAND=$(grep "Tailscale connection failed: tailscale up" "$LOG_FILE" | tail -1 | sed 's/.*Tailscale connection failed: //')
TS_COMMAND=${TS_COMMAND:-"tailscale up --operator=$USERNAME"}
fi
fi
echo -e "\n${GREEN}Server setup and hardening script has finished successfully.${NC}\n"
@@ -1443,6 +1599,13 @@ generate_summary() {
else
echo -e " Remote Backup: ${RED}Not configured${NC}"
fi
if command -v tailscale >/dev/null 2>&1; then
echo -e " Tailscale: ${GREEN}Enabled${NC}"
printf " %-16s%s\n" "- Server:" "$TS_SERVER"
printf " %-16s%s\n" "- Flags:" "$TS_FLAGS"
else
echo -e " Tailscale: ${RED}Not configured${NC}"
fi
echo
printf "${PURPLE}%-16s%s${NC}\n" "Log File:" "$LOG_FILE"
printf "${PURPLE}%-16s%s${NC}\n" "Backups:" "$BACKUP_DIR"
@@ -1459,6 +1622,9 @@ generate_summary() {
fi
if command -v tailscale >/dev/null 2>&1; then
printf " %-20s${CYAN}%s${NC}\n" "- Tailscale status:" "tailscale status"
if [[ "$TS_SERVER" == "Not connected" && -n "$TS_COMMAND" ]]; then
printf " %-20s${CYAN}%s${NC}\n" "- Tailscale connect:" "$TS_COMMAND"
fi
fi
if [[ -f /root/run_backup.sh ]]; then
echo -e " Remote Backup:"
@@ -1468,10 +1634,13 @@ generate_summary() {
printf " %-18s${CYAN}%s${NC}\n" "- Check logs:" "sudo less /var/log/backup_rsync.log"
fi
print_warning "\nACTION REQUIRED: If remote backup is enabled, ensure the root SSH key is copied to the destination server."
if [[ -n "$TS_COMMAND" ]]; then
print_warning "ACTION REQUIRED: Tailscale connection failed. Run the command above to connect manually."
fi
print_warning "A reboot is required to apply all changes cleanly."
if [[ $VERBOSE == true ]]; then
if confirm "Reboot now?" "y"; then
print_info "Rebooting ..."
print_info "Rebooting, bye!..."
sleep 3
reboot
else