- Restructure repo into docker/ and native/ deployment types with a shared common/wallarm-lib.sh (logging, detection, validation, connectivity, env parsing) - Move Docker scripts + artifacts (binaries/, images/) under docker/ (git mv, history preserved) - Refactor Docker scripts to source the shared library; update artifact URLs - Add native/ scripts for no-Docker deployment using the Wallarm all-in-one installer (check, deploy, reconfigure, uninstall) with version pinning via WALLARM_VERSION - Add native/wallarm-native.sh unified node manager (Wallarm Native Node, connector mode) with preflight checks, parallel multi-node install, config/remove/status - Update setup.sh to download scripts per deployment type (DEPLOYMENT_TYPE=...) - Update README.md and changelog.md
673 lines
29 KiB
Bash
Executable file
673 lines
29 KiB
Bash
Executable file
#!/bin/bash
|
|
# ==============================================================================
|
|
# WALLARM DEPLOYMENT SCRIPT - V1.0 (Native deployment)
|
|
# ==============================================================================
|
|
# Purpose: Deploy Wallarm filtering node natively (NO Docker) after preflight
|
|
# Features:
|
|
# - Reads preflight check results from .env file
|
|
# - Interactive configuration (cloud region, ports, token, upstream)
|
|
# - Downloads and runs the official Wallarm all-in-one installer (meganode.wallarm.com)
|
|
# - Configures NGINX server block (proxy, wallarm_mode, trusted proxies, health)
|
|
# - Deployment verification (health endpoint, wallarm-status, node registration)
|
|
# - DAU-friendly error handling with remediation
|
|
# ==============================================================================
|
|
|
|
# Script location and shared library (colors, logging, validation, detection, connectivity)
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=../common/wallarm-lib.sh
|
|
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
|
|
|
|
# Strict error handling
|
|
set -euo pipefail
|
|
trap early_error_handler ERR
|
|
|
|
# Configuration
|
|
ENV_FILE=".env"
|
|
LOG_FILE="${HOME:-.}/logs/wallarm-deployment-native.log"
|
|
|
|
# Wallarm all-in-one installer (current recommended native install method)
|
|
# Override WALLARM_VERSION to pin a different version.
|
|
WALLARM_VERSION="${WALLARM_VERSION:-6.12.7}"
|
|
INSTALLER_BASE_URL="https://meganode.wallarm.com/${WALLARM_VERSION%.*}"
|
|
|
|
# Optional node labels for the installer (e.g. 'group=prod')
|
|
WALLARM_LABELS="${WALLARM_LABELS:-}"
|
|
|
|
# Deployment variables (set during execution)
|
|
CLOUD_REGION=""
|
|
API_HOST=""
|
|
INGRESS_PORT=""
|
|
UPSTREAM_IP=""
|
|
UPSTREAM_PORT=""
|
|
WALLARM_TOKEN=""
|
|
INSTANCE_NAME=""
|
|
INSTANCE_DIR=""
|
|
NGINX_CONFIG=""
|
|
|
|
# Resource reachability from check script
|
|
US_CLOUD_REACHABLE="false"
|
|
EU_CLOUD_REACHABLE="false"
|
|
INSTALLER_REACHABLE="false"
|
|
|
|
# ==============================================================================
|
|
# PREFLIGHT CHECK VERIFICATION
|
|
# ==============================================================================
|
|
|
|
verify_preflight_check() {
|
|
log_message "INFO" "Verifying preflight check results..."
|
|
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
log_message "ERROR" "Preflight check file not found: $ENV_FILE"
|
|
echo -e "\n${YELLOW}Preflight check has not been run or .env file is missing.${NC}"
|
|
echo -e "${YELLOW}Would you like to run the preflight check now?${NC}"
|
|
read -r -p "$(echo -e "${YELLOW}Run preflight check? (Y/n): ${NC}")" -n 1
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
|
echo -e "${CYAN}Running preflight check...${NC}"
|
|
if ! "$SCRIPT_DIR/wallarm-ct-check.sh"; then
|
|
fail_with_remediation "Preflight check failed" \
|
|
"Run the preflight check manually and fix any issues:
|
|
1. $SCRIPT_DIR/wallarm-ct-check.sh
|
|
2. Review the errors in $ENV_FILE
|
|
3. Fix the issues and run this script again"
|
|
fi
|
|
else
|
|
fail_with_remediation "Preflight check required" \
|
|
"Run the preflight check before deployment:
|
|
1. $SCRIPT_DIR/wallarm-ct-check.sh
|
|
2. Review results in $ENV_FILE
|
|
3. Run this script again"
|
|
fi
|
|
fi
|
|
|
|
# Load environment variables from .env file (from shared library)
|
|
if ! load_env_file "$ENV_FILE"; then
|
|
fail_with_remediation "Cannot load preflight results" \
|
|
"The preflight check results file could not be read.
|
|
1. Run the preflight check: $SCRIPT_DIR/wallarm-ct-check.sh
|
|
2. Verify $ENV_FILE exists and is readable
|
|
3. Run this script again"
|
|
fi
|
|
|
|
if [ "${CHECK_RESULT:-}" != "pass" ]; then
|
|
log_message "ERROR" "Preflight check failed (result: $CHECK_RESULT)"
|
|
echo -e "\n${YELLOW}Preflight check found issues. Please review:${NC}"
|
|
echo -e "${YELLOW}1. Check file: $ENV_FILE${NC}"
|
|
echo -e "${YELLOW}2. Run: $SCRIPT_DIR/wallarm-ct-check.sh${NC}"
|
|
echo -e "${YELLOW}3. Fix the issues and try again${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
log_message "SUCCESS" "Preflight check verified:"
|
|
log_message "SUCCESS" " OS: $OS_NAME $OS_VERSION"
|
|
log_message "SUCCESS" " Architecture: $ARCHITECTURE"
|
|
log_message "SUCCESS" " Init System: $INIT_SYSTEM"
|
|
log_message "SUCCESS" " US Cloud Reachable: $US_CLOUD_REACHABLE"
|
|
log_message "SUCCESS" " EU Cloud Reachable: $EU_CLOUD_REACHABLE"
|
|
log_message "SUCCESS" " Wallarm Installer Reachable: $INSTALLER_REACHABLE"
|
|
|
|
# Validate we have at least one cloud region reachable
|
|
if [ "$US_CLOUD_REACHABLE" = "false" ] && [ "$EU_CLOUD_REACHABLE" = "false" ]; then
|
|
fail_with_remediation "No Wallarm cloud region reachable" \
|
|
"Network connectivity issues detected:
|
|
1. Check firewall rules for Wallarm cloud endpoints
|
|
2. Verify network connectivity
|
|
3. Run preflight check again: $SCRIPT_DIR/wallarm-ct-check.sh"
|
|
fi
|
|
|
|
# The all-in-one installer must be reachable for a native deployment
|
|
if [ "$INSTALLER_REACHABLE" != "true" ]; then
|
|
fail_with_remediation "Wallarm all-in-one installer not reachable" \
|
|
"Native deployment requires access to the Wallarm all-in-one installer:
|
|
1. Verify network access to $INSTALLER_BASE_URL
|
|
2. Check the current version at https://docs.wallarm.com/updating-migrating/node-artifact-versions/
|
|
3. Pin the version with: WALLARM_VERSION=<version> sudo ./$0"
|
|
fi
|
|
}
|
|
|
|
# ==============================================================================
|
|
# CONFIGURATION COLLECTION
|
|
# ==============================================================================
|
|
# select_cloud_region, validate_ip_address and check_port_available are provided
|
|
# by the shared library (../common/wallarm-lib.sh).
|
|
|
|
collect_configuration() {
|
|
log_message "INFO" "Collecting deployment configuration..."
|
|
|
|
# Get ingress port
|
|
local default_port=80
|
|
local ingress_port=""
|
|
while [[ ! "$ingress_port" =~ ^[0-9]+$ ]] || [ "$ingress_port" -lt 1 ] || [ "$ingress_port" -gt 65535 ]; do
|
|
read -r -p "$(echo -e "${YELLOW}Enter inbound port [${default_port}]: ${NC}")" ingress_port
|
|
ingress_port="${ingress_port:-$default_port}"
|
|
|
|
if [[ ! "$ingress_port" =~ ^[0-9]+$ ]]; then
|
|
echo -e "${RED}Port must be a number${NC}"
|
|
elif [ "$ingress_port" -lt 1 ] || [ "$ingress_port" -gt 65535 ]; then
|
|
echo -e "${RED}Port must be between 1 and 65535${NC}"
|
|
elif ! check_port_available "$ingress_port"; then
|
|
echo -e "${RED}Port $ingress_port is already in use${NC}"
|
|
ingress_port=""
|
|
fi
|
|
done
|
|
|
|
# Get application server details
|
|
local upstream_ip=""
|
|
local upstream_port=""
|
|
|
|
echo -e "\n${CYAN}${BOLD}Application Server Configuration:${NC}"
|
|
echo -e "${YELLOW}Enter the IP/hostname and port of your backend application${NC}"
|
|
|
|
while [[ -z "$upstream_ip" ]]; do
|
|
read -r -p "$(echo -e "${YELLOW}Upstream App IP/Hostname [127.0.0.1]: ${NC}")" upstream_ip
|
|
upstream_ip="${upstream_ip:-127.0.0.1}"
|
|
|
|
if ! validate_ip_address "$upstream_ip" && \
|
|
! [[ "$upstream_ip" =~ ^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$ ]]; then
|
|
echo -e "${RED}Invalid IP/hostname format${NC}"
|
|
upstream_ip=""
|
|
fi
|
|
done
|
|
|
|
while [[ ! "$upstream_port" =~ ^[0-9]+$ ]] || [ "$upstream_port" -lt 1 ] || [ "$upstream_port" -gt 65535 ]; do
|
|
read -r -p "$(echo -e "${YELLOW}Upstream App Port [8080]: ${NC}")" upstream_port
|
|
upstream_port="${upstream_port:-8080}"
|
|
|
|
if [[ ! "$upstream_port" =~ ^[0-9]+$ ]]; then
|
|
echo -e "${RED}Port must be a number${NC}"
|
|
elif [ "$upstream_port" -lt 1 ] || [ "$upstream_port" -gt 65535 ]; then
|
|
echo -e "${RED}Port must be between 1 and 65535${NC}"
|
|
fi
|
|
done
|
|
|
|
# Verify application server reachability
|
|
log_message "INFO" "Verifying application server reachability..."
|
|
if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$upstream_ip/$upstream_port" 2>/dev/null; then
|
|
log_message "SUCCESS" "Application server $upstream_ip:$upstream_port is reachable"
|
|
else
|
|
log_message "WARNING" "Application server $upstream_ip:$upstream_port is not reachable"
|
|
echo -e "${YELLOW}${BOLD}Warning:${NC} Cannot reach application server at $upstream_ip:$upstream_port"
|
|
echo -e "${YELLOW}This may cause the Wallarm node to fail. Possible reasons:${NC}"
|
|
echo -e "1. Application server is not running"
|
|
echo -e "2. Firewall blocking port $upstream_port"
|
|
echo -e "3. Wrong IP/hostname"
|
|
echo -e "4. Application server not listening on that port"
|
|
|
|
read -r -p "$(echo -e "${YELLOW}Continue anyway? (y/N): ${NC}")" -n 1
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
fail_with_remediation "Application server unreachable" \
|
|
"Ensure your application server is accessible:
|
|
1. Start your application server
|
|
2. Check it's listening: sudo ss -tlnp | grep :$upstream_port
|
|
3. Verify firewall rules allow inbound connections
|
|
4. Test connectivity: telnet $upstream_ip $upstream_port
|
|
5. If using hostname, verify DNS resolution: nslookup $upstream_ip"
|
|
fi
|
|
fi
|
|
|
|
# Get Wallarm node token
|
|
local wallarm_token=""
|
|
echo -e "\n${CYAN}${BOLD}Wallarm Node Token:${NC}"
|
|
echo -e "${YELLOW}Get your token from Wallarm Console:${NC}"
|
|
echo -e "Create a new 'Wallarm node' and copy the token (will be visible as you type)"
|
|
while [[ -z "$wallarm_token" ]]; do
|
|
read -r -p "$(echo -e "${YELLOW}Paste Wallarm Node Token: ${NC}")" wallarm_token
|
|
wallarm_token=$(echo "$wallarm_token" | tr -d '[:space:]')
|
|
|
|
if [[ -z "$wallarm_token" ]]; then
|
|
echo -e "${RED}Token cannot be empty${NC}"
|
|
elif [[ ! "$wallarm_token" =~ ^[A-Za-z0-9_+/=\-]+$ ]]; then
|
|
echo -e "${RED}Token contains invalid characters. Wallarm tokens are base64 strings (A-Z, a-z, 0-9, _, -, +, /, =)${NC}"
|
|
echo -e "${YELLOW}First 20 chars of what you entered: '${wallarm_token:0:20}...'${NC}"
|
|
wallarm_token=""
|
|
else
|
|
token_length=${#wallarm_token}
|
|
echo -e "${GREEN}Token accepted (${token_length} characters).${NC}"
|
|
echo -e "${YELLOW}First 8 chars for verification: ${wallarm_token:0:8}...${NC}"
|
|
fi
|
|
done
|
|
|
|
# Get trusted proxy IPs for real IP configuration
|
|
local trusted_proxies=""
|
|
echo -e "\n${CYAN}${BOLD}Real Client IP Configuration:${NC}"
|
|
echo -e "${YELLOW}For Wallarm to see the real client IP, specify the IP address(es) of trusted proxies"
|
|
echo -e "(e.g., load balancers, firewalls, CDNs) that forward traffic to this node.${NC}"
|
|
echo -e "${YELLOW}You can enter:${NC}"
|
|
echo -e " - Single IP: 10.0.0.10"
|
|
echo -e " - CIDR range: 10.0.0.0/24"
|
|
echo -e " - Multiple entries separated by spaces: 10.0.0.10 10.0.1.0/24 192.168.1.1"
|
|
echo -e "${YELLOW}If unsure, you can leave empty and configure later${NC}"
|
|
|
|
read -r -p "$(echo -e "${YELLOW}Trusted proxy IPs/CIDRs (space-separated): ${NC}")" trusted_proxies_input
|
|
|
|
local validated_proxies=()
|
|
if [[ -n "$trusted_proxies_input" ]]; then
|
|
IFS=' ' read -ra proxy_array <<< "$trusted_proxies_input"
|
|
|
|
for proxy in "${proxy_array[@]}"; do
|
|
proxy=$(echo "$proxy" | xargs)
|
|
if [[ -n "$proxy" ]]; then
|
|
if validate_ip_or_cidr "$proxy"; then
|
|
validated_proxies+=("$proxy")
|
|
else
|
|
echo -e "${RED}Invalid IP/CIDR format: $proxy${NC}"
|
|
echo -e "${YELLOW}Example valid formats: 10.0.0.10, 10.0.0.0/24, 192.168.1.1${NC}"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [[ ${#validated_proxies[@]} -eq 0 ]]; then
|
|
echo -e "${YELLOW}No valid proxy IPs provided. Will skip set_real_ip_from configuration.${NC}"
|
|
echo -e "${YELLOW}You can configure it later with the reconfigure script.${NC}"
|
|
trusted_proxies=""
|
|
else
|
|
trusted_proxies="${validated_proxies[*]}"
|
|
echo -e "${GREEN}Trusted proxies configured: $trusted_proxies${NC}"
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}No trusted proxies specified. The node will see the last hop IP only.${NC}"
|
|
fi
|
|
|
|
# Generate instance name and directory
|
|
local instance_name
|
|
instance_name="wallarm-$(hostname -s | tr '[:upper:]' '[:lower:]')-$(date +%Y%m%d)"
|
|
local instance_dir="/opt/wallarm/$instance_name"
|
|
|
|
sudo mkdir -p "$instance_dir"
|
|
|
|
log_message "SUCCESS" "Configuration collected:"
|
|
log_message "SUCCESS" " Ingress Port: $ingress_port"
|
|
log_message "SUCCESS" " Upstream: $upstream_ip:$upstream_port"
|
|
if [[ -n "$trusted_proxies" ]]; then
|
|
log_message "SUCCESS" " Trusted Proxies: $trusted_proxies"
|
|
else
|
|
log_message "INFO" " Trusted Proxies: Not configured (will need manual setup)"
|
|
fi
|
|
log_message "SUCCESS" " Instance: $instance_name"
|
|
log_message "SUCCESS" " Directory: $instance_dir"
|
|
|
|
INGRESS_PORT="$ingress_port"
|
|
UPSTREAM_IP="$upstream_ip"
|
|
UPSTREAM_PORT="$upstream_port"
|
|
WALLARM_TOKEN="$wallarm_token"
|
|
INSTANCE_NAME="$instance_name"
|
|
INSTANCE_DIR="$instance_dir"
|
|
TRUSTED_PROXIES="$trusted_proxies"
|
|
}
|
|
|
|
# ==============================================================================
|
|
# WALLARM NATIVE INSTALLATION (all-in-one installer)
|
|
# ==============================================================================
|
|
|
|
install_wallarm_native() {
|
|
log_message "INFO" "Installing Wallarm filtering node natively (all-in-one installer)..."
|
|
|
|
# Select the correct installer for the detected architecture
|
|
local arch_suffix
|
|
case "$ARCHITECTURE" in
|
|
"x86_64") arch_suffix="x86_64-glibc" ;;
|
|
"aarch64") arch_suffix="aarch64-glibc" ;;
|
|
*)
|
|
fail_with_remediation "Unsupported architecture for native install: $ARCHITECTURE" \
|
|
"The Wallarm all-in-one installer supports x86_64 and aarch64.
|
|
1. Check architecture: uname -m
|
|
2. If you are on a 32-bit system, consider the Docker deployment instead.
|
|
3. See https://docs.wallarm.com/installation/nginx/all-in-one/ for supported platforms."
|
|
;;
|
|
esac
|
|
|
|
local installer_name="wallarm-${WALLARM_VERSION}.${arch_suffix}.sh"
|
|
local installer_url="${INSTALLER_BASE_URL}/${installer_name}"
|
|
|
|
log_message "INFO" "Downloading Wallarm installer: $installer_name"
|
|
if ! download_from_git "$installer_url" "$installer_name" "Wallarm all-in-one installer"; then
|
|
fail_with_remediation "Failed to download Wallarm installer" \
|
|
"Could not download $installer_url
|
|
1. Verify network access to meganode.wallarm.com
|
|
2. Check the current version at https://docs.wallarm.com/updating-migrating/node-artifact-versions/
|
|
3. Pin the version with: WALLARM_VERSION=<version> sudo ./$0"
|
|
fi
|
|
|
|
chmod +x "$installer_name"
|
|
|
|
# Build installer arguments (batch mode)
|
|
local install_args="-- --batch -t $WALLARM_TOKEN"
|
|
if [ "$CLOUD_REGION" = "US" ]; then
|
|
install_args="$install_args -c US"
|
|
log_message "INFO" "Using US cloud (us1.api.wallarm.com)"
|
|
else
|
|
log_message "INFO" "Using EU cloud (api.wallarm.com)"
|
|
fi
|
|
|
|
# Run the installer (batch mode). The installer registers the node with the
|
|
# token and configures NGINX + the Wallarm module automatically.
|
|
log_message "INFO" "Running Wallarm all-in-one installer (this may take several minutes)..."
|
|
if [ -n "$WALLARM_LABELS" ]; then
|
|
log_message "INFO" "Using node labels: $WALLARM_LABELS"
|
|
if ! sudo env WALLARM_LABELS="$WALLARM_LABELS" sh "$installer_name" $install_args; then
|
|
rm -f "$installer_name"
|
|
fail_with_remediation "Wallarm installer failed" \
|
|
"The all-in-one installer exited with an error. Check:
|
|
1. The installer log output above for the exact error
|
|
2. Token validity in the Wallarm Console
|
|
3. Network access to Wallarm repositories (the installer adds them automatically)
|
|
4. Disk space and memory: df -h / && free -h
|
|
5. Retry with a higher log verbosity, or see https://docs.wallarm.com/installation/nginx/all-in-one/"
|
|
fi
|
|
else
|
|
if ! sudo sh "$installer_name" $install_args; then
|
|
rm -f "$installer_name"
|
|
fail_with_remediation "Wallarm installer failed" \
|
|
"The all-in-one installer exited with an error. Check:
|
|
1. The installer log output above for the exact error
|
|
2. Token validity in the Wallarm Console
|
|
3. Network access to Wallarm repositories (the installer adds them automatically)
|
|
4. Disk space and memory: df -h / && free -h
|
|
5. Retry with a higher log verbosity, or see https://docs.wallarm.com/installation/nginx/all-in-one/"
|
|
fi
|
|
fi
|
|
|
|
rm -f "$installer_name"
|
|
log_message "SUCCESS" "Wallarm all-in-one installer completed"
|
|
|
|
# Verify the node was registered
|
|
if [ -f "/opt/wallarm/etc/wallarm/node.yaml" ]; then
|
|
log_message "SUCCESS" "Wallarm node configuration found: /opt/wallarm/etc/wallarm/node.yaml"
|
|
else
|
|
log_message "WARNING" "Wallarm node configuration not found at /opt/wallarm/etc/wallarm/node.yaml"
|
|
echo -e "${YELLOW}The node may not have been registered. Check the installer output.${NC}"
|
|
fi
|
|
}
|
|
|
|
# ==============================================================================
|
|
# NGINX CONFIGURATION
|
|
# ==============================================================================
|
|
|
|
# Detect existing NGINX server blocks that would conflict with our ingress port
|
|
# and disable the default site if necessary.
|
|
resolve_port_conflict() {
|
|
local port="$1"
|
|
|
|
log_message "INFO" "Checking for NGINX config conflicts on port $port..."
|
|
|
|
# Only relevant for default port 80 where distro default sites listen
|
|
if [ "$port" != "80" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Look for default server blocks listening on port 80
|
|
local conflicting
|
|
conflicting=$(grep -rl "listen.*80" /etc/nginx/sites-enabled/ /etc/nginx/conf.d/ 2>/dev/null | head -1 || true)
|
|
|
|
if [ -n "$conflicting" ]; then
|
|
log_message "WARNING" "Default NGINX site found: $conflicting"
|
|
echo -e "${YELLOW}The default site listens on port 80 and may conflict with the Wallarm node.${NC}"
|
|
read -r -p "$(echo -e "${YELLOW}Disable it (backup to .bak)? (Y/n): ${NC}")" -n 1
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
|
sudo mv "$conflicting" "${conflicting}.bak"
|
|
log_message "SUCCESS" "Disabled $conflicting (backup: ${conflicting}.bak)"
|
|
else
|
|
log_message "WARNING" "Keeping default site. The Wallarm node may not receive traffic on port 80."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
create_nginx_config() {
|
|
NGINX_CONFIG="/etc/nginx/conf.d/wallarm-${INSTANCE_NAME}.conf"
|
|
|
|
log_message "INFO" "Creating NGINX configuration: $NGINX_CONFIG"
|
|
|
|
# Also keep a copy in the instance directory for reference/backup
|
|
sudo tee "$NGINX_CONFIG" > /dev/null <<EOF
|
|
# Wallarm filtering node: $INSTANCE_NAME
|
|
# Generated: $(date)
|
|
server {
|
|
listen $INGRESS_PORT;
|
|
server_name _;
|
|
EOF
|
|
|
|
# Add set_real_ip_from directives if trusted proxies are configured
|
|
if [[ -n "$TRUSTED_PROXIES" ]]; then
|
|
for proxy in $TRUSTED_PROXIES; do
|
|
sudo tee -a "$NGINX_CONFIG" > /dev/null <<EOF
|
|
set_real_ip_from $proxy;
|
|
EOF
|
|
done
|
|
sudo tee -a "$NGINX_CONFIG" > /dev/null <<EOF
|
|
real_ip_header X-Real-IP;
|
|
real_ip_recursive on;
|
|
EOF
|
|
fi
|
|
|
|
# Add the rest of the configuration
|
|
sudo tee -a "$NGINX_CONFIG" > /dev/null <<EOF
|
|
|
|
location / {
|
|
proxy_pass http://$UPSTREAM_IP:$UPSTREAM_PORT;
|
|
proxy_set_header Host \$host;
|
|
proxy_set_header X-Real-IP \$remote_addr;
|
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto \$scheme;
|
|
proxy_set_header X-Forwarded-Server \$http_x_forwarded_server;
|
|
|
|
# Wallarm directives
|
|
wallarm_mode monitoring;
|
|
}
|
|
|
|
# Health check endpoint
|
|
location /health {
|
|
access_log off;
|
|
return 200 "healthy\n";
|
|
add_header Content-Type text/plain;
|
|
}
|
|
}
|
|
EOF
|
|
|
|
# Keep a reference copy in the instance directory
|
|
sudo cp "$NGINX_CONFIG" "$INSTANCE_DIR/nginx.conf"
|
|
log_message "SUCCESS" "NGINX configuration created: $NGINX_CONFIG"
|
|
if [[ -n "$TRUSTED_PROXIES" ]]; then
|
|
log_message "INFO" " Configured trusted proxies: $TRUSTED_PROXIES"
|
|
else
|
|
log_message "INFO" " No trusted proxies configured - real client IP detection may be limited"
|
|
fi
|
|
}
|
|
|
|
reload_nginx() {
|
|
log_message "INFO" "Testing and reloading NGINX..."
|
|
|
|
if ! sudo nginx -t 2>&1 | tee "$INSTANCE_DIR/nginx-test.log"; then
|
|
fail_with_remediation "NGINX configuration test failed" \
|
|
"NGINX rejected the configuration. Check the test output above.
|
|
1. Review the generated config: $NGINX_CONFIG
|
|
2. Look for port conflicts or syntax errors
|
|
3. Restore the backup if the default site was disabled
|
|
4. Manual test: sudo nginx -t"
|
|
fi
|
|
|
|
# Reload according to init system
|
|
case "${INIT_SYSTEM:-systemd}" in
|
|
"systemd")
|
|
sudo systemctl reload nginx 2>/dev/null || sudo systemctl restart nginx
|
|
;;
|
|
"openrc")
|
|
sudo rc-service nginx reload 2>/dev/null || sudo rc-service nginx restart
|
|
;;
|
|
"sysvinit")
|
|
sudo service nginx reload 2>/dev/null || sudo service nginx restart
|
|
;;
|
|
*)
|
|
sudo nginx -s reload 2>/dev/null || true
|
|
;;
|
|
esac
|
|
|
|
log_message "SUCCESS" "NGINX reloaded with Wallarm configuration"
|
|
}
|
|
|
|
# ==============================================================================
|
|
# DEPLOYMENT VERIFICATION
|
|
# ==============================================================================
|
|
|
|
verify_deployment() {
|
|
log_message "INFO" "Verifying native Wallarm deployment..."
|
|
|
|
# Test ingress port
|
|
log_message "INFO" "Testing ingress port $INGRESS_PORT..."
|
|
if ! check_port_available "$INGRESS_PORT"; then
|
|
log_message "SUCCESS" "Ingress port $INGRESS_PORT is in use (as expected)"
|
|
else
|
|
log_message "WARNING" "Ingress port $INGRESS_PORT appears available (NGINX may not be listening)"
|
|
fi
|
|
|
|
# Test health check endpoint
|
|
log_message "INFO" "Testing health check endpoint..."
|
|
local health_check_url="http://localhost:$INGRESS_PORT/health"
|
|
if curl -sf --connect-timeout 5 "$health_check_url" >/dev/null 2>&1; then
|
|
log_message "SUCCESS" "Health check endpoint responsive"
|
|
else
|
|
log_message "WARNING" "Health check endpoint not responsive (may need time to start)"
|
|
sleep 5
|
|
if curl -sf --connect-timeout 5 "$health_check_url" >/dev/null 2>&1; then
|
|
log_message "SUCCESS" "Health check endpoint now responsive"
|
|
else
|
|
log_message "WARNING" "Health check endpoint still not responsive (check nginx config)"
|
|
fi
|
|
fi
|
|
|
|
# Test handshake through filtering node
|
|
log_message "INFO" "Testing handshake through filtering node to upstream..."
|
|
local test_url="http://localhost:$INGRESS_PORT/"
|
|
if curl -sfI --connect-timeout 10 "$test_url" >/dev/null 2>&1; then
|
|
log_message "SUCCESS" "Handshake successful: filtering node can reach upstream"
|
|
else
|
|
log_message "WARNING" "Handshake failed (upstream may not be responding)"
|
|
log_message "INFO" "Checking if upstream is directly reachable..."
|
|
if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$UPSTREAM_IP/$UPSTREAM_PORT" 2>/dev/null; then
|
|
log_message "ERROR" "Upstream is reachable but filtering node cannot proxy"
|
|
echo -e "${YELLOW}Possible NGINX configuration issue. Check:${NC}"
|
|
echo -e "1. NGINX error log: sudo tail -50 /var/log/nginx/error.log"
|
|
echo -e "2. NGINX config: $NGINX_CONFIG"
|
|
else
|
|
log_message "WARNING" "Upstream server is not reachable (as previously warned)"
|
|
fi
|
|
fi
|
|
|
|
# Check Wallarm module status endpoint
|
|
log_message "INFO" "Checking Wallarm module status..."
|
|
if curl -sf --connect-timeout 5 "http://127.0.0.8/wallarm-status" >/dev/null 2>&1; then
|
|
log_message "SUCCESS" "Wallarm module is active (wallarm-status responsive)"
|
|
else
|
|
log_message "WARNING" "wallarm-status not responsive (module may need more time or a restart)"
|
|
fi
|
|
|
|
# Check node registration file
|
|
if [ -f "/opt/wallarm/etc/wallarm/node.yaml" ]; then
|
|
log_message "SUCCESS" "Node is registered (node.yaml present)"
|
|
else
|
|
log_message "WARNING" "node.yaml not found - node may not be registered with the cloud"
|
|
fi
|
|
|
|
log_message "SUCCESS" "Deployment verification completed"
|
|
echo -e "\n${GREEN}${BOLD}Verification Summary:${NC}"
|
|
echo -e " ${GREEN}✓${NC} NGINX + Wallarm module installed"
|
|
echo -e " ${GREEN}✓${NC} Ingress port: $INGRESS_PORT"
|
|
echo -e " ${GREEN}✓${NC} Upstream: $UPSTREAM_IP:$UPSTREAM_PORT"
|
|
echo -e " ${GREEN}✓${NC} Cloud region: $CLOUD_REGION ($API_HOST)"
|
|
}
|
|
|
|
# ==============================================================================
|
|
# MAIN FUNCTION
|
|
# ==============================================================================
|
|
|
|
main() {
|
|
clear
|
|
echo -e "${BLUE}${BOLD}"
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
echo "║ WALLARM DEPLOYMENT SCRIPT (Native) - V1.0 ║"
|
|
echo "║ Filtering Node Deployment Without Docker ║"
|
|
echo "╚══════════════════════════════════════════════════════════════╝${NC}"
|
|
echo -e "\n${YELLOW}Starting deployment at: $(date)${NC}"
|
|
|
|
# Initialize logging
|
|
local log_dir="${HOME:-.}/logs"
|
|
if [ ! -d "$log_dir" ]; then
|
|
if ! mkdir -p "$log_dir"; then
|
|
echo -e "${YELLOW}Cannot create log directory $log_dir, falling back to current directory...${NC}"
|
|
log_dir="."
|
|
fi
|
|
fi
|
|
|
|
LOG_FILE="$log_dir/wallarm-deployment-native.log"
|
|
if ! : > "$LOG_FILE"; then
|
|
echo -e "${RED}Cannot create log file at $LOG_FILE${NC}"
|
|
echo -e "${YELLOW}Falling back to current directory...${NC}"
|
|
LOG_FILE="./wallarm-deployment-native.log"
|
|
: > "$LOG_FILE" 2>/dev/null || true
|
|
fi
|
|
if ! chmod 644 "$LOG_FILE" 2>/dev/null; then
|
|
echo -e "${YELLOW}Warning: Could not set permissions on log file${NC}"
|
|
fi
|
|
|
|
log_message "INFO" "=== Wallarm Native Deployment Started ==="
|
|
|
|
if [ "$INSECURE_SSL" = "1" ]; then
|
|
log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation."
|
|
fi
|
|
|
|
# Phase 1: Verify preflight check
|
|
log_message "INFO" "=== PHASE 1: PREFLIGHT CHECK VERIFICATION ==="
|
|
verify_preflight_check
|
|
|
|
# Phase 2: Configuration collection
|
|
log_message "INFO" "=== PHASE 2: CONFIGURATION COLLECTION ==="
|
|
select_cloud_region
|
|
collect_configuration
|
|
|
|
# Phase 3: Native installation (all-in-one installer)
|
|
log_message "INFO" "=== PHASE 3: WALLARM NATIVE INSTALLATION ==="
|
|
install_wallarm_native
|
|
|
|
# Phase 4: NGINX configuration
|
|
log_message "INFO" "=== PHASE 4: NGINX CONFIGURATION ==="
|
|
resolve_port_conflict "$INGRESS_PORT"
|
|
create_nginx_config
|
|
reload_nginx
|
|
|
|
# Phase 5: Verification
|
|
log_message "INFO" "=== PHASE 5: VERIFICATION ==="
|
|
verify_deployment
|
|
|
|
# Success message
|
|
log_message "SUCCESS" "=== WALLARM NATIVE DEPLOYMENT COMPLETED SUCCESSFULLY ==="
|
|
echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${GREEN}${BOLD}║ WALLARM FILTERING NODE DEPLOYMENT SUCCESSFUL ║${NC}"
|
|
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
|
|
echo -e "\n${CYAN}The Wallarm filtering node is now active and protecting your application.${NC}"
|
|
echo -e "${YELLOW}Full deployment log: $LOG_FILE${NC}"
|
|
echo -e "${YELLOW}Instance directory: $INSTANCE_DIR${NC}"
|
|
echo -e "\n${GREEN}To stop the node:${NC} sudo systemctl stop nginx"
|
|
echo -e "${GREEN}To restart:${NC} sudo systemctl restart nginx"
|
|
echo -e "${GREEN}To view logs:${NC} sudo tail -f /var/log/nginx/error.log"
|
|
echo -e "${GREEN}Node status:${NC} curl http://127.0.0.8/wallarm-status"
|
|
echo -e "\n${MAGENTA}${BOLD}Deployment completed successfully!${NC}"
|
|
echo -e "\n${YELLOW}Important next steps:${NC}"
|
|
echo -e "1. Monitor sync status in Wallarm Console"
|
|
echo -e "2. Test attack detection with safe test: curl http://localhost:$INGRESS_PORT/?wallarm_test=1"
|
|
echo -e "3. Review logs periodically: sudo tail -50 /var/log/nginx/error.log"
|
|
echo -e "4. Switch to block mode after validation: sudo ./native/wallarm-ct-reconfigure.sh"
|
|
}
|
|
|
|
# ==============================================================================
|
|
# SCRIPT EXECUTION
|
|
# ==============================================================================
|
|
|
|
# Ensure we're in bash
|
|
if [ -z "$BASH_VERSION" ]; then
|
|
echo "Error: This script must be run with bash" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Run main function
|
|
main "$@"
|