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:
Executable
+257
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#########################################################################################
|
||||
#### add-nginx-block-head.sh — Block HEAD requests in Nginx (HestiaCP compatible) ####
|
||||
#### Adds a 444 drop rule for HEAD method crawlers/scrapers. ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version 1.01 ####
|
||||
#### ####
|
||||
#### Usage: ####
|
||||
#### sudo ./add-nginx-block-head.sh ####
|
||||
#### sudo ./add-nginx-block-head.sh --dry-run ####
|
||||
#### sudo ./add-nginx-block-head.sh --remove ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
#########################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
DRY_RUN=false
|
||||
REMOVE=false
|
||||
SNIPPET_NAME="nginx.conf_block_head"
|
||||
|
||||
# ── Colors ────────────────────────────────────────────────────────────
|
||||
if [[ -t 1 ]]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BOLD='\033[1m'
|
||||
RESET='\033[0m'
|
||||
else
|
||||
RED="" GREEN="" YELLOW="" BOLD="" RESET=""
|
||||
fi
|
||||
|
||||
log() { echo -e "${GREEN}[OK]${RESET} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
|
||||
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
||||
info() { echo -e "${BOLD}[INFO]${RESET} $*"; }
|
||||
|
||||
# ── Usage ─────────────────────────────────────────────────────────────
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [OPTIONS]
|
||||
|
||||
Block HTTP HEAD requests in Nginx by adding per-domain snippets that return
|
||||
444 (drop connection) for HEAD method requests.
|
||||
|
||||
Works with HestiaCP — adds custom nginx config snippets to each domain's
|
||||
server block via the conf/web include pattern.
|
||||
|
||||
Options:
|
||||
--dry-run Show what would be done without making changes
|
||||
--remove Remove the block-head snippets from all domains
|
||||
-h, --help Show this help
|
||||
|
||||
What it does:
|
||||
1. Finds all HestiaCP web domains
|
||||
2. Adds a custom nginx snippet to each domain's conf/web directory
|
||||
3. Tests Nginx configuration (nginx -t)
|
||||
4. Reloads Nginx if the test passes
|
||||
5. Rolls back ALL changes if the test fails
|
||||
|
||||
The snippet (added inside each domain's server block):
|
||||
if (\$request_method = HEAD) {
|
||||
return 444;
|
||||
}
|
||||
|
||||
444 drops the connection silently — no response headers, no body.
|
||||
Bots get nothing and waste their connection.
|
||||
EOF
|
||||
}
|
||||
|
||||
# ── Parse args ────────────────────────────────────────────────────────
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
--remove) REMOVE=true ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) err "Unknown option: $1"; usage; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# ── Preflight checks ─────────────────────────────────────────────────
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
err "Must run as root (sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v nginx &>/dev/null; then
|
||||
err "Nginx not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v v-list-users &>/dev/null; then
|
||||
err "HestiaCP not found (v-list-users missing)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Snippet content ──────────────────────────────────────────────────
|
||||
SNIPPET_CONTENT='# Block HEAD request crawlers/scrapers
|
||||
# Added by add-nginx-block-head.sh
|
||||
# Returns 444 (drop connection) — no response sent to bot
|
||||
if ($request_method = HEAD) {
|
||||
return 444;
|
||||
}'
|
||||
|
||||
# ── Find all HestiaCP domains ────────────────────────────────────────
|
||||
get_all_domain_dirs() {
|
||||
local users
|
||||
users=$(v-list-users plain 2>/dev/null | cut -f1)
|
||||
|
||||
for user in $users; do
|
||||
local user_conf="/home/${user}/conf/web"
|
||||
[[ -d "$user_conf" ]] || continue
|
||||
|
||||
# Find domain directories by looking for nginx.conf files
|
||||
for nginx_conf in "${user_conf}"/*/nginx.conf; do
|
||||
[[ -f "$nginx_conf" ]] || continue
|
||||
dirname "$nginx_conf"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# ── Remove mode ───────────────────────────────────────────────────────
|
||||
if [[ "$REMOVE" == "true" ]]; then
|
||||
removed=0
|
||||
|
||||
while IFS= read -r domain_dir; do
|
||||
snippet="${domain_dir}/${SNIPPET_NAME}"
|
||||
ssl_snippet="${domain_dir}/nginx.ssl.conf_block_head"
|
||||
|
||||
for f in "$snippet" "$ssl_snippet"; do
|
||||
if [[ -f "$f" ]]; then
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
info "Would remove: ${f}"
|
||||
else
|
||||
rm -f "$f"
|
||||
log "Removed ${f}"
|
||||
fi
|
||||
((removed++)) || true
|
||||
fi
|
||||
done
|
||||
done < <(get_all_domain_dirs)
|
||||
|
||||
if [[ $removed -eq 0 ]]; then
|
||||
info "No block-head snippets found — nothing to remove"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
info "Would test and reload Nginx"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if nginx -t 2>/dev/null; then
|
||||
systemctl reload nginx
|
||||
log "Nginx reloaded — HEAD requests are now allowed"
|
||||
else
|
||||
err "Nginx config test failed after removal — check your config"
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Install mode ──────────────────────────────────────────────────────
|
||||
domain_dirs=()
|
||||
while IFS= read -r dir; do
|
||||
domain_dirs+=("$dir")
|
||||
done < <(get_all_domain_dirs)
|
||||
|
||||
if [[ ${#domain_dirs[@]} -eq 0 ]]; then
|
||||
err "No HestiaCP web domains found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
info "Found ${#domain_dirs[@]} domain config(s)"
|
||||
echo ""
|
||||
|
||||
created=0
|
||||
skipped=0
|
||||
created_files=()
|
||||
|
||||
for domain_dir in "${domain_dirs[@]}"; do
|
||||
domain_name=$(basename "$domain_dir")
|
||||
|
||||
# Add snippet for both HTTP and HTTPS server blocks
|
||||
for conf_type in "" ".ssl"; do
|
||||
if [[ -n "$conf_type" ]]; then
|
||||
snippet="${domain_dir}/nginx${conf_type}.conf_block_head"
|
||||
else
|
||||
snippet="${domain_dir}/${SNIPPET_NAME}"
|
||||
fi
|
||||
|
||||
# Check the main config exists for this type
|
||||
main_conf="${domain_dir}/nginx${conf_type}.conf"
|
||||
[[ -f "$main_conf" ]] || continue
|
||||
|
||||
if [[ -f "$snippet" ]]; then
|
||||
info "Already exists: ${snippet}"
|
||||
((skipped++)) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
info "Would create: ${snippet}"
|
||||
((created++)) || true
|
||||
else
|
||||
echo "$SNIPPET_CONTENT" > "$snippet"
|
||||
created_files+=("$snippet")
|
||||
log "Created ${snippet}"
|
||||
((created++)) || true
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
if [[ $created -eq 0 && $skipped -gt 0 ]]; then
|
||||
info "HEAD requests are already blocked on all domains"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
echo ""
|
||||
echo "$SNIPPET_CONTENT"
|
||||
echo ""
|
||||
info "Would create ${created} snippet(s) (${skipped} already exist)"
|
||||
info "Would test Nginx config and reload"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test Nginx config
|
||||
info "Testing Nginx configuration..."
|
||||
if nginx -t 2>&1; then
|
||||
echo ""
|
||||
log "Config test passed"
|
||||
systemctl reload nginx
|
||||
log "Nginx reloaded — HEAD requests blocked on ${#domain_dirs[@]} domain(s) (444 drop)"
|
||||
else
|
||||
echo ""
|
||||
err "Config test FAILED — rolling back all changes"
|
||||
for f in "${created_files[@]}"; do
|
||||
rm -f "$f"
|
||||
err "Removed ${f}"
|
||||
done
|
||||
err "Nginx was NOT reloaded — your site is unaffected"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
info "Verify with: curl -I https://your-site.com"
|
||||
info "Expected: curl returns empty reply (connection dropped)"
|
||||
info "To undo: $(basename "$0") --remove"
|
||||
Reference in New Issue
Block a user