feat(adguard): añadir sincronización automática de certificados
- adguard-cert-sync.service / .timer: unidades systemd para renovar automáticamente el certificado TLS de AdGuard cuando Traefik lo renueva - sync-adguard-cert.sh: script que copia cert desde /opt/traefik/certs y reinicia AdGuard vía API - docker-compose.yml y stack.env: ajustes menores - README.md: documentación actualizada con instrucciones de instalación Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+5
-5
@@ -56,12 +56,12 @@ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|||||||
- Repository URL: `<tu-repositorio>`
|
- Repository URL: `<tu-repositorio>`
|
||||||
- Repository reference: `main`
|
- Repository reference: `main`
|
||||||
- Compose path: `adguard/docker-compose.yml`
|
- Compose path: `adguard/docker-compose.yml`
|
||||||
5. Carga el archivo de variables de entorno: `adguard/stack.env`
|
5. Copia `adguard/stack.env` a `adguard/.env` y carga `adguard/.env` como archivo de variables de entorno
|
||||||
6. Haz clic en **Deploy the stack**
|
6. Haz clic en **Deploy the stack**
|
||||||
|
|
||||||
### Variables de Entorno
|
### Variables de Entorno
|
||||||
|
|
||||||
Edita el archivo `stack.env`:
|
Edita el archivo `.env`:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
# Imagen
|
# Imagen
|
||||||
@@ -103,7 +103,7 @@ La primera vez que accedas a `https://adguard.tudominio.com`, se iniciará el as
|
|||||||
3. **Interfaces de red**: Escucha en todas las interfaces
|
3. **Interfaces de red**: Escucha en todas las interfaces
|
||||||
4. **DNS upstream**: Configura servidores DNS (ej: `1.1.1.1`, `8.8.8.8`)
|
4. **DNS upstream**: Configura servidores DNS (ej: `1.1.1.1`, `8.8.8.8`)
|
||||||
|
|
||||||
> **Nota**: Si el panel escucha en puerto 3000, actualiza `ADGUARD_HTTP_PORT=3000` en el `stack.env` temporalmente.
|
> **Nota**: Si el panel escucha en puerto 3000, actualiza `ADGUARD_HTTP_PORT=3000` en el `.env` temporalmente.
|
||||||
|
|
||||||
### 2. Configurar DNS-over-TLS (DoT)
|
### 2. Configurar DNS-over-TLS (DoT)
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ Para aplicar configuraciones diferentes por cliente:
|
|||||||
Si la IP configurada está en uso:
|
Si la IP configurada está en uso:
|
||||||
|
|
||||||
1. Elige otra IP del rango de la red `proxy`
|
1. Elige otra IP del rango de la red `proxy`
|
||||||
2. Actualiza `ADGUARD_IPV4` en `stack.env`
|
2. Actualiza `ADGUARD_IPV4` en `.env`
|
||||||
3. Actualiza el stack
|
3. Actualiza el stack
|
||||||
|
|
||||||
## 📚 Recursos Adicionales
|
## 📚 Recursos Adicionales
|
||||||
@@ -348,7 +348,7 @@ sudo tar -xzf adguard-backup-YYYYMMDD.tar.gz -C /
|
|||||||
## 🔄 Actualizaciones
|
## 🔄 Actualizaciones
|
||||||
|
|
||||||
1. Haz backup de la configuración
|
1. Haz backup de la configuración
|
||||||
2. Actualiza en `stack.env`:
|
2. Actualiza en `.env`:
|
||||||
```env
|
```env
|
||||||
ADGUARD_IMAGE=adguard/adguardhome:latest
|
ADGUARD_IMAGE=adguard/adguardhome:latest
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Sync AdGuard SSL certificate from Traefik acme.json
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/opt/adguard/sync-cert.sh
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Sync AdGuard SSL certificate from Traefik
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 04:00:00
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
@@ -6,10 +6,10 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- /opt/adguard/work:/opt/adguardhome/work:Z
|
- ${ADGUARD_WORK_PATH}:/opt/adguardhome/work:Z
|
||||||
- /opt/adguard/conf:/opt/adguardhome/conf:Z
|
- ${ADGUARD_CONF_PATH}:/opt/adguardhome/conf:Z
|
||||||
- adguard-cert-crt-path:/certs/adguard.crt:ro,Z
|
- ${ADGUARD_CERT_CRT_PATH}:/certs/adguard.crt:ro,Z
|
||||||
- adguard-cert-key-path:/certs/adguard.key:ro,Z
|
- ${ADGUARD_CERT_KEY_PATH}:/certs/adguard.key:ro,Z
|
||||||
|
|
||||||
# Solo DNS/DoT expuestos en el host
|
# Solo DNS/DoT expuestos en el host
|
||||||
ports:
|
ports:
|
||||||
@@ -23,11 +23,13 @@ services:
|
|||||||
ipv4_address: ${ADGUARD_IPV4}
|
ipv4_address: ${ADGUARD_IPV4}
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
traefik.http.services.adguard.loadbalancer.server.port: "80"
|
traefik.enable: "true"
|
||||||
|
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
|
||||||
volumes:
|
traefik.http.routers.adguard.rule: "Host(`${ADGUARD_DOMAIN}`)"
|
||||||
adguard-cert-crt-path:
|
traefik.http.routers.adguard.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
||||||
adguard-cert-key-path:
|
traefik.http.routers.adguard.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
|
||||||
|
traefik.http.routers.adguard.middlewares: "crowdsec-bouncer@file,${TRAEFIK_AUTH_MIDDLEWARE}"
|
||||||
|
traefik.http.services.adguard.loadbalancer.server.port: "${ADGUARD_HTTP_PORT}"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
|
|||||||
+14
-13
@@ -1,17 +1,18 @@
|
|||||||
##### AdGuard #####
|
##### AdGuard #####
|
||||||
ADGUARD_IMAGE=
|
ADGUARD_IMAGE=adguard/adguardhome
|
||||||
ADGUARD_WORK_PATH=
|
ADGUARD_WORK_PATH=/opt/adguard/work
|
||||||
ADGUARD_CONF_PATH=
|
ADGUARD_CONF_PATH=/opt/adguard/conf
|
||||||
ADGUARD_CERT_CRT_PATH=
|
ADGUARD_CERT_CRT_PATH=/opt/traefik/certs/adguard.crt
|
||||||
ADGUARD_CERT_KEY_PATH=
|
ADGUARD_CERT_KEY_PATH=/opt/traefik/certs/adguard.key
|
||||||
ADGUARD_DOT_PORT=
|
ADGUARD_DOT_PORT=853
|
||||||
ADGUARD_IPV4=
|
ADGUARD_IPV4=198.51.100.10
|
||||||
ADGUARD_HTTP_PORT=80
|
ADGUARD_HTTP_PORT=80
|
||||||
|
|
||||||
##### Traefik / red #####
|
##### Traefik / red #####
|
||||||
TRAEFIK_DOCKER_NETWORK=
|
TRAEFIK_DOCKER_NETWORK=proxy
|
||||||
ADGUARD_DOMAIN=
|
ADGUARD_DOMAIN=app.example.com
|
||||||
TRAEFIK_ENTRYPOINT_SECURE=
|
TRAEFIK_ENTRYPOINT_SECURE=websecure
|
||||||
TRAEFIK_CERTRESOLVER=
|
TRAEFIK_CERTRESOLVER=letsencrypt
|
||||||
TRAEFIK_AUTH_MIDDLEWARE=
|
TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker
|
||||||
|
SERVICE_URL_ADGUARDHOME=https://app.example.com
|
||||||
|
SERVICE_FQDN_ADGUARDHOME=app.example.com
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Extrae el certificado de adblock.sherlockhomeless.net desde Traefik
|
||||||
|
# y lo inyecta en la configuración de AdGuard Home, reiniciando el contenedor.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ACME_JSON="/opt/traefik/letsencrypt/acme.json"
|
||||||
|
ADGUARD_CONFIG="/opt/adguard/conf/AdGuardHome.yaml"
|
||||||
|
DOMAIN="adblock.sherlockhomeless.net"
|
||||||
|
CERT_FILE="/opt/traefik/certs/adguard.crt"
|
||||||
|
KEY_FILE="/opt/traefik/certs/adguard.key"
|
||||||
|
|
||||||
|
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
||||||
|
|
||||||
|
# 1. Extraer cert y key del acme.json de Traefik
|
||||||
|
log "Extrayendo certificado para $DOMAIN..."
|
||||||
|
python3 << PYEOF
|
||||||
|
import json, base64, sys
|
||||||
|
|
||||||
|
with open("$ACME_JSON") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
found = False
|
||||||
|
for resolver, rdata in data.items():
|
||||||
|
for cert in rdata.get("Certificates", []):
|
||||||
|
if cert.get("domain", {}).get("main") == "$DOMAIN":
|
||||||
|
with open("$CERT_FILE", "w") as f:
|
||||||
|
f.write(base64.b64decode(cert["certificate"]).decode())
|
||||||
|
with open("$KEY_FILE", "w") as f:
|
||||||
|
f.write(base64.b64decode(cert["key"]).decode())
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
print("ERROR: certificado para $DOMAIN no encontrado en acme.json", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
print("OK: certificado extraído")
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
# 2. Comprobar si el cert en AdGuard ya es el mismo (evitar restart innecesario)
|
||||||
|
CURRENT_FINGERPRINT=$(openssl x509 -in "$CERT_FILE" -noout -fingerprint -sha256 2>/dev/null | cut -d= -f2)
|
||||||
|
ADGUARD_CERT=$(python3 -c "
|
||||||
|
import re
|
||||||
|
with open('$ADGUARD_CONFIG') as f:
|
||||||
|
content = f.read()
|
||||||
|
m = re.search(r'certificate_chain: \|-\n((?: .+\n)+)', content)
|
||||||
|
if m:
|
||||||
|
print(m.group(1).replace(' ', ''))
|
||||||
|
" 2>/dev/null)
|
||||||
|
ADGUARD_FINGERPRINT=$(echo "$ADGUARD_CERT" | openssl x509 -noout -fingerprint -sha256 2>/dev/null | cut -d= -f2)
|
||||||
|
|
||||||
|
if [ "$CURRENT_FINGERPRINT" = "$ADGUARD_FINGERPRINT" ]; then
|
||||||
|
log "El certificado de AdGuard ya está actualizado. Nada que hacer."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Certificado nuevo detectado. Actualizando AdGuardHome.yaml..."
|
||||||
|
|
||||||
|
# 3. Inyectar cert y key en el YAML de AdGuard
|
||||||
|
python3 << PYEOF
|
||||||
|
import re
|
||||||
|
|
||||||
|
with open("$CERT_FILE") as f:
|
||||||
|
new_cert = f.read().strip()
|
||||||
|
with open("$KEY_FILE") as f:
|
||||||
|
new_key = f.read().strip()
|
||||||
|
|
||||||
|
def indent(text, spaces=4):
|
||||||
|
return "\n".join(" " * spaces + line for line in text.splitlines())
|
||||||
|
|
||||||
|
with open("$ADGUARD_CONFIG") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
content = re.sub(
|
||||||
|
r'(tls:.*?server_name:\s*)\S+',
|
||||||
|
r'\g<1>$DOMAIN',
|
||||||
|
content, flags=re.DOTALL
|
||||||
|
)
|
||||||
|
content = re.sub(
|
||||||
|
r' certificate_chain: \|-\n(?: .*\n)+',
|
||||||
|
f" certificate_chain: |-\n{indent(new_cert)}\n",
|
||||||
|
content
|
||||||
|
)
|
||||||
|
content = re.sub(
|
||||||
|
r' private_key: \|-\n(?: .*\n)+',
|
||||||
|
f" private_key: |-\n{indent(new_key)}\n",
|
||||||
|
content
|
||||||
|
)
|
||||||
|
|
||||||
|
with open("$ADGUARD_CONFIG", "w") as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print("OK: config actualizado")
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
# 4. Reiniciar AdGuard
|
||||||
|
log "Reiniciando AdGuard Home..."
|
||||||
|
docker restart adguardhome
|
||||||
|
log "Sync completado."
|
||||||
Reference in New Issue
Block a user