Skip to content

Instantly share code, notes, and snippets.

@emrul
Last active March 19, 2026 11:14
Show Gist options
  • Select an option

  • Save emrul/f30f878443eb7a1624137980a2d1f975 to your computer and use it in GitHub Desktop.

Select an option

Save emrul/f30f878443eb7a1624137980a2d1f975 to your computer and use it in GitHub Desktop.
OpenZiti Router Deploy Script
#!/bin/bash
#
# Ziti Router Deployment Script
#
# Usage: /bin/bash -c "$(curl -fsSL https://gitlab.com/.../deploy-router.sh)" - <router-name>
#
# This script automates the deployment of a Ziti router by:
# 1. Accepting the router name as an argument
# 2. Accepting a JWT token from the user
# 3. Detecting the external IP address
# 4. Generating an sslip.io address
# 5. Creating a directory for the router
# 6. Downloading the router compose file
# 7. Running docker compose with the appropriate configuration
set -e
# Get router name from first argument and optional JWT from second argument
ROUTER_NAME="$1"
JWT_ARG="$2"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
DEFAULT_PORT=3022
COMPOSE_URL="https://get.openziti.io/dist/docker-images/ziti-router/compose.yml"
# Function to print colored messages
print_info() {
echo -e "${BLUE}ℹ${NC} $1"
}
print_success() {
echo -e "${GREEN}✓${NC} $1"
}
print_warning() {
echo -e "${YELLOW}⚠${NC} $1"
}
print_error() {
echo -e "${RED}✗${NC} $1"
}
print_header() {
echo ""
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo -e "${BLUE} Ziti Router Deployment${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════${NC}"
echo ""
}
# Check if required commands are available
check_requirements() {
local missing_deps=()
if ! command -v docker &> /dev/null; then
missing_deps+=("docker")
fi
if ! command -v curl &> /dev/null; then
missing_deps+=("curl")
fi
if [ ${#missing_deps[@]} -ne 0 ]; then
print_error "Missing required dependencies: ${missing_deps[*]}"
print_info "Please install the missing dependencies and try again."
exit 1
fi
}
# Detect external IP address
detect_external_ip() {
local ip=""
local services=(
"https://api.ipify.org"
"https://ifconfig.me"
"https://icanhazip.com"
"https://ipecho.net/plain"
)
print_info "Detecting external IP address..." >&2
for service in "${services[@]}"; do
ip=$(curl -s --max-time 5 "$service" 2>/dev/null || echo "")
if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
print_success "Detected external IP: $ip" >&2
echo "$ip"
return 0
fi
done
print_error "Failed to detect external IP address" >&2
return 1
}
# Prompt for JWT token
get_jwt_token() {
echo "" >&2
print_info "Please paste your Ziti router enrollment JWT token below." >&2
print_info "Press ENTER when done." >&2
echo "" >&2
echo -n "JWT Token: " >&2
# Read the JWT token (hidden input)
local jwt=""
read -r -s jwt
echo "" >&2
# Validate JWT (basic check - should start with "eyJ")
if [[ ! "$jwt" =~ ^eyJ ]]; then
print_error "Invalid JWT token format. JWT tokens should start with 'eyJ'." >&2
return 1
fi
if [ ${#jwt} -lt 100 ]; then
print_error "JWT token appears too short. Please verify and try again." >&2
return 1
fi
print_success "JWT token received" >&2
echo "$jwt"
}
# Generate sslip.io address
generate_sslip_address() {
local ip="$1"
local sslip_address="${ip//./-}.sslip.io"
echo "$sslip_address"
}
# Confirm or override value
confirm_or_override() {
local prompt="$1"
local default_value="$2"
local value=""
echo "" >&2
echo -e "${BLUE}${prompt}${NC} [${default_value}]: " >&2
read -r value
if [ -z "$value" ]; then
echo "$default_value"
else
echo "$value"
fi
}
# Create temporary directory for JWT
create_temp_jwt_file() {
local jwt="$1"
local temp_file=$(mktemp)
echo "$jwt" > "$temp_file"
echo "$temp_file"
}
# Main deployment function
main() {
print_header
# Check if router name was provided
if [ -z "$ROUTER_NAME" ]; then
print_error "Router name is required"
print_info "Usage: /bin/bash -c \"\$(curl -fsSL <script-url>)\" - <router-name>"
exit 1
fi
# Validate router name format (only letters, numbers, hyphens, and underscores)
if [[ ! "$ROUTER_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
print_error "Invalid router name: '$ROUTER_NAME'"
print_info "Router names can only contain letters, numbers, hyphens (-), and underscores (_)"
exit 1
fi
print_info "Router name: $ROUTER_NAME"
# Check requirements
check_requirements
# Get JWT token (from argument or prompt)
if [ -n "$JWT_ARG" ]; then
JWT="$JWT_ARG"
print_success "JWT token received from argument"
# Validate JWT (basic check - should start with "eyJ")
if [[ ! "$JWT" =~ ^eyJ ]]; then
print_error "Invalid JWT token format. JWT tokens should start with 'eyJ'."
exit 1
fi
if [ ${#JWT} -lt 100 ]; then
print_error "JWT token appears too short. Please verify and try again."
exit 1
fi
else
JWT=$(get_jwt_token)
if [ $? -ne 0 ]; then
exit 1
fi
fi
# Detect external IP
EXTERNAL_IP=$(detect_external_ip)
if [ $? -ne 0 ]; then
EXTERNAL_IP=""
fi
# Generate sslip address
if [ -n "$EXTERNAL_IP" ]; then
SSLIP_ADDRESS=$(generate_sslip_address "$EXTERNAL_IP")
print_success "Generated sslip.io address: $SSLIP_ADDRESS"
else
SSLIP_ADDRESS=""
fi
# Confirm or override advertised address
if [ -n "$SSLIP_ADDRESS" ]; then
ROUTER_ADDRESS=$(confirm_or_override "Router advertised address" "$SSLIP_ADDRESS")
else
print_warning "Could not detect external IP. Please enter the router's advertised address manually."
echo -e "${BLUE}Router advertised address${NC}: " >&2
read -r ROUTER_ADDRESS
if [ -z "$ROUTER_ADDRESS" ]; then
print_error "Router advertised address is required."
exit 1
fi
fi
# Confirm or override port
ROUTER_PORT=$(confirm_or_override "Router port" "$DEFAULT_PORT")
# Validate port number
if ! [[ "$ROUTER_PORT" =~ ^[0-9]+$ ]] || [ "$ROUTER_PORT" -lt 1 ] || [ "$ROUTER_PORT" -gt 65535 ]; then
print_error "Invalid port number: $ROUTER_PORT"
exit 1
fi
echo ""
print_info "Configuration Summary:"
echo " Router Name: $ROUTER_NAME"
echo " Advertised Address: $ROUTER_ADDRESS"
echo " Port: $ROUTER_PORT"
echo ""
echo -e "${YELLOW}Proceed with deployment? [y/N]:${NC} " >&2
read -r confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
print_warning "Deployment cancelled."
exit 0
fi
# Create router directory
print_info "Creating router directory: $ROUTER_NAME"
if [ -d "$ROUTER_NAME" ]; then
print_warning "Directory '$ROUTER_NAME' already exists"
echo -e "${YELLOW}Overwrite existing directory? [y/N]:${NC} " >&2
read -r overwrite
if [[ ! "$overwrite" =~ ^[Yy]$ ]]; then
print_warning "Deployment cancelled."
exit 0
fi
fi
mkdir -p "$ROUTER_NAME"
cd "$ROUTER_NAME"
print_success "Router directory created and navigated to: $(pwd)"
# Download compose file
print_info "Downloading Ziti router compose file..."
if ! curl -fsSL "$COMPOSE_URL" -o docker-compose.yml; then
print_error "Failed to download compose file from $COMPOSE_URL"
cd ..
rm -rf "$ROUTER_NAME"
exit 1
fi
print_success "Compose file downloaded as docker-compose.yml"
# Run docker compose
echo ""
print_info "Starting Ziti router with Docker Compose..."
echo ""
export ZITI_ENROLL_TOKEN="$JWT"
export ZITI_ROUTER_ADVERTISED_ADDRESS="$ROUTER_ADDRESS"
export ZITI_ROUTER_PORT="$ROUTER_PORT"
if docker compose up -d; then
echo ""
print_success "Ziti router deployed successfully!"
echo ""
print_info "Router Details:"
echo " Name: $ROUTER_NAME"
echo " Directory: $(pwd)"
echo " Advertised Address: $ROUTER_ADDRESS"
echo " Port: $ROUTER_PORT"
echo ""
print_info "Useful Commands (run from $ROUTER_NAME directory):"
echo " View logs: docker compose logs -f"
echo " Stop router: docker compose down"
echo " Restart router: docker compose restart"
echo ""
else
print_error "Failed to start router with Docker Compose"
cd ..
rm -rf "$ROUTER_NAME"
exit 1
fi
}
# Run main function
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment