diff --git a/src/common/core/adidos/README.md b/src/common/core/adidos/README.md new file mode 100644 index 0000000000..ff5e22b0c9 --- /dev/null +++ b/src/common/core/adidos/README.md @@ -0,0 +1,265 @@ +# ADIDOS (Adaptive DDoS Protection System) + +ADIDOS is an intelligent load-based antibot control system that automatically monitors remote server CPU load and dynamically enables or disables antibot protection based on configurable thresholds. This helps protect your infrastructure during high-load periods while maintaining user experience during normal operations. + +**How it works:** + +1. ADIDOS continuously monitors the CPU load of a remote server via SSH connection. +2. When CPU load exceeds the high threshold, antibot protection is automatically enabled. +3. When CPU load drops below the low threshold and cooldown period has passed, antibot protection is automatically disabled. +4. Optional webhook notifications keep you informed of protection status changes. +5. The system uses configurable cooldown periods to prevent rapid toggling of protection. + +### How to Use + +Follow these steps to enable and configure the ADIDOS feature: + +1. **Set up SSH access:** Configure SSH key-based authentication to your monitored server. +2. **Mount SSH keys:** Ensure SSH private key is accessible in the bw-scheduler container. +3. **Enable the feature:** Set the `USE_ADIDOS` setting to `yes` in your BunkerWeb configuration. +4. **Configure monitoring:** Set the target host, thresholds, and other ADIDOS settings. +5. **Optional:** Configure webhook notifications for real-time alerts. + +!!! important "SSH Requirements" + The bw-scheduler container already includes SSH client pre-installed. You only need to: + - Mount or manually place an SSH private key in the container at the path specified in `ADIDOS_SSH_KEY` (default: `/usr/share/bunkerweb/scheduler/.ssh/id_rsa`) + - Ensure the key has passwordless access to the monitored server + - The SSH client is already available in the container via the src/scheduler/Dockerfile installation (at line 44 add `RUN apk add .... ssh`) or by installing it manually (docker exec bw-scheduler bash -c "apk add --no-cache openssh && which ssh") + - The SSH client version must be at least 7.0 (docker exec bw-scheduler bash -c "ssh -V") + +!!! warning "Docker Configuration Required" + When using Docker, you **must** mount the SSH directory to the bw-scheduler container. See the [Docker Configuration](#docker-configuration) section below for the complete setup. + +### Configuration Settings + +The following settings control ADIDOS behavior: + +| Setting | Default | Context | Multiple | Description | +| -------------------------- | ---------------------------------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- | +| `USE_ADIDOS` | `no` | global | no | **Enable ADIDOS:** Set to `yes` to enable load-based antibot control. | +| `ADIDOS_HOST` | `85.198.111.8` | global | no | **Monitor Host:** Remote server hostname or IP address to monitor for CPU load. | +| `ADIDOS_SSH_KEY` | `/usr/share/bunkerweb/scheduler/.ssh/id_rsa` | global | no | **SSH Private Key:** Path to SSH private key file for remote server access. | +| `ADIDOS_THRESHOLD_HIGH` | `80` | global | no | **High Load Threshold:** CPU load percentage to trigger antibot activation. | +| `ADIDOS_THRESHOLD_LOW` | `50` | global | no | **Low Load Threshold:** CPU load percentage to trigger antibot deactivation. | +| `ADIDOS_COOLDOWN_MINUTES` | `5` | global | no | **Cooldown Period:** Minutes to wait before disabling antibot after load drops. | +| `ADIDOS_CAPTCHA_TYPE` | `no` | global | no | **Captcha Type:** Type of antibot challenge to activate (cookie, javascript, captcha, etc.). | +| `ADIDOS_SERVICES` | | global | no | **Services:** Space-separated list of services to apply antibot protection to. | +| `ADIDOS_USE_WEBHOOK` | `no` | global | no | **Enable Webhooks:** Set to `yes` to enable webhook notifications. | +| `ADIDOS_WEB_HOOK_URL` | | global | no | **Webhook URL:** HTTP endpoint to send notifications to. | +| `ADIDOS_WEB_HOOK_BODY` | `{\"chat\": \"\", \"text\": \"{{MESSAGE}}\"}` | global | no | **Webhook Body:** Template for webhook payload. Use `{{MESSAGE}}` placeholder for content. | +| `ADIDOS_LOG` | `no` | global | no | **Enable Logging:** Set to `yes` to enable detailed ADIDOS logging. | + +### Supported Antibot Types + +ADIDOS can activate any of the following antibot challenge types: + +- **no** - No antibot protection +- **cookie** - Simple cookie-based challenge +- **javascript** - JavaScript computational challenge +- **captcha** - Image-based CAPTCHA challenge +- **recaptcha** - Google reCAPTCHA integration +- **hcaptcha** - hCaptcha integration +- **turnstile** - Cloudflare Turnstile integration +- **mcaptcha** - mCaptcha integration + +For external services (reCAPTCHA, hCaptcha, Turnstile, mCaptcha), you must configure the appropriate API keys in the antibot plugin settings. + +### Webhook Notifications + +ADIDOS can send webhook notifications when antibot protection is enabled or disabled. This is useful for monitoring and alerting purposes. + +**Webhook Message Format:** +- **Activation:** `🛡️ ADIDOS: antibot enabled, current load {load}%` +- **Deactivation:** `✅ ADIDOS: antibot disabled after {duration} activity, current load {load}%` + +**Webhook Configuration Examples:** + +=== \"Telegram Bot\" + + ```yaml + ADIDOS_USE_WEBHOOK: \"yes\" + ADIDOS_WEB_HOOK_URL: \"https://api.telegram.org/bot/sendMessage\" + ADIDOS_WEB_HOOK_BODY: '{\"chat_id\": \"\", \"text\": \"{{MESSAGE}}\"}' + ``` + +=== \"Discord Webhook\" + + ```yaml + ADIDOS_USE_WEBHOOK: \"yes\" + ADIDOS_WEB_HOOK_URL: \"https://discord.com/api/webhooks//\" + ADIDOS_WEB_HOOK_BODY: '{\"content\": \"{{MESSAGE}}\"}' + ``` + +=== \"Slack Webhook\" + + ```yaml + ADIDOS_USE_WEBHOOK: \"yes\" + ADIDOS_WEB_HOOK_URL: \"https://hooks.slack.com/services/\" + ADIDOS_WEB_HOOK_BODY: '{\"text\": \"{{MESSAGE}}\"}' + ``` + +### Docker Configuration + +When using ADIDOS with Docker, you must mount the SSH directory to the bw-scheduler container. The SSH client is already pre-installed in the container. Here's the complete configuration: + +```yaml +bw-scheduler: + image: bunkerity/bunkerweb-scheduler:1.6.3 + user: $(id -u):$(id -g) + env_file: + - .env + environment: + <<: *bw-env + BUNKERWEB_INSTANCES: \"${BUNKERWEB_INSTANCES}\" + MULTISITE: \"${MULTISITE}\" + DATABASE_URI: \"${DATABASE_URI}\" + SERVE_FILES: \"${SERVE_FILES}\" + DISABLE_DEFAULT_SERVER: \"${DISABLE_DEFAULT_SERVER}\" + USE_CLIENT_CACHE: \"${USE_CLIENT_CACHE}\" + USE_GZIP: \"${USE_GZIP}\" + AUTO_LETS_ENCRYPT: \"${AUTO_LETS_ENCRYPT}\" + EMAIL_LETS_ENCRYPT: \"${EMAIL_LETS_ENCRYPT}\" + ${SERVER_NAME}_USE_TEMPLATE: \"ui\" + ${SERVER_NAME}_USE_REVERSE_PROXY: \"yes\" + ${SERVER_NAME}_REVERSE_PROXY_URL: \"${REVERSE_PROXY_URL}\" # Change it to a hard to guess URI + ${SERVER_NAME}_REVERSE_PROXY_HOST: \"${REVERSE_PROXY_HOST}\" + volumes: + - ./data/bw-storage:/data # This is used to persist the cache and other data like the backups + - ~/.ssh:/usr/share/bunkerweb/scheduler/.ssh # SSH keys for ADIDOS monitoring + restart: \"unless-stopped\" + networks: + - bw-universe + - bw-db + depends_on: + bw-db: + condition: service_healthy + restart: true + bw-redis: + condition: service_healthy + restart: true + logging: + driver: syslog + options: + tag: \"bw-scheduler\" # This will be the tag used by syslog-ng to create the log file + syslog-address: \"udp://${SYSLOG_NG_IP}:514\" # This is the syslog-ng container address +``` + +!!! important \"SSH Client Pre-installed\" + The bw-scheduler container comes with SSH client pre-installed via the Dockerfile. You don't need to modify the Dockerfile or install SSH manually. The installation is handled by this line in the Dockerfile: + ```dockerfile + RUN apk add --no-cache bash unzip libgcc libstdc++ libpq openssl libmagic mariadb-connector-c mariadb-client postgresql-client sqlite tzdata sed grep ssh curl + ``` + +!!! important \"SSH Key Requirements\" + - The SSH private key must be readable by the user running the bw-scheduler container + - The key must have passwordless access to the monitored server + - Ensure the `~/.ssh/known_hosts` file contains the monitored server's host key, or ADIDOS will use `StrictHostKeyChecking=no` + +### Example Configurations + +=== \"Basic Configuration\" + + ```yaml + USE_ADIDOS: \"yes\" + ADIDOS_HOST: \"192.168.1.100\" + ADIDOS_SSH_KEY: \"/usr/share/bunkerweb/scheduler/.ssh/id_rsa\" + ADIDOS_THRESHOLD_HIGH: \"80\" + ADIDOS_THRESHOLD_LOW: \"50\" + ADIDOS_COOLDOWN_MINUTES: \"5\" + ADIDOS_CAPTCHA_TYPE: \"captcha\" + ADIDOS_SERVICES: \"example.com www.example.com\" + ``` + +=== \"With Webhook Notifications\" + + ```yaml + USE_ADIDOS: \"yes\" + ADIDOS_HOST: \"192.168.1.100\" + ADIDOS_SSH_KEY: \"/usr/share/bunkerweb/scheduler/.ssh/id_rsa\" + ADIDOS_THRESHOLD_HIGH: \"75\" + ADIDOS_THRESHOLD_LOW: \"40\" + ADIDOS_COOLDOWN_MINUTES: \"10\" + ADIDOS_CAPTCHA_TYPE: \"javascript\" + ADIDOS_SERVICES: \"api.example.com\" + ADIDOS_USE_WEBHOOK: \"yes\" + ADIDOS_WEB_HOOK_URL: \"https://api.telegram.org/bot/sendMessage\" + ADIDOS_WEB_HOOK_BODY: '{\"chat_id\": \"\", \"text\": \"{{MESSAGE}}\"}' + ADIDOS_LOG: \"yes\" + ``` + +=== \"High-Security Configuration\" + + ```yaml + USE_ADIDOS: \"yes\" + ADIDOS_HOST: \"production-server.example.com\" + ADIDOS_SSH_KEY: \"/usr/share/bunkerweb/scheduler/.ssh/production_key\" + ADIDOS_THRESHOLD_HIGH: \"70\" + ADIDOS_THRESHOLD_LOW: \"30\" + ADIDOS_COOLDOWN_MINUTES: \"15\" + ADIDOS_CAPTCHA_TYPE: \"recaptcha\" + ADIDOS_SERVICES: \"app.example.com api.example.com\" + ADIDOS_USE_WEBHOOK: \"yes\" + ADIDOS_WEB_HOOK_URL: \"https://monitoring.example.com/webhook\" + ADIDOS_WEB_HOOK_BODY: '{\"alert\": \"ADIDOS\", \"message\": \"{{MESSAGE}}\", \"timestamp\": \"{{TIMESTAMP}}\"}' + ADIDOS_LOG: \"yes\" + ``` + +### Monitoring and Troubleshooting + +**Common Issues:** + +1. **SSH Connection Failed:** + - Verify SSH key permissions (should be 600) + - Check if the monitored server is accessible + - Ensure SSH key is properly mounted in the container + - SSH client is pre-installed, no additional installation needed + +2. **Load Detection Issues:** + - Verify the monitored server has `top` command available + - Check if the SSH user has sufficient permissions + - Enable logging with `ADIDOS_LOG: \"yes\"` for detailed diagnostics + +3. **Webhook Delivery Failed:** + - Verify webhook URL is accessible from the container + - Check webhook body format matches the target service requirements + - Review container logs for webhook error messages + +**Monitoring Commands:** + +```bash +# Check ADIDOS logs +docker logs bw-scheduler | grep ADIDOS + +# Test SSH connection manually +docker exec bw-scheduler ssh -i /usr/share/bunkerweb/scheduler/.ssh/id_rsa user@target-host \"top -bn1 | grep 'Cpu(s)'\" + +# Check current antibot state +docker exec bw-scheduler cat /data/cache/adidos-monitor/antibot_state + +# Verify SSH client is available +docker exec bw-scheduler which ssh +``` + +### Security Considerations + +- **SSH Key Security:** Use dedicated SSH keys with minimal privileges for monitoring +- **Network Access:** Ensure the monitored server is only accessible from trusted networks +- **Webhook Security:** Use HTTPS endpoints and consider authentication for webhook URLs +- **Threshold Tuning:** Set appropriate thresholds to avoid false positives during normal load spikes +- **Cooldown Periods:** Configure adequate cooldown periods to prevent rapid protection toggling +- **Container Security:** The SSH client is securely installed in the container during build time + +### Technical Notes + +**SSH Installation in Container:** +The bw-scheduler container includes SSH client pre-installed through the Dockerfile. The relevant installation line is: +```dockerfile +RUN apk add --no-cache bash unzip libgcc libstdc++ libpq openssl libmagic mariadb-connector-c mariadb-client postgresql-client sqlite tzdata sed grep ssh curl +``` + +This means you don't need to: +- Modify the Dockerfile +- Install SSH manually +- Build custom images + +You only need to provide the SSH keys and proper configuration. \ No newline at end of file diff --git a/src/common/core/adidos/jobs/adidos-monitor.py b/src/common/core/adidos/jobs/adidos-monitor.py new file mode 100644 index 0000000000..b64120e63d --- /dev/null +++ b/src/common/core/adidos/jobs/adidos-monitor.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 + +from Database import Database +from jobs import Job +from logger import setup_logger +from datetime import datetime, timedelta +from os import getenv, sep +from os.path import join +from sys import exit as sys_exit, path as sys_path +from traceback import format_exc +import subprocess +import json +import requests + +for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("db",))]: + if deps_path not in sys_path: + sys_path.append(deps_path) + + +# LOGGER = setup_logger("ADIDOS.monitor", getenv("LOG_LEVEL", "info")) +LOG_LEVEL = "info" if getenv("ADIDOS_LOG") == "yes" else getenv("LOG_LEVEL", "error") + +LOGGER = setup_logger("ADIDOS.monitor", LOG_LEVEL) + +exit_status = 0 + + +def send_webhook(message): + """Send webhook notification""" + # Check if webhooks are enabled + use_webhook = getenv("ADIDOS_USE_WEBHOOK", "no").lower() == "yes" + if not use_webhook: + LOGGER.debug("Webhooks are disabled, skipping webhook") + return + + webhook_url = getenv("ADIDOS_WEB_HOOK_URL") + webhook_body = getenv("ADIDOS_WEB_HOOK_BODY") + + if not webhook_url or not webhook_body: + LOGGER.debug("Webhook URL or body not configured, skipping webhook") + return + + try: + # Replace placeholder with actual message + body = webhook_body.replace("{{MESSAGE}}", message) + + # Try to parse as JSON, if fails send as plain text + try: + json_body = json.loads(body) + headers = {"Content-Type": "application/json"} + response = requests.post(webhook_url, json=json_body, headers=headers, timeout=10) + except json.JSONDecodeError: + headers = {"Content-Type": "text/plain"} + response = requests.post(webhook_url, data=body, headers=headers, timeout=10) + + if response.status_code == 200: + LOGGER.info(f"Webhook sent successfully: {message}") + else: + LOGGER.error(f"Webhook failed with status {response.status_code}: {response.text}") + + except Exception as e: + LOGGER.error(f"Failed to send webhook: {e}") + + +try: + LOGGER.info("ADIDOS monitoring is started") + # Check if ADIDOS monitoring is enabled + if getenv("USE_ADIDOS", "no") != "yes": + LOGGER.info("ADIDOS monitoring is disabled") + sys_exit(0) + LOGGER.info("ADIDOS monitoring is enabled") + + # Configuration + monitor_host = getenv("ADIDOS_HOST", "85.198.111.8") + ssh_key_path = getenv("ADIDOS_SSH_KEY", "/usr/share/bunkerweb/scheduler/.ssh/id_rsa") + high_threshold = float(getenv("ADIDOS_THRESHOLD_HIGH", "80")) + low_threshold = float(getenv("ADIDOS_THRESHOLD_LOW", "50")) + cooldown_minutes = int(getenv("ADIDOS_COOLDOWN_MINUTES", "5")) + + if not monitor_host: + LOGGER.error("ADIDOS_HOST not configured") + sys_exit(1) + + # Initialize job and database + JOB = Job(LOGGER, __file__) + DB = Database(LOGGER, sqlalchemy_string=getenv("DATABASE_URI", None)) + + # Get current load via SSH + ssh_cmd = [ + "ssh", + "-i", + ssh_key_path, + "-o", + "StrictHostKeyChecking=no", + "-o", + "ConnectTimeout=10", + monitor_host, + "top -bn1 | grep 'Cpu(s)' | awk '{print $8}' | cut -d'%' -f1 | awk '{print 100-$1}'", + ] + + try: + result = subprocess.run(ssh_cmd, capture_output=True, text=True, timeout=30) + if result.returncode != 0: + LOGGER.error(f"SSH command failed: {result.stderr}") + sys_exit(1) + + current_load = float(result.stdout.strip()) + LOGGER.info(f"Current load: {current_load}%") + except Exception as e: + LOGGER.error(f"Failed to get load: {e}") + sys_exit(1) + + # Get cached state + cached_state = JOB.get_cache("antibot_state") + if cached_state: + try: + # Parse cached state + if isinstance(cached_state, str): + cached_data = cached_state.split(",") + elif isinstance(cached_state, bytes): + cached_data = cached_state.decode().split(",") + elif isinstance(cached_state, dict) and "data" in cached_state: + # Handle dict format + if isinstance(cached_state["data"], bytes): + cached_data = cached_state["data"].decode().split(",") + else: + cached_data = str(cached_state["data"]).split(",") + else: + raise ValueError(f"Unexpected cached_state type: {type(cached_state)}") + + if len(cached_data) >= 2: + cached_antibot, last_activation_str = cached_data[0], cached_data[1] + last_activation = datetime.fromisoformat(last_activation_str) + else: + cached_antibot = "no" + last_activation = datetime.now() + except Exception as e: + LOGGER.warning(f"Failed to parse cached state: {e}") + cached_antibot = "no" + last_activation = datetime.now() + else: + cached_antibot = "yes" + last_activation = datetime.now() + cache_data = f"{cached_antibot},{datetime.now().isoformat()}" + JOB.cache_file("antibot_state", cache_data.encode()) + + # Decision logic + should_enable = False + should_disable = False + new_antibot_state = current_antibot = cached_antibot + + if current_load >= high_threshold and current_antibot == "no": + should_enable = True + new_antibot_state = "yes" + LOGGER.info(f"Load {current_load}% >= {high_threshold}%, should enable antibot") + elif current_load <= low_threshold and current_antibot == "yes": + # Check cooldown period + time_since_activation = datetime.now() - last_activation + if time_since_activation >= timedelta(minutes=cooldown_minutes): + should_disable = True + new_antibot_state = "no" + LOGGER.info(f"Load {current_load}% <= {low_threshold}% and cooldown passed, should disable antibot") + else: + LOGGER.info(f"Load low but cooldown period not passed ({time_since_activation} < {cooldown_minutes}min)") + + # Apply changes + if should_enable: + LOGGER.info("Decision: Enable antibot (captcha mode)") + # Update cache with new activation time + cache_data = f"yes,{datetime.now().isoformat()}" + JOB.cache_file("antibot_state", cache_data.encode()) + config = DB.get_config(with_drafts=True) + services = getenv("ADIDOS_SERVICES", "").split(" ") + config_update = config + + # Save to database + try: + captcha_type = getenv("ADIDOS_CAPTCHA_TYPE", "captcha") + for service in services: + config_update[f"{service}_USE_ANTIBOT"] = captcha_type + result = DB.save_config(config_update, method="scheduler", changed=True) + if isinstance(result, str): + LOGGER.warning(f"Failed to save antibot state to database: {result}") + else: + LOGGER.info("Antibot state successfully saved to database") + # Send webhook notification + send_webhook(f"🛡️ ADIDOS: antibot enabled, current load {current_load}%") + except Exception as e: + LOGGER.error(f"Exception while saving to database: {e}") + + elif should_disable: + LOGGER.info("Decision: Disable antibot") + # Clear activation time from cache + cache_data = f"no,{datetime.now().isoformat()}" + JOB.cache_file("antibot_state", cache_data.encode()) + + # Get config and services for disabling + config = DB.get_config(with_drafts=True) + services = getenv("ADIDOS_SERVICES", "").split(" ") + config_update = config + + # Save to database + try: + for service in services: + config_update[f"{service}_USE_ANTIBOT"] = "no" + result = DB.save_config(config_update, method="scheduler", changed=True) + if isinstance(result, str): + LOGGER.warning(f"Failed to save antibot state to database: {result}") + else: + LOGGER.info("Antibot state successfully saved to database") + # Send webhook notification + time_since_activation = datetime.now() - last_activation + hours = int(time_since_activation.total_seconds() // 3600) + minutes = int((time_since_activation.total_seconds() % 3600) // 60) + time_format = f"{hours:02d}h {minutes:02d}m" if hours > 0 else f"{minutes} minutes" + send_webhook(f"✅ ADIDOS: antibot disabled after {time_format} activity, current load {current_load}%") + except Exception as e: + LOGGER.error(f"Exception while saving to database: {e}") + else: + LOGGER.info(f"Decision: No change needed (current: {current_antibot}, load: {current_load}%)") + +except SystemExit as e: + LOGGER.info(f"Nothing to do, exit status: {e.code}") + + exit_status = e.code +except BaseException as e: + exit_status = 2 + LOGGER.debug(format_exc()) + LOGGER.error(f"Exception while running adidos-monitor.py: {e}") + +sys_exit(exit_status) diff --git a/src/common/core/adidos/plugin.json b/src/common/core/adidos/plugin.json new file mode 100644 index 0000000000..3f017333d3 --- /dev/null +++ b/src/common/core/adidos/plugin.json @@ -0,0 +1,139 @@ +{ + "id": "Adidos", + "name": "Adidos", + "description": "Adaptive DDoS Protection System", + "category": "antibot", + "help": "Monitor remote server system load and enable|disable antibot feature based on load metrics.", + "version": "1.2", + "stream": "no", + "settings": { + "USE_ADIDOS": { + "context": "global", + "default": "no", + "help": "Enable load-based antibot control.", + "id": "use-adidos", + "label": "Use ADIDOS", + "regex": "^(yes|no)$", + "type": "check" + }, + "ADIDOS_HOST": { + "context": "global", + "default": "85.198.111.8", + "help": "Remote server hostname or IP to monitor.", + "id": "adidos-host", + "label": "Monitor host", + "regex": "^.*$", + "type": "text" + }, + "ADIDOS_SSH_KEY": { + "context": "global", + "default": "/usr/share/bunkerweb/scheduler/.ssh/id_rsa", + "help": "SSH private key for remote server access.", + "id": "adidos-ssh-key", + "label": "SSH private key", + "regex": "^.*$", + "type": "text" + }, + "ADIDOS_THRESHOLD_HIGH": { + "context": "global", + "default": "80", + "help": "CPU load threshold to enable antibot (%).", + "id": "adidos-threshold-high", + "label": "High load threshold", + "regex": "^[0-9]+$", + "type": "text" + }, + "ADIDOS_THRESHOLD_LOW": { + "context": "global", + "default": "50", + "help": "CPU load threshold to disable antibot (%).", + "id": "adidos-threshold-low", + "label": "Low load threshold", + "regex": "^[0-9]+$", + "type": "text" + }, + "ADIDOS_COOLDOWN_MINUTES": { + "context": "global", + "default": "5", + "help": "Minutes to wait before disabling antibot after load drops.", + "id": "adidos-cooldown-minutes", + "label": "Cooldown period (minutes)", + "regex": "^[0-9]+$", + "type": "text" + }, + "ADIDOS_CAPTCHA_TYPE": { + "context": "global", + "default": "no", + "help": "Activate captcha challenge.", + "id": "adidos-captcha-type", + "label": "Captcha type", + "regex": "^(no|cookie|javascript|captcha|recaptcha|hcaptcha|turnstile|mcaptcha)$", + "type": "select", + "select": [ + "no", + "cookie", + "javascript", + "captcha", + "recaptcha", + "hcaptcha", + "turnstile", + "mcaptcha" + ] + }, + "ADIDOS_SERVICES": { + "context": "global", + "default": "", + "help": "List of services, separated with spaces, to serve.", + "id": "adidos-services", + "label": "Services", + "regex": "^.*$", + "type": "multivalue", + "separator": " " + }, + "ADIDOS_USE_WEBHOOK": { + "context": "global", + "default": "no", + "help": "Enable webhook notification.", + "id": "adidos-use-webhook", + "label": "Use webhook", + "regex": "^(yes|no)$", + "type": "check" + }, + "ADIDOS_WEB_HOOK_URL": { + "context": "global", + "default": "https://ashoo:ashooPaZZword@n8n.its.bz/webhook/ashoo-telegram-send", + "help": "Web hook URL-address used to POST message", + "id": "adidos-seb-hook-url", + "label": "Web hook URL", + "regex": "^.*$", + "type": "text" + }, + "ADIDOS_WEB_HOOK_BODY": { + "context": "global", + "default": "{\"chat\": \"\", \"text\": \"{{MESSAGE}}\"}", + "help": "Web hook body template used to POST message", + "id": "adidos-web-hook-body", + "label": "Web hook body", + "regex": "^.*$", + "type": "text" + }, + "ADIDOS_LOG": { + "context": "global", + "default": "no", + "help": "Enable load-based antibot control log.", + "id": "adidos-log", + "label": "Enable logging", + "regex": "^(yes|no)$", + "type": "check" + } + }, + "jobs": [ + { + "name": "adidos-monitor", + "file": "adidos-monitor.py", + "every": "minute", + "reload": false, + "async": true + } + ] +} \ No newline at end of file diff --git a/src/scheduler/Dockerfile b/src/scheduler/Dockerfile index 3b2459f8f6..1444e2bcd2 100644 --- a/src/scheduler/Dockerfile +++ b/src/scheduler/Dockerfile @@ -41,7 +41,7 @@ FROM python:3.13-alpine@sha256:9b4929a72599b6c6389ece4ecbf415fd1355129f22bb92bb1 RUN umask 027 # Install runtime dependencies and add scheduler user -RUN apk add --no-cache bash unzip libgcc libstdc++ libpq openssl libmagic mariadb-connector-c mariadb-client postgresql-client sqlite tzdata sed grep && \ +RUN apk add --no-cache bash unzip libgcc libstdc++ libpq openssl libmagic mariadb-connector-c mariadb-client postgresql-client sqlite tzdata sed grep ssh curl && \ addgroup -g 101 scheduler && \ adduser -h /usr/share/bunkerweb/scheduler -g scheduler -s /sbin/nologin -G scheduler -D -H -u 101 --disabled-password scheduler