Skip to content

Instantly share code, notes, and snippets.

@shrijayan
Last active May 30, 2026 05:48
Show Gist options
  • Select an option

  • Save shrijayan/1aaf72c3883d3de049bc2127f5a330c0 to your computer and use it in GitHub Desktop.

Select an option

Save shrijayan/1aaf72c3883d3de049bc2127f5a330c0 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Exit on any error
set -e
# Help helper function
usage() {
echo "Usage: $0 [domain_name] [local_url]"
echo "Example: $0 app.mydomain.com http://localhost:3000"
}
# Helper to run commands with root privileges
run_as_root() {
if [ "$EUID" -eq 0 ]; then
"$@"
else
if command -v sudo &> /dev/null; then
sudo "$@"
else
echo "Error: This script requires root privileges. Please run as root or install sudo."
exit 1
fi
fi
}
# Read arguments or prompt the user if they are missing
DOMAIN=$1
LOCAL_URL=$2
if [ -z "$DOMAIN" ]; then
read -p "Enter your custom domain name (e.g., app.example.com): " DOMAIN
fi
if [ -z "$LOCAL_URL" ]; then
read -p "Enter your local URL (e.g., http://localhost:8080): " LOCAL_URL
fi
if [ -z "$DOMAIN" ] || [ -z "$LOCAL_URL" ]; then
echo "Error: Both domain name and local URL are required."
usage
exit 1
fi
echo "Target Domain: $DOMAIN"
echo "Local Service: $LOCAL_URL"
# 1. Install cloudflared if not present
if ! command -v cloudflared &> /dev/null; then
echo "cloudflared is not installed. Attempting installation..."
# Detect OS
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
# Check for Debian/Ubuntu
if [ -f /etc/debian_version ]; then
echo "Detected Debian/Ubuntu system..."
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
run_as_root dpkg -i cloudflared.deb
rm cloudflared.deb
else
echo "Detected non-Debian Linux system. Installing static binary to /usr/local/bin..."
curl -L --output cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared
run_as_root mv cloudflared /usr/local/bin/
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then
echo "Detected macOS..."
if command -v brew &> /dev/null; then
brew install cloudflare/cloudflare/cloudflared
else
echo "Homebrew not found. Downloading macOS binary manually..."
curl -L --output cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-amd64.tgz
tar -xzf cloudflared-darwin-amd64.tgz
chmod +x cloudflared
run_as_root mv cloudflared /usr/local/bin/
rm cloudflared-darwin-amd64.tgz
fi
else
echo "Unsupported OS. Please install cloudflared manually before running this script."
exit 1
fi
else
echo "cloudflared is already installed."
fi
# 2. Cloudflare Login (Only runs if certificate does not exist)
USER_CONFIG_DIR="$HOME/.cloudflared"
mkdir -p "$USER_CONFIG_DIR"
if [ ! -f "$USER_CONFIG_DIR/cert.pem" ]; then
echo "-----------------------------------------------------"
echo "Requesting Cloudflare login..."
echo "Please click the URL printed below to authorize your account."
echo "-----------------------------------------------------"
cloudflared tunnel login
else
echo "Existing login certificate found at $USER_CONFIG_DIR/cert.pem. Skipping login step."
fi
# 3. Create or Retrieve the Tunnel
TUNNEL_NAME="tunnel-$(echo "$DOMAIN" | tr '.' '-')"
echo "Checking if tunnel '$TUNNEL_NAME' already exists..."
# List existing tunnels and extract the ID if found
EXISTING_TUNNEL_ID=$(cloudflared tunnel list | grep -w "$TUNNEL_NAME" | awk '{print $1}' || true)
if [ -n "$EXISTING_TUNNEL_ID" ]; then
CRED_FILE="$USER_CONFIG_DIR/$EXISTING_TUNNEL_ID.json"
if [ -f "$CRED_FILE" ]; then
echo "Tunnel '$TUNNEL_NAME' already exists and credentials file is present locally."
echo "Reusing Tunnel ID: $EXISTING_TUNNEL_ID"
TUNNEL_ID=$EXISTING_TUNNEL_ID
else
echo "Tunnel '$TUNNEL_NAME' exists on Cloudflare, but credentials are missing locally."
echo "Deleting the existing remote tunnel and creating a new one..."
cloudflared tunnel delete -f "$TUNNEL_NAME"
CREATE_OUTPUT=$(cloudflared tunnel create "$TUNNEL_NAME")
TUNNEL_ID=$(echo "$CREATE_OUTPUT" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -n 1)
fi
else
echo "Creating new tunnel: $TUNNEL_NAME"
CREATE_OUTPUT=$(cloudflared tunnel create "$TUNNEL_NAME")
TUNNEL_ID=$(echo "$CREATE_OUTPUT" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -n 1)
fi
if [ -z "$TUNNEL_ID" ]; then
echo "Error: Could not retrieve or generate the Tunnel ID."
exit 1
fi
# 4. Set up system-wide configuration directories
SYS_CONFIG_DIR="/etc/cloudflared"
echo "Creating system configuration directory at $SYS_CONFIG_DIR..."
run_as_root mkdir -p "$SYS_CONFIG_DIR"
# Copy credentials file to system directory
run_as_root cp "$USER_CONFIG_DIR/$TUNNEL_ID.json" "$SYS_CONFIG_DIR/"
# Generate system-wide config.yml
CONFIG_PATH="$SYS_CONFIG_DIR/config.yml"
echo "Generating system configuration file at $CONFIG_PATH..."
# Write the config securely
cat <<EOF | run_as_root tee "$CONFIG_PATH" > /dev/null
tunnel: $TUNNEL_ID
credentials-file: $SYS_CONFIG_DIR/$TUNNEL_ID.json
ingress:
- hostname: $DOMAIN
service: $LOCAL_URL
- service: http_status:404
EOF
# Remove redundant local configuration file to avoid conflicts
if [ -f "$USER_CONFIG_DIR/config.yml" ]; then
echo "Removing redundant local configuration file from $USER_CONFIG_DIR to prevent conflicts..."
rm -f "$USER_CONFIG_DIR/config.yml"
fi
# 5. Route DNS
echo "Routing DNS for $DOMAIN to point to the tunnel..."
cloudflared tunnel route dns "$TUNNEL_NAME" "$DOMAIN"
# 6. Systemd Service Installation (Linux background service)
if command -v systemctl &> /dev/null; then
echo "systemd detected. Configuring cloudflared as a system service..."
# Clean up previous service configurations to prevent installation blocks
if systemctl is-active --quiet cloudflared || systemctl is-enabled --quiet cloudflared &> /dev/null; then
echo "Removing existing cloudflared service..."
run_as_root cloudflared service uninstall || true
fi
# Install the service explicitly referencing the system configuration file
run_as_root cloudflared --config "$CONFIG_PATH" service install
# Enable and start the service
echo "Enabling and starting the cloudflared service..."
run_as_root systemctl daemon-reload
run_as_root systemctl enable cloudflared
run_as_root systemctl start cloudflared
echo "-----------------------------------------------------"
echo "Setup is complete."
echo "The tunnel is now running in the background via systemd."
echo "You can close this terminal or press Ctrl+C safely."
echo "-----------------------------------------------------"
echo "To check service status:"
echo " systemctl status cloudflared"
echo "To stop the service:"
echo " systemctl stop cloudflared"
echo "To start the service:"
echo " systemctl start cloudflared"
echo "-----------------------------------------------------"
else
echo "-----------------------------------------------------"
echo "systemd was not detected on this system."
echo "The system-wide configuration is saved at: $CONFIG_PATH"
echo "You must manage this tunnel manually:"
echo " cloudflared tunnel run $TUNNEL_NAME"
echo "-----------------------------------------------------"
fi
@shrijayan

shrijayan commented May 30, 2026

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment