Run container as non-root via PUID/PGID / Move environment configuration to a .env file #14
+4
-3
@@ -2,7 +2,7 @@ FROM python:3.14.7-alpine AS base
|
||||
|
||||
ENV TZ=Europe/Paris
|
||||
|
||||
RUN apk add --no-cache tzdata curl \
|
||||
RUN apk add --no-cache tzdata curl su-exec \
|
||||
&& cp /usr/share/zoneinfo/$TZ /etc/localtime \
|
||||
&& echo $TZ > /etc/timezone
|
||||
|
||||
@@ -11,7 +11,8 @@ WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY blocklist_scheduler.py .
|
||||
COPY blocklist_scheduler.py entrypoint.sh VERSION ./
|
||||
RUN chmod +x entrypoint.sh
|
||||
|
||||
FROM base AS test
|
||||
RUN pip install --no-cache-dir pytest==9.1.1
|
||||
@@ -19,4 +20,4 @@ COPY tests/ tests/
|
||||
COPY pytest.ini .
|
||||
|
||||
FROM base
|
||||
ENTRYPOINT ["python3", "blocklist_scheduler.py"]
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
| Variable | Description | Example | Possible Values |
|
||||
|--------------------------|--------------------------------------------------------------------------|-----------------------------|---------------------------------------------|
|
||||
| `PUID` | User ID the process runs as (drops root at startup) | `1000` | Any valid numeric UID |
|
||||
| `PGID` | Group ID the process runs as | `1000` | Any valid numeric GID |
|
||||
| `TZ` | Timezone of the container to correctly schedule updates | `Europe/Paris` | Any valid timezone (e.g., `UTC`, `America/New_York`, etc.) |
|
||||
| `BLOCK_COUNTRIES` | List of country codes for CIDR lists, separated by commas. You can also define an exclude list (all countries except the specified ones) by prefixing each country code with !. Mixing inclusion and exclusion codes is not supported. | including list : `cn,ru,ir`, excluding list : `!cn,!ru,!ir` | ISO 2-letter country codes |
|
||||
| `BLOCKLIST_CRON_TYPE` | Scheduling type: `daily` or `weekly` | `daily` | `daily`, `weekly` |
|
||||
@@ -64,6 +66,8 @@
|
||||
container_name: adguard-cidre
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000 # user id the process runs as, matches ownership of the /adguard mount
|
||||
- PGID=1000 # group id the process runs as
|
||||
- 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_TYPE=daily # daily or weekly
|
||||
|
||||
@@ -11,7 +11,7 @@ from pathlib import Path
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='[blocklist] %(levelname)s: %(message)s',
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
stream=sys.stdout,
|
||||
)
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ services:
|
||||
container_name: adguard-cidre
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000 # user id the process runs as, matches ownership of the /adguard mount
|
||||
- PGID=1000 # group id the process runs as
|
||||
- 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_TYPE=daily # daily or weekly
|
||||
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
CYAN="\033[1;36m"
|
||||
NC="\033[0m"
|
||||
|
||||
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*"; }
|
||||
fail() { echo "$(date '+%Y-%m-%d %H:%M:%S') [!] $*" >&2; exit 1; }
|
||||
|
||||
print_banner() {
|
||||
version=$(cat VERSION 2>/dev/null || echo "unknown")
|
||||
title="AdGuard CIDRe - Version ${version}"
|
||||
lines="Source: https://git.djeex.fr/Djeex/adguard-cidre
|
||||
Mirror: https://github.com/Djeex/adguard-cidre"
|
||||
|
||||
width=${#title}
|
||||
old_ifs=$IFS
|
||||
IFS='
|
||||
'
|
||||
for l in $lines; do
|
||||
[ ${#l} -gt "$width" ] && width=${#l}
|
||||
done
|
||||
IFS=$old_ifs
|
||||
width=$((width + 2))
|
||||
|
||||
border=""
|
||||
i=0
|
||||
while [ "$i" -lt "$width" ]; do
|
||||
border="${border}─"
|
||||
i=$((i + 1))
|
||||
done
|
||||
printf "${CYAN}╭%s╮${NC}\n" "$border"
|
||||
|
||||
total_pad=$((width - ${#title}))
|
||||
left=$((total_pad / 2))
|
||||
right=$((total_pad - left))
|
||||
printf "${CYAN}│${NC}%*s%s%*s${CYAN}│${NC}\n" "$left" "" "$title" "$right" ""
|
||||
|
||||
printf "${CYAN}├%s┤${NC}\n" "$border"
|
||||
|
||||
IFS='
|
||||
'
|
||||
for l in $lines; do
|
||||
printf "${CYAN}│${NC} %-*s${CYAN}│${NC}\n" "$((width - 1))" "$l"
|
||||
done
|
||||
IFS=$old_ifs
|
||||
|
||||
printf "${CYAN}╰%s╯${NC}\n" "$border"
|
||||
}
|
||||
|
||||
print_banner
|
||||
|
||||
PUID=${PUID:-911}
|
||||
PGID=${PGID:-911}
|
||||
|
||||
case "$PGID" in
|
||||
''|*[!0-9]*) fail "PGID '$PGID' is not a valid numeric group id." ;;
|
||||
esac
|
||||
case "$PUID" in
|
||||
''|*[!0-9]*) fail "PUID '$PUID' is not a valid numeric user id." ;;
|
||||
esac
|
||||
|
||||
[ -d /adguard ] || fail "/adguard is not mounted — check the volume mapping in docker-compose.yml."
|
||||
|
||||
log "[i] Requested PUID=$PUID, PGID=$PGID"
|
||||
|
||||
log "[~] Checking group for GID $PGID..."
|
||||
GROUP_NAME=$(getent group "$PGID" | cut -d: -f1 || true)
|
||||
if [ -z "$GROUP_NAME" ]; then
|
||||
log "[→] No existing group with GID $PGID, creating 'appgroup'."
|
||||
addgroup -g "$PGID" appgroup || fail "Failed to create group with GID $PGID (addgroup exited $?)."
|
||||
GROUP_NAME=appgroup
|
||||
else
|
||||
log "[i] Reusing existing group '$GROUP_NAME' (GID $PGID)."
|
||||
fi
|
||||
log "[✓] Group ready: $GROUP_NAME"
|
||||
|
||||
log "[~] Checking user for UID $PUID..."
|
||||
USER_NAME=$(getent passwd "$PUID" | cut -d: -f1 || true)
|
||||
if [ -z "$USER_NAME" ]; then
|
||||
log "[→] No existing user with UID $PUID, creating 'appuser'."
|
||||
adduser -D -u "$PUID" -G "$GROUP_NAME" appuser || fail "Failed to create user with UID $PUID (adduser exited $?)."
|
||||
USER_NAME=appuser
|
||||
else
|
||||
log "[i] Reusing existing user '$USER_NAME' (UID $PUID)."
|
||||
fi
|
||||
log "[✓] User ready: $USER_NAME"
|
||||
|
||||
# Grant write access to the shared AdGuard config directory and to the files
|
||||
# this script manages, without touching anything else AdGuardHome owns in
|
||||
# there (its own db/certs/stats). AdGuardHome itself runs as root, so this is
|
||||
# a one-way grant: it keeps full access regardless of what we chown here.
|
||||
log "[~] Setting ownership of /adguard to $USER_NAME:$GROUP_NAME..."
|
||||
chown "$USER_NAME:$GROUP_NAME" /adguard || fail "chown on /adguard failed — check that the host directory permissions allow it."
|
||||
log "[✓] Ownership set on /adguard"
|
||||
|
||||
for f in AdGuardHome.yaml AdGuardHome.yaml.first-start.bak AdGuardHome.yaml.last-update.bak AdGuardHome.yaml.tmp; do
|
||||
if [ -e "/adguard/$f" ]; then
|
||||
chown "$USER_NAME:$GROUP_NAME" "/adguard/$f" || fail "chown on /adguard/$f failed."
|
||||
log "[✓] chown OK: /adguard/$f"
|
||||
fi
|
||||
done
|
||||
|
||||
log "[→] Dropping privileges to $USER_NAME:$GROUP_NAME and starting blocklist_scheduler.py"
|
||||
exec su-exec "$USER_NAME:$GROUP_NAME" python3 blocklist_scheduler.py "$@"
|
||||
Reference in New Issue
Block a user