Compare commits

17 Commits

Author SHA1 Message Date
424ce59511 Merge branch 'wip-python' - Image and readme update 2025-05-31 22:05:39 +00:00
7ead6b4154 Image + readme update 2025-05-31 22:04:41 +00:00
77e2a9875f Merge pull request 'wip-python -> Python rewriting + better logs + backup + update at startup' (#3) from wip-python into main
Reviewed-on: #3
2025-05-31 23:22:30 +02:00
31865613cc Fixed bracket issues + readme with backup 2025-05-31 21:21:01 +00:00
a5f39c196e fix indentation in adguardhome.yaml 2025-05-31 21:05:36 +00:00
dea060b4d2 adguard restart 2025-05-31 21:00:12 +00:00
d97348cd17 Fixes missing requests + cross device error + cron folder error 2025-05-31 20:48:05 +00:00
17b80fa446 Added timezone and fixed entrypoint 2025-05-31 20:13:36 +00:00
5afe9c1601 First python commit 2025-05-31 19:46:12 +00:00
b55e462548 Merge branch 'main' of https://git.djeex.fr/Djeex/adguard-cidre 2025-05-31 17:48:09 +00:00
5471371401 Fixed readme 2025-05-31 17:46:16 +00:00
e1b43dc895 Merge pull request 'wip - v1 => It's working !!' (#1) from wip into main
Reviewed-on: #1
2025-05-31 19:44:48 +02:00
0da63e9cc0 fixed list issues with awk (too many arguments -> temp file) 2025-05-31 17:42:35 +00:00
02d891b6db fixed cidr list url 2025-05-31 17:30:37 +00:00
93d38900c8 Updated readme and container name 2025-05-31 17:12:11 +00:00
820020f23e Added adguard container name cariable and fixed docker socket proxy permissions to restart container 2025-05-31 17:10:33 +00:00
3d465082a5 Fixed cron issues with cronie 2025-05-31 17:02:27 +00:00
7 changed files with 316 additions and 83 deletions

View File

@ -1,10 +1,30 @@
FROM alpine:latest
FROM python:3.11-slim
RUN apk add --no-cache curl bash dcron tzdata
# Install required utilities
RUN apt-get update && apt-get install -y \
curl \
cron \
tzdata \
&& rm -rf /var/lib/apt/lists/*
COPY update-blocklist.sh /usr/local/bin/update-blocklist.sh
COPY entrypoint.sh /entrypoint.sh
# Install python dependencies
RUN pip install --no-cache-dir requests
RUN chmod +x /usr/local/bin/update-blocklist.sh /entrypoint.sh
# Create crontabs directory (if needed)
RUN mkdir -p /etc/crontabs
ENTRYPOINT ["/entrypoint.sh"]
# Copy scripts
COPY update-blocklist.py /usr/local/bin/update-blocklist.py
COPY entrypoint.py /usr/local/bin/entrypoint.py
# Make scripts executable
RUN chmod +x /usr/local/bin/update-blocklist.py /usr/local/bin/entrypoint.py
# Set default timezone (can be overridden with TZ env var)
ENV TZ=UTC
# Configure timezone (tzdata)
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Set entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint.py"]

View File

@ -23,6 +23,7 @@
- Updates the disallowed_clients section in the AdGuard Home config.
- Configurable update frequency via cron expression environment variable.
- Automatically restarts the AdGuard Home container after updates via Docker socket proxy.
- Backup `AdguardHome.yaml` at first startup, then create a second backup at each update.
## Environment Variables
@ -31,7 +32,9 @@
| `TZ` | Your Time Zone | (required) |
| `BLOCK_COUNTRIES` | Comma-separated country codes to block (e.g., `CN,RU,IR`) | (required) |
| `BLOCKLIST_CRON` | Cron expression for update frequency (e.g., `0 6 * * *`) | `0 6 * * *` (at 6:00 everydays) |
| `DOCKER_API_URL` | URL of Docker socket proxy to restart AdGuard container | `tcp://socket-proxy-adguard:2375` |
| `DOCKER_API_URL` | URL of Docker socket proxy to restart AdGuard container | `http://socket-proxy-adguard:2375` |
| `ADGUARD_CONTAINER_NAME` | Name of your adguard container | `adguardhome` |
## File Structure
@ -43,6 +46,66 @@
## Installation and Usage
### With our docker image
1. **Create `docker-compose.yml` in your `adguard-cidre` folder**
```yaml
---
services:
adguard-cidre:
image: git.djeex.fr/djeex/adguard-cidre:latest
container_name: adguard-cidre
restart: unless-stopped
environment:
- TZ=Europe/Paris # change to your timezone
- BLOCK_COUNTRIES=cn,ru # choose countries listed IP to block. Full lists here https://github.com/vulnebify/cidre/tree/main/output/cidr/ipv4
- BLOCKLIST_CRON=0 6 * * * # at 6:00 every days
- DOCKER_API_URL=http://socket-proxy-adguard:2375 # docker socket proxy
- ADGUARD_CONTAINER_NAME=adguardhome # adguard container name
volumes:
- /path/to/adguard/confdir:/adguard
socket-proxy:
image: lscr.io/linuxserver/socket-proxy:latest
container_name: socket-proxy-adguard
security_opt:
- no-new-privileges:true
environment:
- CONTAINERS=1
- ALLOW_RESTARTS=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
read_only: true
tmpfs:
- /run
```
2. **Modify docker-compose.yml**
- Set `BLOCK_COUNTRIES` environment variable with the countries you want to block.
- Adjust `BLOCKLIST_CRON` if you want a different update frequency.
- Bind mount your adguard configuration folder (wich contains `AdGuardHome.yaml`) to `/adguard`
- (optionnally) create and edit `manually_blocked_ips.conf` file in your adguard configuration folder to add other IPs you want to block. Only valid IP or CIDR entries will be processed, for exemple :
```bash
192.168.1.100
10.0.0.0/24
# Comments or empty lines are ignored
```
3. **Start the container**
```bash
docker compose up -d
```
4. **Check logs to verify updates**
```bash
docker compose logs -f
```
### With git (developer)
1. **Clone the repository:**
```bash
@ -62,15 +125,15 @@
# Comments or empty lines are ignored
```
4. **Build and start the container**
3. **Build and start the container**
```bash
docker-compose build
docker-compose up -d
docker compose build
docker compose up -d
```
5. **Check logs to verify updates**
4. **Check logs to verify updates**
```bash
docker-compose logs -f
docker compose logs -f
```

View File

@ -2,11 +2,14 @@
services:
adguard-cidre:
build: .
container_name: adguard-cidre
restart: unless-stopped
environment:
- TZ=Europe/Paris # change to your timezone
- BLOCK_COUNTRIES=CN,RU,IR # choose countries listed IP to block. Full lists here https://github.com/vulnebify/cidre/tree/main/output/cidr/ipv4
- BLOCK_COUNTRIES=cn,ru # choose countries listed IP to block. Full lists here https://github.com/vulnebify/cidre/tree/main/output/cidr/ipv4
- BLOCKLIST_CRON=0 6 * * * # at 6:00 every days
- DOCKER_API_URL=tcp://socket-proxy-adguard:2375
- DOCKER_API_URL=http://socket-proxy-adguard:2375 # docker socket proxy
- ADGUARD_CONTAINER_NAME=adguardhome # adguard container name
volumes:
- /path/to/adguard/confdir:/adguard
@ -17,6 +20,7 @@ services:
- no-new-privileges:true
environment:
- CONTAINERS=1
- ALLOW_RESTARTS=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped

67
entrypoint.py Normal file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
import logging
from pathlib import Path
logging.basicConfig(
level=logging.INFO,
format='[entrypoint] %(message)s',
stream=sys.stdout
)
ADGUARD_YAML = Path("/adguard/AdGuardHome.yaml")
FIRST_BACKUP = Path("/adguard/AdGuardHome.yaml.first-start.bak")
def setup_cron():
cron_expr = os.getenv("BLOCKLIST_CRON", "0 6 * * *")
cron_line = f"{cron_expr} root /usr/local/bin/update-blocklist.py\n"
cron_dir = "/etc/crontabs"
cron_file = f"{cron_dir}/root"
logging.info(f"Setting cron job: {cron_line.strip()}")
# Ensure cron directory exists
os.makedirs(cron_dir, exist_ok=True)
with open(cron_file, "w") as f:
f.write(cron_line)
def backup_first_start():
if not FIRST_BACKUP.exists():
logging.info("Creating first start backup...")
FIRST_BACKUP.write_text(ADGUARD_YAML.read_text())
else:
logging.info("First start backup already exists.")
def run_initial_update():
logging.info("Running initial update-blocklist.py script...")
try:
subprocess.run(
["/usr/local/bin/update-blocklist.py"],
check=True,
stdout=sys.stdout,
stderr=sys.stderr,
)
except subprocess.CalledProcessError as e:
logging.error(f"Initial update script failed: {e}")
sys.exit(1)
def start_cron_foreground():
logging.info("Starting cron in foreground...")
os.execvp("cron", ["cron", "-f"])
def main():
# Check AdGuardHome.yaml exists
if not ADGUARD_YAML.exists():
logging.error(f"{ADGUARD_YAML} not found. Exiting.")
sys.exit(1)
backup_first_start()
run_initial_update()
setup_cron()
start_cron_foreground()
if __name__ == "__main__":
main()

View File

@ -1,22 +0,0 @@
#!/bin/sh
set -e
if [ -n "$TZ" ]; then
if [ -f "/usr/share/zoneinfo/$TZ" ]; then
cp "/usr/share/zoneinfo/$TZ" /etc/localtime
echo "$TZ" > /etc/timezone
else
echo "Warning: Timezone file /usr/share/zoneinfo/$TZ not found, skipping timezone setup."
fi
fi
CRON_EXPR="${BLOCKLIST_CRON:-"0 6 * * *"}" # default: every day at 6:00 am
SCRIPT_PATH="/usr/local/bin/update-blocklist.sh"
echo "Installing cron job with expression: $CRON_EXPR"
echo "$CRON_EXPR root $SCRIPT_PATH" > /etc/crontabs/root
echo "Starting cron..."
exec crond -f -L /dev/stdout

148
update-blocklist.py Normal file
View File

@ -0,0 +1,148 @@
#!/usr/bin/env python3
import os
import sys
import logging
import requests
from pathlib import Path
logging.basicConfig(
level=logging.INFO,
format='[update-blocklist] %(levelname)s: %(message)s',
stream=sys.stdout,
)
ADGUARD_YAML = Path("/adguard/AdGuardHome.yaml")
FIRST_BACKUP = Path("/adguard/AdGuardHome.yaml.first-start.bak")
LAST_CRON_BACKUP = Path("/adguard/AdGuardHome.yaml.last-cron.bak")
TMP_YAML = ADGUARD_YAML.parent / (ADGUARD_YAML.name + ".tmp")
MANUAL_IPS_FILE = Path("/adguard/manually_blocked_ips.conf")
CIDR_BASE_URL = "https://raw.githubusercontent.com/vulnebify/cidre/main/output/cidr/ipv4"
COUNTRIES = os.getenv("BLOCK_COUNTRIES", "")
def backup_files():
if not FIRST_BACKUP.exists():
logging.info(f"Creating first-start backup: {FIRST_BACKUP}")
FIRST_BACKUP.write_text(ADGUARD_YAML.read_text())
else:
logging.info("First-start backup already exists, skipping.")
logging.info(f"Creating last-cron backup: {LAST_CRON_BACKUP}")
LAST_CRON_BACKUP.write_text(ADGUARD_YAML.read_text())
def download_cidr_lists(countries):
combined_ips = []
for code in countries:
url = f"{CIDR_BASE_URL}/{code.lower()}.cidr"
logging.info(f"Downloading CIDR list for {code} from {url}")
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
ips = r.text.strip().splitlines()
logging.info(f"Downloaded {len(ips)} CIDR entries for {code}")
combined_ips.extend(ips)
except Exception as e:
logging.warning(f"Failed to download {code}: {e}")
return combined_ips
def read_manual_ips():
if MANUAL_IPS_FILE.exists():
logging.info(f"Reading manual IPs from {MANUAL_IPS_FILE}")
valid_ips = []
with MANUAL_IPS_FILE.open() as f:
for line in f:
line = line.strip()
# Simple check for IPv4 or IPv4 CIDR format
if line and line.count('.') == 3:
valid_ips.append(line)
logging.info(f"Added {len(valid_ips)} manual IP entries")
return valid_ips
else:
logging.info("Manual IPs file does not exist, skipping.")
return []
def update_yaml_with_ips(ips):
output_lines = []
inside_disallowed = False
disallowed_indent = ""
with ADGUARD_YAML.open() as f:
lines = f.readlines()
for line in lines:
stripped = line.lstrip()
indent = line[:len(line) - len(stripped)]
if stripped.startswith("disallowed_clients:"):
# Capture the indentation of the disallowed_clients key
disallowed_indent = indent
# Replace entire line with just 'disallowed_clients:' (remove any [])
output_lines.append(f"{disallowed_indent}disallowed_clients:")
# Add all IPs indented 2 spaces more than disallowed_clients
formatted_ips = [f"{disallowed_indent} - {ip}" for ip in ips]
output_lines.extend(formatted_ips)
inside_disallowed = True
continue
if inside_disallowed:
# We skip all old lines inside disallowed_clients block.
# The block ends when we find a line with indentation
# less than or equal to disallowed_indent but not the key line itself.
# To detect end of block, compare indent length:
if len(indent) <= len(disallowed_indent) and stripped != "":
inside_disallowed = False
output_lines.append(line.rstrip("\n"))
else:
# skip this line (old disallowed_clients content)
continue
else:
output_lines.append(line.rstrip("\n"))
# Write temp file in same directory to avoid cross-device rename errors
with TMP_YAML.open("w") as f:
f.write("\n".join(output_lines) + "\n")
TMP_YAML.replace(ADGUARD_YAML)
logging.info(f"Updated {ADGUARD_YAML} with new disallowed clients list.")
def restart_adguard_container():
docker_api_url = os.getenv("DOCKER_API_URL", "http://socket-proxy-adguard:2375")
container_name = os.getenv("ADGUARD_CONTAINER_NAME", "adguardhome")
restart_url = f"{docker_api_url}/containers/{container_name}/restart"
logging.info(f"Restarting AdGuard container '{container_name}'...")
try:
resp = requests.post(restart_url, timeout=10)
if resp.status_code == 204:
logging.info("AdGuard container restarted successfully.")
else:
logging.error(f"Failed to restart container: {resp.status_code} {resp.text}")
except Exception as e:
logging.error(f"Error restarting container: {e}")
def main():
if not ADGUARD_YAML.exists():
logging.error(f"{ADGUARD_YAML} not found, exiting.")
sys.exit(1)
if not COUNTRIES:
logging.error("No countries specified in BLOCK_COUNTRIES environment variable, exiting.")
sys.exit(1)
backup_files()
countries_list = [c.strip() for c in COUNTRIES.split(",") if c.strip()]
cidr_ips = download_cidr_lists(countries_list)
manual_ips = read_manual_ips()
combined_ips = cidr_ips + manual_ips
update_yaml_with_ips(combined_ips)
restart_adguard_container()
if __name__ == "__main__":
main()

View File

@ -1,47 +0,0 @@
#!/bin/bash
set -e
ADGUARD_YAML="/adguard/AdGuardHome.yaml"
TMP_YAML="/tmp/AdGuardHome.yaml"
MANUAL_IPS_FILE="/adguard/manually_blocked_ips.conf"
CIDR_BASE_URL="https://raw.githubusercontent.com/vulnebify/cidre/main/output/cidr/ipv4"
COUNTRIES=${BLOCK_COUNTRIES:-""}
DOCKER_API_URL=${DOCKER_API_URL:-"tcp://socket-proxy-adguard:2375"}
if [ -z "$COUNTRIES" ]; then
echo "No countries specified in BLOCK_COUNTRIES."
exit 1
fi
mkdir -p /tmp/cidr
> /tmp/cidr/all.txt
IFS=',' read -ra CODES <<< "$COUNTRIES"
for CODE in "${CODES[@]}"; do
echo "Downloading CIDR list for $CODE..."
curl -sf "$CIDR_BASE_URL/${CODE^^}.txt" -o "/tmp/cidr/${CODE}.txt" || continue
cat "/tmp/cidr/${CODE}.txt" >> /tmp/cidr/all.txt
done
if [ -f "$MANUAL_IPS_FILE" ]; then
echo "Validating and adding manually blocked IPs from $MANUAL_IPS_FILE..."
grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?$' "$MANUAL_IPS_FILE" >> /tmp/cidr/all.txt
fi
IPS_FORMATTED=$(sed 's/^/ - /' /tmp/cidr/all.txt)
awk -v ips="$IPS_FORMATTED" '
BEGIN { inside=0 }
/^ disallowed_clients:/ { print; inside=1; next }
/^ [^ ]/ && inside==1 { print ips; inside=0 }
{ if (!inside) print }
END { if (inside==1) print ips }
' "$ADGUARD_YAML" > "$TMP_YAML"
mv "$TMP_YAML" "$ADGUARD_YAML"
echo "Restarting adguard-home container..."
curl -s -X POST "$DOCKER_API_URL/containers/adguard-home/restart" -o /dev/null
echo "Done."