Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#########################################################################################
|
||||
#### nginx-security-hardening.sh — Add rate limiting, bot honeypot, security ####
|
||||
#### headers, query string filtering, and hotlink protection to nginx ####
|
||||
#### ####
|
||||
#### Supports standalone nginx (default) and HestiaCP/VestaCP ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version 2.04 ####
|
||||
#### ####
|
||||
#### Usage: ####
|
||||
#### sudo ./nginx-security-hardening.sh --domain example.com ####
|
||||
#### sudo ./nginx-security-hardening.sh --domain example.com --dry-run ####
|
||||
#### sudo ./nginx-security-hardening.sh --domain example.com --user admin ####
|
||||
#### sudo ./nginx-security-hardening.sh --domain example.com --skip honeypot ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
#########################################################################################
|
||||
# v2.03 changes:
|
||||
# - Fixed: grep in pipeline crashes under set -euo pipefail when no matches found. Added || true guard
|
||||
#########################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
DOMAIN=""
|
||||
USER=""
|
||||
DRY_RUN=false
|
||||
SKIP=()
|
||||
RATE="5r/m"
|
||||
BURST=10
|
||||
BANTIME=86400
|
||||
TRAP_PATH="/trap"
|
||||
DOWNLOAD_PATH="/downloads/"
|
||||
BACKUP_EXT=".bak.$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
# ── Colors ────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
# ── Usage ─────────────────────────────────────────────────────────────
|
||||
SCRIPT_NAME="$(basename "$0")"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
${SCRIPT_NAME} — Nginx security hardening (standalone or HestiaCP/VestaCP)
|
||||
|
||||
USAGE:
|
||||
sudo ${SCRIPT_NAME} --domain DOMAIN [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
--domain DOMAIN Domain name (required)
|
||||
--user USER HestiaCP/VestaCP username (omit for standalone nginx)
|
||||
--skip FEATURES Comma-separated: rate-limit, honeypot, headers, query-filter, hotlink-protection
|
||||
--rate RATE Rate limit (default: 5r/m)
|
||||
--burst NUM Rate limit burst (default: 10)
|
||||
--bantime SECS Honeypot ban duration (default: 86400)
|
||||
--trap-path PATH Honeypot path (default: /trap)
|
||||
--download-path PATH Rate-limited path (default: /downloads/)
|
||||
--dry-run Preview changes without writing files
|
||||
--help Show this help
|
||||
|
||||
EXAMPLES:
|
||||
${SCRIPT_NAME} --domain example.com
|
||||
${SCRIPT_NAME} --domain example.com --skip honeypot
|
||||
${SCRIPT_NAME} --domain example.com --user admin
|
||||
${SCRIPT_NAME} --domain example.com --dry-run
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||||
log_dry() { echo -e "${CYAN}[DRY-RUN]${NC} $*"; }
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────
|
||||
should_skip() {
|
||||
local feature="$1"
|
||||
for skip in "${SKIP[@]+"${SKIP[@]}"}"; do
|
||||
[[ "$skip" == "$feature" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
backup_file() {
|
||||
local file="$1"
|
||||
[[ -f "$file" ]] || return 0
|
||||
local backup_dir="$(dirname "$file")/.backups"
|
||||
local backup_dest="${backup_dir}/$(basename "$file")${BACKUP_EXT}"
|
||||
if $DRY_RUN; then
|
||||
log_dry "Would back up $file → ${backup_dest}"
|
||||
else
|
||||
mkdir -p "$backup_dir"
|
||||
cp "$file" "$backup_dest"
|
||||
log_info "Backed up $file"
|
||||
fi
|
||||
}
|
||||
|
||||
write_file() {
|
||||
local file="$1"
|
||||
local content="$2"
|
||||
local desc="$3"
|
||||
|
||||
if $DRY_RUN; then
|
||||
log_dry "Would create $file"
|
||||
echo -e "${CYAN}--- $desc ---${NC}"
|
||||
echo "$content"
|
||||
echo ""
|
||||
else
|
||||
mkdir -p "$(dirname "$file")"
|
||||
backup_file "$file"
|
||||
echo "$content" > "$file"
|
||||
log_info "Created $file"
|
||||
fi
|
||||
}
|
||||
|
||||
is_hestia_mode() { [[ -n "$USER" ]]; }
|
||||
|
||||
detect_backend() {
|
||||
local conf_dir="/home/${USER}/conf/web/${DOMAIN}"
|
||||
local http_backend=""
|
||||
local https_backend=""
|
||||
|
||||
if [[ -f "${conf_dir}/nginx.conf" ]]; then
|
||||
http_backend=$({ grep -m1 'proxy_pass' "${conf_dir}/nginx.conf" || true; } | awk '{print $2}' | tr -d ';')
|
||||
fi
|
||||
if [[ -f "${conf_dir}/nginx.ssl.conf" ]]; then
|
||||
https_backend=$({ grep -m1 'proxy_pass' "${conf_dir}/nginx.ssl.conf" || true; } | awk '{print $2}' | tr -d ';')
|
||||
fi
|
||||
|
||||
if [[ -z "$http_backend" || -z "$https_backend" ]]; then
|
||||
log_error "Could not detect backend proxy_pass from ${conf_dir}/nginx.conf"
|
||||
log_error "Check that the domain exists in HestiaCP/VestaCP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "${http_backend}|${https_backend}"
|
||||
}
|
||||
|
||||
# ── Parse Arguments ───────────────────────────────────────────────────
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--domain) DOMAIN="$2"; shift 2 ;;
|
||||
--user) USER="$2"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
--skip) IFS=',' read -ra SKIP <<< "$2"; shift 2 ;;
|
||||
--rate) RATE="$2"; shift 2 ;;
|
||||
--burst) BURST="$2"; shift 2 ;;
|
||||
--bantime) BANTIME="$2"; shift 2 ;;
|
||||
--trap-path) TRAP_PATH="$2"; shift 2 ;;
|
||||
--download-path) DOWNLOAD_PATH="$2"; shift 2 ;;
|
||||
-h|--help) usage ;;
|
||||
*) log_error "Unknown option: $1"; usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ── Validate ──────────────────────────────────────────────────────────
|
||||
if [[ -z "$DOMAIN" ]]; then
|
||||
log_error "Missing required --domain"
|
||||
usage
|
||||
fi
|
||||
|
||||
if [[ "$EUID" -ne 0 && "$DRY_RUN" == false ]]; then
|
||||
log_error "Must run as root (or use --dry-run to preview)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Detect Mode ───────────────────────────────────────────────────────
|
||||
if is_hestia_mode; then
|
||||
CONF_DIR="/home/${USER}/conf/web/${DOMAIN}"
|
||||
if [[ ! -d "$CONF_DIR" ]]; then
|
||||
log_error "Directory not found: ${CONF_DIR}"
|
||||
log_error "Check your --user and --domain values"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Mode: HestiaCP/VestaCP (user: ${USER}, domain: ${DOMAIN})"
|
||||
|
||||
BACKENDS=$(detect_backend)
|
||||
HTTP_BACKEND=$(echo "$BACKENDS" | cut -d'|' -f1)
|
||||
HTTPS_BACKEND=$(echo "$BACKENDS" | cut -d'|' -f2)
|
||||
log_info "Detected HTTP backend: ${HTTP_BACKEND}"
|
||||
log_info "Detected HTTPS backend: ${HTTPS_BACKEND}"
|
||||
|
||||
HTTPS_IS_SSL=false
|
||||
if [[ "$HTTPS_BACKEND" == https://* ]]; then
|
||||
HTTPS_IS_SSL=true
|
||||
fi
|
||||
else
|
||||
CONF_DIR="/etc/nginx"
|
||||
log_info "Mode: standalone nginx"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "Domain: ${DOMAIN}"
|
||||
log_info "Features to install:"
|
||||
should_skip rate-limit || log_info " ✓ Rate limiting (${RATE}, burst ${BURST}) on ${DOWNLOAD_PATH}"
|
||||
should_skip honeypot || log_info " ✓ Bot honeypot (${TRAP_PATH}, ban ${BANTIME}s)"
|
||||
should_skip headers || log_info " ✓ Security headers"
|
||||
should_skip query-filter || log_info " ✓ Query string filtering"
|
||||
should_skip hotlink-protection || log_info " ✓ Hotlink protection (images)"
|
||||
for skip in "${SKIP[@]+"${SKIP[@]}"}"; do
|
||||
log_warn " ✗ Skipping: ${skip}"
|
||||
done
|
||||
echo ""
|
||||
|
||||
# =====================================================================
|
||||
# 1. RATE LIMITING
|
||||
# =====================================================================
|
||||
if ! should_skip rate-limit; then
|
||||
log_info "Setting up rate limiting..."
|
||||
|
||||
RATE_ZONE_CONF="# Rate limit zone for download paths
|
||||
# Installed by nginx-security-hardening.sh
|
||||
limit_req_zone \$binary_remote_addr zone=downloads_${DOMAIN//./_}:10m rate=${RATE};"
|
||||
|
||||
write_file "/etc/nginx/conf.d/rate-limit-${DOMAIN}.conf" "$RATE_ZONE_CONF" "Rate limit zone (http context)"
|
||||
|
||||
if is_hestia_mode; then
|
||||
RATE_HTTP="# Rate limiting on ${DOWNLOAD_PATH}
|
||||
# Installed by nginx-security-hardening.sh
|
||||
location ${DOWNLOAD_PATH} {
|
||||
limit_req zone=downloads_${DOMAIN//./_} burst=${BURST} nodelay;
|
||||
limit_req_status 429;
|
||||
proxy_pass ${HTTP_BACKEND};
|
||||
}"
|
||||
write_file "${CONF_DIR}/nginx.conf_rate_limit" "$RATE_HTTP" "Rate limit (HTTP)"
|
||||
|
||||
RATE_HTTPS="# Rate limiting on ${DOWNLOAD_PATH}
|
||||
# Installed by nginx-security-hardening.sh
|
||||
location ${DOWNLOAD_PATH} {
|
||||
limit_req zone=downloads_${DOMAIN//./_} burst=${BURST} nodelay;
|
||||
limit_req_status 429;"
|
||||
if $HTTPS_IS_SSL; then
|
||||
RATE_HTTPS+="
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_name \$host;"
|
||||
fi
|
||||
RATE_HTTPS+="
|
||||
proxy_pass ${HTTPS_BACKEND};
|
||||
}"
|
||||
write_file "${CONF_DIR}/nginx.ssl.conf_rate_limit" "$RATE_HTTPS" "Rate limit (HTTPS)"
|
||||
else
|
||||
RATE_SNIPPET="# Rate limiting on ${DOWNLOAD_PATH}
|
||||
# Installed by nginx-security-hardening.sh
|
||||
# Include inside your server block: include snippets/rate-limit-${DOMAIN}.conf;
|
||||
location ${DOWNLOAD_PATH} {
|
||||
limit_req zone=downloads_${DOMAIN//./_} burst=${BURST} nodelay;
|
||||
limit_req_status 429;
|
||||
}"
|
||||
write_file "/etc/nginx/snippets/rate-limit-${DOMAIN}.conf" "$RATE_SNIPPET" "Rate limit snippet"
|
||||
log_info "Add to your server block: include snippets/rate-limit-${DOMAIN}.conf;"
|
||||
fi
|
||||
fi
|
||||
|
||||
# =====================================================================
|
||||
# 2. BOT HONEYPOT
|
||||
# =====================================================================
|
||||
if ! should_skip honeypot; then
|
||||
log_info "Setting up bot honeypot..."
|
||||
|
||||
HONEYPOT_LOG="/var/log/nginx/${DOMAIN}.honeypot.log"
|
||||
|
||||
if is_hestia_mode; then
|
||||
HONEYPOT_LOG="/var/log/nginx/domains/${DOMAIN}.honeypot.log"
|
||||
|
||||
TRAP_HTTP="# Bot honeypot — any request to ${TRAP_PATH} gets logged and blocked
|
||||
# Installed by nginx-security-hardening.sh
|
||||
location ${TRAP_PATH} {
|
||||
access_log ${HONEYPOT_LOG} combined;
|
||||
return 403;
|
||||
}"
|
||||
write_file "${CONF_DIR}/nginx.conf_honeypot" "$TRAP_HTTP" "Honeypot (HTTP)"
|
||||
|
||||
TRAP_HTTPS="# Bot honeypot — any request to ${TRAP_PATH} gets logged and blocked
|
||||
# Installed by nginx-security-hardening.sh
|
||||
location ${TRAP_PATH} {
|
||||
access_log ${HONEYPOT_LOG} combined;
|
||||
return 403;
|
||||
}"
|
||||
write_file "${CONF_DIR}/nginx.ssl.conf_honeypot" "$TRAP_HTTPS" "Honeypot (HTTPS)"
|
||||
else
|
||||
TRAP_SNIPPET="# Bot honeypot — any request to ${TRAP_PATH} gets logged and blocked
|
||||
# Installed by nginx-security-hardening.sh
|
||||
# Include inside your server block: include snippets/honeypot-${DOMAIN}.conf;
|
||||
location ${TRAP_PATH} {
|
||||
access_log ${HONEYPOT_LOG} combined;
|
||||
return 403;
|
||||
}"
|
||||
write_file "/etc/nginx/snippets/honeypot-${DOMAIN}.conf" "$TRAP_SNIPPET" "Honeypot snippet"
|
||||
log_info "Add to your server block: include snippets/honeypot-${DOMAIN}.conf;"
|
||||
fi
|
||||
|
||||
# Fail2ban filter
|
||||
HONEYPOT_FILTER="# Bot honeypot filter
|
||||
# Installed by nginx-security-hardening.sh
|
||||
[Definition]
|
||||
failregex = ^<HOST> .* \"(GET|POST|HEAD) ${TRAP_PATH}
|
||||
ignoreregex ="
|
||||
|
||||
write_file "/etc/fail2ban/filter.d/nginx-honeypot.conf" "$HONEYPOT_FILTER" "Fail2ban honeypot filter"
|
||||
|
||||
# Fail2ban jail
|
||||
HONEYPOT_JAIL="# Bot honeypot jail — ban on first hit
|
||||
# Installed by nginx-security-hardening.sh
|
||||
[nginx-honeypot]
|
||||
enabled = true
|
||||
port = http,https
|
||||
filter = nginx-honeypot
|
||||
logpath = ${HONEYPOT_LOG}
|
||||
maxretry = 1
|
||||
bantime = ${BANTIME}
|
||||
findtime = ${BANTIME}"
|
||||
|
||||
write_file "/etc/fail2ban/jail.d/nginx-honeypot.conf" "$HONEYPOT_JAIL" "Fail2ban honeypot jail"
|
||||
|
||||
# Create the log file so fail2ban doesn't complain
|
||||
if ! $DRY_RUN; then
|
||||
touch "$HONEYPOT_LOG"
|
||||
chmod 644 "$HONEYPOT_LOG"
|
||||
fi
|
||||
|
||||
log_warn "Add a hidden link to your site template to attract bots:"
|
||||
echo -e " ${CYAN}<a href=\"${TRAP_PATH}/\" style=\"display:none\" aria-hidden=\"true\" tabindex=\"-1\">admin</a>${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# =====================================================================
|
||||
# 3. SECURITY HEADERS
|
||||
# =====================================================================
|
||||
if ! should_skip headers; then
|
||||
log_info "Setting up security headers..."
|
||||
|
||||
HEADERS_CONF="# Security headers
|
||||
# Installed by nginx-security-hardening.sh
|
||||
|
||||
# Prevent MIME type sniffing
|
||||
add_header X-Content-Type-Options \"nosniff\" always;
|
||||
|
||||
# Prevent clickjacking (SAMEORIGIN allows AWStats/panel frames)
|
||||
add_header X-Frame-Options \"SAMEORIGIN\" always;
|
||||
|
||||
# Control referrer information
|
||||
add_header Referrer-Policy \"strict-origin-when-cross-origin\" always;
|
||||
|
||||
# Restrict browser features
|
||||
add_header Permissions-Policy \"camera=(), microphone=(), geolocation=(), payment=()\" always;
|
||||
|
||||
# Prevent XSS in older browsers
|
||||
add_header X-XSS-Protection \"1; mode=block\" always;"
|
||||
|
||||
if is_hestia_mode; then
|
||||
write_file "${CONF_DIR}/nginx.conf_security_headers" "$HEADERS_CONF" "Security headers (HTTP)"
|
||||
write_file "${CONF_DIR}/nginx.ssl.conf_security_headers" "$HEADERS_CONF" "Security headers (HTTPS)"
|
||||
else
|
||||
write_file "/etc/nginx/snippets/security-headers-${DOMAIN}.conf" "$HEADERS_CONF" "Security headers snippet"
|
||||
log_info "Add to your server block: include snippets/security-headers-${DOMAIN}.conf;"
|
||||
fi
|
||||
fi
|
||||
|
||||
# =====================================================================
|
||||
# 4. QUERY STRING FILTERING
|
||||
# =====================================================================
|
||||
if ! should_skip query-filter; then
|
||||
log_info "Setting up query string filtering..."
|
||||
|
||||
QUERY_CONF="# Block malicious query strings (SQL injection, XSS, path traversal)
|
||||
# Installed by nginx-security-hardening.sh
|
||||
|
||||
# SQL injection patterns
|
||||
if (\$query_string ~* \"(union|select\s.*from|insert\s.*into|delete\s.*from|drop\s+table|update\s.*set|concat\s*\(|exec\s*\()\") {
|
||||
return 403;
|
||||
}
|
||||
|
||||
# XSS patterns
|
||||
if (\$query_string ~* \"(<script|javascript:|on(?:error|load|click|mouseover)=)\") {
|
||||
return 403;
|
||||
}
|
||||
|
||||
# Path traversal
|
||||
if (\$query_string ~* \"(\\.\\./|\\.\\.\\\\/)\") {
|
||||
return 403;
|
||||
}
|
||||
|
||||
# Common exploit tools
|
||||
if (\$query_string ~* \"(base64_decode|eval\s*\\(|php://input)\") {
|
||||
return 403;
|
||||
}"
|
||||
|
||||
if is_hestia_mode; then
|
||||
write_file "${CONF_DIR}/nginx.conf_query_filter" "$QUERY_CONF" "Query filter (HTTP)"
|
||||
write_file "${CONF_DIR}/nginx.ssl.conf_query_filter" "$QUERY_CONF" "Query filter (HTTPS)"
|
||||
else
|
||||
write_file "/etc/nginx/snippets/query-filter-${DOMAIN}.conf" "$QUERY_CONF" "Query filter snippet"
|
||||
log_info "Add to your server block: include snippets/query-filter-${DOMAIN}.conf;"
|
||||
fi
|
||||
fi
|
||||
|
||||
# =====================================================================
|
||||
# 5. HOTLINK PROTECTION
|
||||
# =====================================================================
|
||||
if ! should_skip hotlink-protection; then
|
||||
log_info "Setting up hotlink protection..."
|
||||
|
||||
HOTLINK_CONF="# Hotlink protection — block image requests from other domains
|
||||
# Installed by nginx-security-hardening.sh
|
||||
location ~* \.(png|jpg|jpeg|gif|webp|svg|ico)$ {
|
||||
valid_referers none blocked ${DOMAIN} *.${DOMAIN};
|
||||
if (\$invalid_referer) {
|
||||
return 403;
|
||||
}
|
||||
}"
|
||||
|
||||
if is_hestia_mode; then
|
||||
write_file "${CONF_DIR}/nginx.conf_hotlink_protection" "$HOTLINK_CONF" "Hotlink protection (HTTP)"
|
||||
write_file "${CONF_DIR}/nginx.ssl.conf_hotlink_protection" "$HOTLINK_CONF" "Hotlink protection (HTTPS)"
|
||||
else
|
||||
write_file "/etc/nginx/snippets/hotlink-protection-${DOMAIN}.conf" "$HOTLINK_CONF" "Hotlink protection snippet"
|
||||
log_info "Add to your server block: include snippets/hotlink-protection-${DOMAIN}.conf;"
|
||||
fi
|
||||
fi
|
||||
|
||||
# =====================================================================
|
||||
# FINALIZE
|
||||
# =====================================================================
|
||||
echo ""
|
||||
|
||||
if $DRY_RUN; then
|
||||
log_dry "No changes were made (dry-run mode)"
|
||||
log_dry "Remove --dry-run to apply changes"
|
||||
else
|
||||
log_info "Testing nginx configuration..."
|
||||
if nginx -t 2>&1; then
|
||||
log_info "Nginx config test passed"
|
||||
log_info "Reloading nginx..."
|
||||
systemctl reload nginx
|
||||
log_info "Nginx reloaded"
|
||||
else
|
||||
log_error "Nginx config test FAILED — check the errors above"
|
||||
log_error "Your previous config is still active (no reload happened)"
|
||||
log_error "Backup files are in .backups/ subdirectories"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! should_skip honeypot; then
|
||||
if systemctl is-active --quiet fail2ban; then
|
||||
log_info "Reloading fail2ban..."
|
||||
fail2ban-client reload 2>/dev/null || true
|
||||
log_info "Fail2ban reloaded"
|
||||
else
|
||||
log_warn "Fail2ban is not running — start it to enable the honeypot jail"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "Installation complete!"
|
||||
echo ""
|
||||
|
||||
should_skip rate-limit || echo -e " ${GREEN}✓${NC} Rate limiting: ${RATE} on ${DOWNLOAD_PATH} (burst ${BURST})"
|
||||
should_skip honeypot || echo -e " ${GREEN}✓${NC} Bot honeypot: ${TRAP_PATH} → ban ${BANTIME}s"
|
||||
should_skip headers || echo -e " ${GREEN}✓${NC} Security headers: X-Frame-Options, CSP, Referrer-Policy"
|
||||
should_skip query-filter || echo -e " ${GREEN}✓${NC} Query filter: SQL injection, XSS, path traversal blocked"
|
||||
should_skip hotlink-protection || echo -e " ${GREEN}✓${NC} Hotlink protection: Image hotlinking blocked"
|
||||
|
||||
if ! is_hestia_mode; then
|
||||
echo ""
|
||||
log_info "Standalone nginx — include the snippets in your server block:"
|
||||
should_skip rate-limit || echo -e " ${CYAN}include snippets/rate-limit-${DOMAIN}.conf;${NC}"
|
||||
should_skip honeypot || echo -e " ${CYAN}include snippets/honeypot-${DOMAIN}.conf;${NC}"
|
||||
should_skip headers || echo -e " ${CYAN}include snippets/security-headers-${DOMAIN}.conf;${NC}"
|
||||
should_skip query-filter || echo -e " ${CYAN}include snippets/query-filter-${DOMAIN}.conf;${NC}"
|
||||
should_skip hotlink-protection || echo -e " ${CYAN}include snippets/hotlink-protection-${DOMAIN}.conf;${NC}"
|
||||
fi
|
||||
|
||||
if ! should_skip honeypot; then
|
||||
echo ""
|
||||
log_warn "Don't forget to add the hidden honeypot link to your site template!"
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user