Created
April 26, 2026 18:36
-
-
Save liwsakilive/16d13a04699dedf521a830fe1d00456c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ============================================================================= | |
| # setup-cloudflared.sh | |
| # Cloudflare Tunnel setup for Debian LXC (Proxmox) | |
| # Zotect Digital Capital Co., Ltd. | |
| # ============================================================================= | |
| # Usage: | |
| # chmod +x setup-cloudflared.sh | |
| # ./setup-cloudflared.sh <TUNNEL_TOKEN> | |
| # ============================================================================= | |
| set -euo pipefail | |
| # --------------------------------------------------------------------------- # | |
| # Config | |
| # --------------------------------------------------------------------------- # | |
| CF_USER="cloudflared" | |
| CF_GROUP="cloudflared" | |
| PING_GROUP_RANGE="0 65534" | |
| LOG_TAG="[cloudflared-setup]" | |
| # --------------------------------------------------------------------------- # | |
| # Helpers | |
| # --------------------------------------------------------------------------- # | |
| info() { echo -e "\e[32m${LOG_TAG} INFO $*\e[0m"; } | |
| warn() { echo -e "\e[33m${LOG_TAG} WARN $*\e[0m"; } | |
| error() { echo -e "\e[31m${LOG_TAG} ERROR $*\e[0m"; exit 1; } | |
| section() { echo -e "\n\e[36m══════════════════════════════════════\e[0m"; \ | |
| echo -e "\e[36m $*\e[0m"; \ | |
| echo -e "\e[36m══════════════════════════════════════\e[0m"; } | |
| # --------------------------------------------------------------------------- # | |
| # Pre-flight checks | |
| # --------------------------------------------------------------------------- # | |
| section "Pre-flight Checks" | |
| [[ $EUID -ne 0 ]] && error "กรุณารันด้วย root: sudo $0 <TOKEN>" | |
| [[ $# -lt 1 ]] && error "Usage: $0 <TUNNEL_TOKEN>" | |
| TUNNEL_TOKEN="$1" | |
| info "Tunnel token received ✓" | |
| info "OS: $(grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d '\"')" | |
| info "Arch: $(uname -m)" | |
| # --------------------------------------------------------------------------- # | |
| # Install cloudflared | |
| # --------------------------------------------------------------------------- # | |
| section "Installing cloudflared" | |
| info "Adding Cloudflare GPG key..." | |
| apt-get update -qq | |
| apt-get install -y -qq curl gnupg lsb-release | |
| mkdir -p /usr/share/keyrings | |
| curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \ | |
| | gpg --dearmor -o /usr/share/keyrings/cloudflare-main.gpg | |
| echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] \ | |
| https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \ | |
| > /etc/apt/sources.list.d/cloudflared.list | |
| info "Installing cloudflared package..." | |
| apt-get update -qq | |
| apt-get install -y -qq cloudflared | |
| INSTALLED_VER=$(cloudflared --version 2>&1 | head -1) | |
| info "Installed: ${INSTALLED_VER}" | |
| # --------------------------------------------------------------------------- # | |
| # Create dedicated user/group | |
| # --------------------------------------------------------------------------- # | |
| section "Creating cloudflared User" | |
| if ! getent group "${CF_GROUP}" > /dev/null 2>&1; then | |
| groupadd --system "${CF_GROUP}" | |
| info "Created group: ${CF_GROUP}" | |
| else | |
| warn "Group ${CF_GROUP} already exists — skipping" | |
| fi | |
| if ! id "${CF_USER}" > /dev/null 2>&1; then | |
| useradd --system \ | |
| --gid "${CF_GROUP}" \ | |
| --no-create-home \ | |
| --shell /bin/false \ | |
| "${CF_USER}" | |
| info "Created user: ${CF_USER} (GID: $(id -g ${CF_USER}))" | |
| else | |
| warn "User ${CF_USER} already exists — skipping" | |
| fi | |
| # --------------------------------------------------------------------------- # | |
| # Fix ping_group_range (resolve ICMP/GID warning) | |
| # --------------------------------------------------------------------------- # | |
| section "Fixing ping_group_range" | |
| CF_GID=$(id -g "${CF_USER}") | |
| info "cloudflared GID: ${CF_GID}" | |
| # Apply immediately | |
| echo "${PING_GROUP_RANGE}" > /proc/sys/net/ipv4/ping_group_range | |
| # Persist across reboots | |
| SYSCTL_CONF="/etc/sysctl.d/99-cloudflared.conf" | |
| cat > "${SYSCTL_CONF}" <<EOF | |
| # Allow cloudflared ICMP proxy | |
| net.ipv4.ping_group_range = ${PING_GROUP_RANGE} | |
| EOF | |
| sysctl -p "${SYSCTL_CONF}" > /dev/null | |
| info "ping_group_range set to: ${PING_GROUP_RANGE} (persistent) ✓" | |
| # --------------------------------------------------------------------------- # | |
| # Install tunnel as systemd service | |
| # --------------------------------------------------------------------------- # | |
| section "Installing Tunnel Service" | |
| info "Registering tunnel with token..." | |
| cloudflared service install "${TUNNEL_TOKEN}" | |
| # Override service to run as cloudflared user (not root) | |
| OVERRIDE_DIR="/etc/systemd/system/cloudflared.service.d" | |
| mkdir -p "${OVERRIDE_DIR}" | |
| cat > "${OVERRIDE_DIR}/user.conf" <<EOF | |
| [Service] | |
| User=${CF_USER} | |
| Group=${CF_GROUP} | |
| EOF | |
| info "Systemd override written: User=${CF_USER} Group=${CF_GROUP} ✓" | |
| # --------------------------------------------------------------------------- # | |
| # Fix credential file permissions | |
| # --------------------------------------------------------------------------- # | |
| section "Fixing Permissions" | |
| if [[ -d /etc/cloudflared ]]; then | |
| chown -R "${CF_USER}:${CF_GROUP}" /etc/cloudflared | |
| chmod 750 /etc/cloudflared | |
| find /etc/cloudflared -type f -exec chmod 640 {} \; | |
| info "Permissions set on /etc/cloudflared ✓" | |
| fi | |
| # --------------------------------------------------------------------------- # | |
| # Enable & start service | |
| # --------------------------------------------------------------------------- # | |
| section "Starting Service" | |
| systemctl daemon-reload | |
| systemctl enable cloudflared | |
| systemctl restart cloudflared | |
| info "Waiting for tunnel to connect (10s)..." | |
| sleep 10 | |
| # --------------------------------------------------------------------------- # | |
| # Verify | |
| # --------------------------------------------------------------------------- # | |
| section "Verification" | |
| STATUS=$(systemctl is-active cloudflared) | |
| if [[ "${STATUS}" == "active" ]]; then | |
| info "Service status: ${STATUS} ✓" | |
| else | |
| warn "Service status: ${STATUS} — ดู log ด้านล่าง" | |
| fi | |
| echo "" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo " Recent Logs" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| journalctl -u cloudflared --no-pager -n 20 | |
| echo "" | |
| CONN_COUNT=$(journalctl -u cloudflared --no-pager -n 30 \ | |
| | grep -c "Connection established" || true) | |
| if [[ "${CONN_COUNT}" -ge 1 ]]; then | |
| echo -e "\e[32m✅ Tunnel connected! (${CONN_COUNT}/4 connections established)\e[0m" | |
| else | |
| echo -e "\e[33m⚠️ Connection not confirmed yet — ตรวจ log ด้านบนครับ\e[0m" | |
| fi | |
| echo "" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo " Summary" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo " cloudflared user : ${CF_USER} (GID: ${CF_GID})" | |
| echo " ping_group_range : ${PING_GROUP_RANGE}" | |
| echo " sysctl config : ${SYSCTL_CONF}" | |
| echo " service override : ${OVERRIDE_DIR}/user.conf" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "" | |
| info "Done! 🎉" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment