APmanageur Wi-Fi V1.0 : conteneur Debian + Apache

This commit is contained in:
yoann committed 2026-10-05 01:18:55 +02:00
1 parent c705504e5d
commit 2d3f8d8b3c
5 files changed
+64 -45

No files matched your search

+5 -2
View File
@@ -20,16 +20,19 @@ COPY ap.py /app/ap.py
ARG HTML_FILE=index.html ARG HTML_FILE=index.html
COPY ${HTML_FILE} /app/index.html COPY ${HTML_FILE} /app/index.html
COPY ${HTML_FILE} /var/www/html/index.html COPY ${HTML_FILE} /var/www/html/index.html
# L'API n'est plus joignable que via Apache : le HTML appelle /api sur le même port (1001)
RUN sed -i 's#const API_URL=[^;]*;#const API_URL="";#' /app/index.html /var/www/html/index.html
COPY apache-ap.conf /etc/apache2/sites-available/000-default.conf COPY apache-ap.conf /etc/apache2/sites-available/000-default.conf
COPY entrypoint.sh /entrypoint.sh COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh && rm -f /var/www/html/index.html.orig \ RUN chmod +x /entrypoint.sh && rm -f /var/www/html/index.html.orig \
&& sed -i 's/^Listen 80$/Listen 1001/; s/^\s*Listen 443$/ Listen 1443/' /etc/apache2/ports.conf && sed -i 's/^Listen 80$/Listen ${AP_WEB_PORT}/; s/^\s*Listen 443$/ Listen 1443/' /etc/apache2/ports.conf
ENV AP_DB_FILE=/data/ap-dashboard.sqlite3 \ ENV AP_DB_FILE=/data/ap-dashboard.sqlite3 \
AP_CONNECTION_FILE=/data/connection \ AP_CONNECTION_FILE=/data/connection \
AP_UPTIME_FILE=/data/uptime AP_UPTIME_FILE=/data/uptime
VOLUME ["/data", "/etc/NetworkManager/system-connections", "/var/lib/NetworkManager"] VOLUME ["/data", "/etc/NetworkManager/system-connections", "/var/lib/NetworkManager"]
EXPOSE 1001 8080 ENV AP_WEB_PORT=1001
EXPOSE 1001
ENTRYPOINT ["/entrypoint.sh"] ENTRYPOINT ["/entrypoint.sh"]
+17 -3
View File
@@ -1,9 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import base64, hashlib, hmac, json, os, re, secrets, socket, sqlite3, subprocess, threading, time, urllib.parse import base64, hashlib, hmac, json, os, re, secrets, socket, sqlite3, subprocess, threading, time, urllib.parse, socketserver, shutil
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
INTERFACE = os.environ.get('AP_INTERFACE', 'wls16b1') INTERFACE = os.environ.get('AP_INTERFACE', 'wls16b1')
HOST, PORT = '0.0.0.0', 8080 SOCKET_PATH = os.environ.get('AP_SOCKET', '/run/ap-api.sock')
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_FILE = os.environ.get('AP_DB_FILE', os.path.join(BASE_DIR, 'ap-dashboard.sqlite3')) DB_FILE = os.environ.get('AP_DB_FILE', os.path.join(BASE_DIR, 'ap-dashboard.sqlite3'))
CONNECTION_FILE = os.environ.get('AP_CONNECTION_FILE', os.path.join(BASE_DIR, 'ap-dashboard-connection')) CONNECTION_FILE = os.environ.get('AP_CONNECTION_FILE', os.path.join(BASE_DIR, 'ap-dashboard-connection'))
@@ -501,5 +501,19 @@ def monitor():
except Exception: pass except Exception: pass
time.sleep(2) time.sleep(2)
class UnixServer(ThreadingHTTPServer):
address_family = socket.AF_UNIX
daemon_threads = True
def server_bind(self):
socketserver.TCPServer.server_bind(self)
self.server_name, self.server_port = 'localhost', 0
if __name__ == '__main__': if __name__ == '__main__':
db(); threading.Thread(target=monitor,daemon=True).start(); print(f'API AP sur http://0.0.0.0:{PORT}'); ThreadingHTTPServer((HOST,PORT),Handler).serve_forever() db(); threading.Thread(target=monitor,daemon=True).start()
try: os.remove(SOCKET_PATH)
except OSError: pass
server = UnixServer(SOCKET_PATH, Handler)
os.chmod(SOCKET_PATH, 0o660)
try: shutil.chown(SOCKET_PATH, user='root', group='www-data')
except (LookupError, OSError): os.chmod(SOCKET_PATH, 0o666)
print(f'API AP sur le socket {SOCKET_PATH} (aucun port TCP)'); server.serve_forever()
+3 -3
View File
@@ -1,6 +1,6 @@
ServerName localhost ServerName localhost
<VirtualHost *:1001> <VirtualHost *:${AP_WEB_PORT}>
DocumentRoot /var/www/html DocumentRoot /var/www/html
DirectoryIndex index.html DirectoryIndex index.html
@@ -12,8 +12,8 @@ ServerName localhost
# L'API Python lit l'IP réelle du client dans X-Real-IP # L'API Python lit l'IP réelle du client dans X-Real-IP
RequestHeader set X-Real-IP "expr=%{REMOTE_ADDR}" RequestHeader set X-Real-IP "expr=%{REMOTE_ADDR}"
ProxyPreserveHost On ProxyPreserveHost On
ProxyPass /api http://127.0.0.1:8080/api ProxyPass /api unix:/run/ap-api.sock|http://localhost/api
ProxyPassReverse /api http://127.0.0.1:8080/api ProxyPassReverse /api http://localhost/api
ErrorLog /dev/stderr ErrorLog /dev/stderr
CustomLog /dev/stdout combined CustomLog /dev/stdout combined
+12 -25
View File
@@ -1,31 +1,18 @@
# 1. Trouver l'interface de la carte Wi-Fi : iw dev
# 2. Lancer : AP_INTERFACE=wlan0 docker compose up -d --build
# 3. Injecter la carte Wi-Fi dans le conteneur (à refaire à chaque redémarrage du conteneur) :
# sudo ./attach-wifi.sh wlan0
# 4. Ouvrir : http://IP-DE-LA-MACHINE:1001/
#
# Si votre fichier HTML ne s'appelle pas index.html, ajoutez sous "build:"
# args:
# HTML_FILE: ap_dashboard.html
services: services:
ap-wifi: AP-Manageur:
build: . image: gitea.yoann-nas.fr/yoannmultigaming/apmanageur.git:latest
container_name: ap-wifi container_name: ap-manageur
restart: unless-stopped restart: unless-stopped
ports: network_mode: host # accès direct à la carte Wi-Fi de l'hôte (Apache sur le port 1001)
- "1001:1001" # interface web (Apache)
- "8080:8080" # API (le HTML l'appelle sur ce port)
privileged: true # NetworkManager interne : rfkill, NAT, sysctl privileged: true # NetworkManager interne : rfkill, NAT, sysctl
environment: environment:
AP_INTERFACE: ${AP_INTERFACE:-} # Laisser vide = détection automatique de la carte Wi-Fi.
# Écrire un nom (ex. "wlan0") = cette interface sera utilisée.
AP_INTERFACE: ""
# Port d'écoute de l'interface web.
AP_WEB_PORT: "1001"
volumes: volumes:
- ap-data:/data - /path/to/APmanageur/data:/data
- nm-connections:/etc/NetworkManager/system-connections - /path/to/APmanageur/nm-connections:/etc/NetworkManager/system-connections
- nm-state:/var/lib/NetworkManager - /path/to/APmanageur/nm-state:/var/lib/NetworkManager
- /run/udev:/run/udev:ro # NetworkManager reconnaît ainsi la carte USB - /run/udev:/run/udev:ro # NetworkManager reconnaît ainsi la carte USB
volumes:
ap-data:
nm-connections:
nm-state:
+27 -12
View File
@@ -3,18 +3,33 @@ set -euo pipefail
log() { echo "[ap-wifi] $*"; } log() { echo "[ap-wifi] $*"; }
# 1. Interface Wi-Fi (Netgear) -------------------------------------------------- # Port d'écoute d'Apache (défini dans docker-compose.yml)
IFACE="${AP_INTERFACE:-}" AP_WEB_PORT="${AP_WEB_PORT:-1001}"
mapfile -t FOUND < <(iw dev 2>/dev/null | awk '$1=="Interface"{print $2}') if ! [[ "$AP_WEB_PORT" =~ ^[0-9]+$ ]] || (( AP_WEB_PORT < 1 || AP_WEB_PORT > 65535 )); then
if [[ -z "$IFACE" ]]; then log "ERREUR : AP_WEB_PORT invalide ('$AP_WEB_PORT'), attendu un nombre entre 1 et 65535"
if [[ ${#FOUND[@]} -eq 1 ]]; then
IFACE="${FOUND[0]}"
else
log "ERREUR : précisez AP_INTERFACE. Interfaces Wi-Fi détectées : ${FOUND[*]:-aucune}"
exit 1 exit 1
fi
fi fi
iw dev "$IFACE" info >/dev/null 2>&1 || { log "ERREUR : interface '$IFACE' introuvable (détectées : ${FOUND[*]:-aucune})"; exit 1; } export AP_WEB_PORT
# 1. Interface Wi-Fi --------------------------------------------------
IFACE="${AP_INTERFACE:-}"
log "Recherche de la carte Wi-Fi…"
FOUND=()
for _ in $(seq 1 180); do
mapfile -t FOUND < <(iw dev 2>/dev/null | awk '$1=="Interface"{print $2}')
if [[ -n "$IFACE" ]]; then
printf '%s\n' "${FOUND[@]:-}" | grep -qx "$IFACE" && break
elif [[ ${#FOUND[@]} -ge 1 ]]; then
IFACE="${FOUND[0]}"
for d in "${FOUND[@]}"; do
p="$(iw dev "$d" info 2>/dev/null | awk '/wiphy/{print "phy"$2}')"
if [[ -n "$p" ]] && iw "$p" info 2>/dev/null | grep -qE '^\s+\* AP$'; then IFACE="$d"; break; fi
done
break
fi
sleep 1
done
[[ -n "$IFACE" ]] && iw dev "$IFACE" info >/dev/null 2>&1 || { log "ERREUR : interface '${IFACE:-?}' absente après 3 min (détectées : ${FOUND[*]:-aucune})"; exit 1; }
export AP_INTERFACE="$IFACE" export AP_INTERFACE="$IFACE"
log "Interface utilisée : $IFACE" log "Interface utilisée : $IFACE"
@@ -48,7 +63,7 @@ nmcli radio wifi on 2>/dev/null || true
nmcli device set "$IFACE" managed yes 2>/dev/null || true nmcli device set "$IFACE" managed yes 2>/dev/null || true
log "NetworkManager prêt" log "NetworkManager prêt"
# 3. API Python (port 8080) + Apache (port 80) ------------------------------------ # 3. API Python (socket Unix, aucun port) + Apache (port 1001) ------------------------------------
python3 /app/ap.py & python3 /app/ap.py &
API_PID=$! API_PID=$!
apache2ctl -D FOREGROUND & apache2ctl -D FOREGROUND &
@@ -56,7 +71,7 @@ WEB_PID=$!
trap 'log "Arrêt"; kill "$WEB_PID" "$API_PID" "$NM_PID" 2>/dev/null || true; exit 0' TERM INT trap 'log "Arrêt"; kill "$WEB_PID" "$API_PID" "$NM_PID" 2>/dev/null || true; exit 0' TERM INT
log "Interface web : http://<ip-de-la-machine>:1001/ (API directe : port 8080)" log "Interface web : http://<ip-de-la-machine>:${AP_WEB_PORT}/ (API interne par socket, aucun port)"
wait -n wait -n
log "Un service s'est arrêté, fermeture du conteneur" log "Un service s'est arrêté, fermeture du conteneur"
kill "$WEB_PID" "$API_PID" "$NM_PID" 2>/dev/null || true kill "$WEB_PID" "$API_PID" "$NM_PID" 2>/dev/null || true