Déploiement
L’API Apprise est conçue pour fonctionner comme un service conteneurisé.
Cette page explique comment la déployer et l’exploiter, pas comment utiliser les endpoints de l’API.
Si vous cherchez à :
- envoyer des notifications, consultez Utilisation de l’API
- l’intégrer avec la CLI ou la bibliothèque Python, consultez Intégrations
- comprendre les clés, le stockage ou le verrouillage, consultez Configuration
Démarrage Rapide
Section intitulée « Démarrage Rapide »Choisissez ci-dessous une méthode de déploiement pour démarrer rapidement l’API Apprise.
Les exemples auto-hébergés publient normalement le port 8000 afin que les
appareils de confiance de votre réseau domestique ou interne puissent se
connecter sans proxy supplémentaire. Ils utilisent le mode normal. Ne les
exposez pas directement à Internet. Utilisez l’onglet Déploiement derrière un
proxy pour un serveur public avec HTTPS, authentification, routage strict et
port de conteneur limité à l’adresse locale.
docker run --name apprise \ -p 8000:8000 \ -v ./config:/config \ -v ./attach:/attach \ -e APPRISE_STATEFUL_MODE=simple \ -e APPRISE_WORKER_COUNT=1 \ -e APPRISE_DEFAULT_FORMAT=text \ -d caronc/apprise:latestLa commande suivante configure le même conteneur, mais avec une surveillance par health check :
docker run --name apprise \ -p 8000:8000 \ -v ./config:/config \ -v ./attach:/attach \ -e APPRISE_STATEFUL_MODE=simple \ -e APPRISE_WORKER_COUNT=1 \ -e APPRISE_DEFAULT_FORMAT=text \ --health-cmd='curl -fsS http://127.0.0.1:8000/status >/dev/null || exit 1' \ --health-interval=30s \ --health-timeout=5s \ --health-retries=3 \ --health-start-period=20s \ -d caronc/apprise:latestPour essayer la connexion administrateur intégrée en local, arrêtez d’abord le
conteneur de démarrage rapide : les deux exemples utilisent le port 8000.
Celui-ci laisse la liste des configurations accessible à admin :
docker run --name apprise-auth \ -p 127.0.0.1:8000:8000 \ -v ./config:/config \ -v ./attach:/attach \ -e APPRISE_STATEFUL_MODE=simple \ -e APPRISE_AUTH_REQUIRED=yes \ -e APPRISE_USER=admin \ -e APPRISE_PASSWORD=changeme \ -e APPRISE_WEB_AUTH_SECRET="$(openssl rand -hex 32)" \ -e APPRISE_WORKER_COUNT=1 \ -e APPRISE_DEFAULT_FORMAT=text \ -d caronc/apprise:latestOuvrez http://127.0.0.1:8000/cfg et connectez-vous avec admin et le mot de
passe changeme. La liste fonctionne grâce au mode simple ; la liste des
configurations est affichée par défaut.
Ce modèle rend le conteneur accessible uniquement depuis l’hôte Docker. Une instance Nginx distincte fournit le HTTPS public, les journaux et la politique de sécurité.
Préparer les fichiers du conteneur
Section intitulée « Préparer les fichiers du conteneur »Créez les répertoires persistants, un fichier d’environnement et un fichier hôte vide pour la surcharge du serveur Nginx. Remplacez le mot de passe d’exemple avant de démarrer le conteneur. La surcharge sera remplie après que Docker aura indiqué la passerelle du conteneur actif.
mkdir -p apprise/config apprise/attachchmod 700 apprise
web_secret="$(openssl rand -hex 32)"cat > apprise/apprise.env <<EOFSTRICT_MODE=yesAPPRISE_STATEFUL_MODE=simpleAPPRISE_WORKER_COUNT=1APPRISE_AUTH_REQUIRED=yesAPPRISE_WEB_AUTH_SECRET=${web_secret}APPRISE_USER=adminAPPRISE_PASSWORD=replace-with-a-strong-passwordAPPRISE_TRUSTED_ORIGINS=https://apprise.example.comALLOWED_HOSTS=apprise.example.comTZ=Etc/UTCEOFchmod 600 apprise/apprise.envtouch apprise/nginx-server-override.confchmod 644 apprise/nginx-server-override.confLe fichier hôte vide doit exister avant docker run, car la commande ci-dessous
le monte à la place du fichier vide du conteneur. Son contenu sera ajouté après
le démarrage du conteneur.
STRICT_MODE=yes conserve le code 404 pour les routes inconnues, renvoie
405 pour les méthodes non prises en charge et limite le trafic
d’authentification avec 429 et Retry-After: 60. Le conteneur applique ces
contrôles stricts. Le serveur Nginx public ci-dessous reste un simple relais
HTTPS et journalise les réponses pour des outils comme Fail2ban.
Démarrer le conteneur limité à l’adresse locale
Section intitulée « Démarrer le conteneur limité à l’adresse locale »docker run -d \ --name apprise \ --publish 127.0.0.1:8010:8000 \ --user "$(id -u):$(id -g)" \ --env-file "$PWD/apprise/apprise.env" \ --volume "$PWD/apprise/config:/config" \ --volume "$PWD/apprise/attach:/attach" \ --volume "$PWD/apprise/nginx-server-override.conf:/etc/nginx/server-override.conf:ro" \ --health-cmd='curl -fsS -u "$APPRISE_USER:$APPRISE_PASSWORD" http://127.0.0.1:8000/status >/dev/null || exit 1' \ --health-interval=30s \ --health-timeout=5s \ --health-retries=3 \ --health-start-period=20s \ --restart unless-stopped \ caronc/apprise:latestLa publication du port sur 127.0.0.1 empêche tout accès réseau direct au
conteneur. Seuls les services exécutés sur l’hôte Docker, comme le proxy Nginx
public ci-dessous, peuvent joindre le port 8010.
Configurer la passerelle Docker fiable
Section intitulée « Configurer la passerelle Docker fiable »Inspectez maintenant ce conteneur une seule fois, écrivez la passerelle obtenue dans la surcharge montée, puis redémarrez Apprise pour que Nginx la charge :
docker_gateway="$(docker inspect \ --format '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' \ apprise)"
if [ -z "$docker_gateway" ]; then echo "Impossible de déterminer la passerelle Docker d'Apprise." exit 1fi
cat > apprise/nginx-server-override.conf <<EOF# Adresse obtenue depuis le conteneur Apprise actif avec docker inspect.set_real_ip_from ${docker_gateway};
real_ip_header X-Forwarded-For;real_ip_recursive on;EOF
docker restart appriseCette méthode fonctionne avec le bridge par défaut et les réseaux personnalisés, car la passerelle provient du conteneur actif. Répétez cette étape après un changement de réseau Docker. Ne faites pas confiance à tout un réseau Docker ou privé, sauf si chacun de ses appareils est fiable. Apprise utilise l’adresse client obtenue pour l’audit et les limites de débit du mode strict.
Configurer le proxy Nginx public
Section intitulée « Configurer le proxy Nginx public »La directive map doit se trouver dans le contexte http de Nginx. Les fichiers
placés sous /etc/nginx/conf.d/ y sont généralement chargés. Cette règle masque
les contrôles d’état réussis et conserve les erreurs ainsi que les réponses de
limitation de débit.
map "$uri:$status" $apprise_access_loggable { default 1; ~^/(?:status(?:/.*)?|metrics|favicon\.ico|robots\.txt)/?:[23] 0;}
server { listen 80; server_name apprise.example.com;
return 301 https://apprise.example.com$request_uri;}
server { listen 443 ssl http2; server_name apprise.example.com;
ssl_certificate /etc/letsencrypt/live/apprise.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/apprise.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/apprise_access.log combined if=$apprise_access_loggable; error_log /var/log/nginx/apprise_error.log warn;
# Le proxy public contrôle la limite effective des téléversements. client_max_body_size 100m;
location / { proxy_pass http://127.0.0.1:8010; proxy_http_version 1.1; proxy_set_header Connection "";
proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Real-IP $remote_addr;
# Remplacer toute chaîne de transfert fournie par le client public. proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Expect $http_expect;
proxy_connect_timeout 5s; proxy_send_timeout 310s; proxy_read_timeout 310s;
# Transmettre directement les téléversements et réponses événementielles. proxy_request_buffering off; proxy_buffering off; proxy_cache off;
# Préserver les réponses d'authentification, de limitation et d'erreur. proxy_intercept_errors off; proxy_redirect off; }}Utilisez votre automatisation de certificats et votre politique de sécurité existantes à la place des chemins d’exemple. N’activez HSTS qu’après avoir confirmé que le domaine et ses éventuels sous-domaines resteront exclusivement accessibles en HTTPS.
Vérifier la chaîne de proxy
Section intitulée « Vérifier la chaîne de proxy »nginx -tsystemctl reload nginx
curl --user admin https://apprise.example.com/statusdocker inspect --format '{{json .State.Health}}' appriseLe proxy externe doit remplacer X-Forwarded-For, et le conteneur ne doit faire
confiance qu’à la passerelle Docker de ce proxy. Ensemble, ces réglages
conservent l’adresse publique du client sans permettre sa falsification.
services: apprise: image: caronc/apprise:latest container_name: apprise ports: - "8000:8000" environment: APPRISE_STATEFUL_MODE: simple APPRISE_WORKER_COUNT: 1 APPRISE_DEFAULT_FORMAT: "text" volumes: - ./config:/config - ./attach:/attachLa configuration suivante met en place le même conteneur, mais avec surveillance par health check :
services: apprise: image: caronc/apprise:latest container_name: apprise ports: - "8000:8000" environment: APPRISE_STATEFUL_MODE: simple APPRISE_WORKER_COUNT: 1 APPRISE_DEFAULT_FORMAT: "text" volumes: - ./config:/config - ./attach:/attach healthcheck: test: [ "CMD-SHELL", "curl -fsS http://127.0.0.1:8000/status >/dev/null || exit 1", ] interval: 30s timeout: 5s retries: 3 start_period: 20sPour obtenir la même configuration administrateur locale avec Compose,
enregistrez le YAML ci-dessous dans compose.yaml. Placez le mot de passe
d’exemple et un secret durable pour les connexions Web dans un fichier .env
protégé :
printf 'APPRISE_PASSWORD=changeme\nAPPRISE_WEB_AUTH_SECRET=%s\n' \ "$(openssl rand -hex 32)" > .envchmod 600 .envservices: apprise: image: caronc/apprise:latest ports: - "127.0.0.1:8000:8000" env_file: - .env environment: APPRISE_STATEFUL_MODE: simple APPRISE_AUTH_REQUIRED: "yes" APPRISE_USER: admin APPRISE_WORKER_COUNT: 1 APPRISE_DEFAULT_FORMAT: "text" volumes: - ./config:/config - ./attach:/attachL’entrée env_file charge les deux secrets depuis .env, placé à côté de
compose.yaml. Arrêtez tout ancien conteneur utilisant le port 8000, puis lancez
docker compose up -d. Ouvrez http://127.0.0.1:8000/cfg et connectez-vous
avec admin et le mot de passe changeme. Conservez .env lors des
redéploiements ; changer son secret Web déconnecte les sessions existantes.
apiVersion: apps/v1kind: Deploymentmetadata: name: apprisespec: replicas: 1 selector: matchLabels: app: apprise template: metadata: labels: app: apprise spec: containers: - name: apprise image: caronc/apprise:latest ports: - containerPort: 8000 env: - name: APPRISE_STATEFUL_MODE value: simple - name: APPRISE_WORKER_COUNT value: 1 - name: APPRISE_DEFAULT_FORMAT value: "text"L’exemple suivant reprend cette base et ajoute des probes de liveness et readiness :
apiVersion: apps/v1kind: Deploymentmetadata: name: apprisespec: replicas: 1 selector: matchLabels: app: apprise template: metadata: labels: app: apprise spec: containers: - name: apprise image: caronc/apprise:latest ports: - containerPort: 8000 env: - name: APPRISE_STATEFUL_MODE value: simple - name: APPRISE_WORKER_COUNT value: 1 - name: APPRISE_DEFAULT_FORMAT value: "text"
# Prêt uniquement lorsque /status renvoie 200 readinessProbe: httpGet: path: /status port: 8000 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3
# Redémarre le conteneur si /status cesse de renvoyer 200 livenessProbe: httpGet: path: /status port: 8000 initialDelaySeconds: 20 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3Voici un exemple Kubernetes plus complet. Notez qu’il utilise encore les variables d’environnement héritées PGID et PUID :
apiVersion: v1kind: Namespacemetadata: labels: name: apprise name: apprise---apiVersion: v1kind: ConfigMapmetadata: labels: name: apprise name: apprise-api-override-conf-config namespace: apprisedata: location-override.conf: | auth_basic "Apprise API Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd;---apiVersion: v1kind: Secretmetadata: labels: name: apprise name: apprise-api-htpasswd-secret namespace: apprisedata: .htpasswd: <base64_encoded> # ajoutez la sortie de : htpasswd -c apprise_api.htpasswd <USERNAME> && cat apprise_api.htpasswd | base64---apiVersion: v1kind: PersistentVolumeClaimmetadata: labels: name: apprise name: apprise-data namespace: apprisespec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi---apiVersion: v1kind: Servicemetadata: labels: name: apprise name: apprise namespace: apprisespec: ports: - name: http port: 80 protocol: TCP targetPort: 8000 selector: name: apprise type: ClusterIP---apiVersion: apps/v1kind: Deploymentmetadata: labels: name: apprise name: apprise namespace: apprisespec: replicas: 1 selector: matchLabels: name: apprise strategy: type: Recreate template: metadata: labels: name: apprise spec: containers: - env: - name: APPRISE_STATEFUL_MODE value: simple - name: PGID value: "1000" - name: PUID value: "1000" image: caronc/apprise:latest name: apprise ports: - containerPort: 8000 protocol: TCP resources: limits: cpu: "500m" memory: "512Mi" requests: cpu: "250m" memory: "128Mi" volumeMounts: - mountPath: /config name: apprise-data - mountPath: /plugin name: apprise-data - mountPath: /attach name: apprise-data # Le mountPath suivant peut être supprimé si non souhaité / non utilisé - mountPath: /etc/nginx/.htpasswd name: apprise-api-htpasswd-secret-volume readOnly: true subPath: .htpasswd # Le mountPath suivant peut être supprimé si non souhaité / non utilisé - mountPath: /etc/nginx/location-override.conf name: apprise-api-override-conf-config-volume readOnly: true subPath: location-override.conf restartPolicy: Always volumes: - name: apprise-data persistentVolumeClaim: claimName: apprise-data # Le volume suivant peut être supprimé si non souhaité / non utilisé - name: apprise-api-htpasswd-secret-volume secret: secretName: apprise-api-htpasswd-secret # Le volume suivant peut être supprimé si non souhaité / non utilisé - name: apprise-api-override-conf-config-volume configMap: name: apprise-api-override-conf-configMerci à @steled pour l’exemple ci-dessus. La même configuration peut être étendue avec des probes de liveness et readiness simplement en remplaçant la dernière section par celle-ci :
apiVersion: apps/v1kind: Deploymentmetadata: labels: name: apprise name: apprise namespace: apprisespec: replicas: 1 selector: matchLabels: name: apprise strategy: type: Recreate template: metadata: labels: name: apprise spec: containers: - env: - name: APPRISE_STATEFUL_MODE value: simple - name: PGID value: "1000" - name: PUID value: "1000" image: caronc/apprise:latest name: apprise ports: - containerPort: 8000 protocol: TCP
readinessProbe: httpGet: path: /status port: 8000 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3
livenessProbe: httpGet: path: /status port: 8000 initialDelaySeconds: 20 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3
resources: limits: cpu: "500m" memory: "512Mi" requests: cpu: "250m" memory: "128Mi" volumeMounts: - mountPath: /config name: apprise-data - mountPath: /plugin name: apprise-data - mountPath: /attach name: apprise-data - mountPath: /etc/nginx/.htpasswd name: apprise-api-htpasswd-secret-volume readOnly: true subPath: .htpasswd - mountPath: /etc/nginx/location-override.conf name: apprise-api-override-conf-config-volume readOnly: true subPath: location-override.conf restartPolicy: Always volumes: - name: apprise-data persistentVolumeClaim: claimName: apprise-data - name: apprise-api-htpasswd-secret-volume secret: secretName: apprise-api-htpasswd-secret - name: apprise-api-override-conf-config-volume configMap: name: apprise-api-override-conf-configPour une configuration davantage orientée sécurité, vous pouvez exécuter l’API Apprise comme utilisateur non-root avec un système de fichiers racine en lecture seule et des volumes éphémères explicites.
L’exemple suivant suppose que vous avez déjà créé des persistent volume claims pour /config, /plugin et /attach.
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: apprise name: apprise namespace: apprisespec: replicas: 1 selector: matchLabels: app: apprise template: metadata: labels: app: apprise spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 readOnlyRootFilesystem: true containers: - name: apprise image: caronc/apprise:latest imagePullPolicy: IfNotPresent securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: APPRISE_STATEFUL_MODE value: simple - name: APPRISE_WORKER_COUNT value: "1" - name: APPRISE_DEFAULT_FORMAT value: "text" ports: - containerPort: 8000 name: http volumeMounts: # Données persistantes - name: config mountPath: /config - name: plugin mountPath: /plugin - name: attach mountPath: /attach
# Fichiers runtime et temporaires éphémères - name: tmp mountPath: /tmp
volumes: - name: config persistentVolumeClaim: claimName: apprise-config - name: plugin persistentVolumeClaim: claimName: apprise-plugin - name: attach persistentVolumeClaim: claimName: apprise-attach
# Le déploiement monte /tmp en emptyDir en mémoire ; c'est là que nginx, # gunicorn et supervisord stockent leurs pid, sockets et fichiers temporaires. # Ce volume est éphémère et stocké en mémoire. - name: tmp emptyDir: medium: MemoryLa même configuration peut être étendue avec des probes de liveness et readiness en remplaçant la section par celle-ci :
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: apprise name: apprise namespace: apprisespec: replicas: 1 selector: matchLabels: app: apprise template: metadata: labels: app: apprise spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 readOnlyRootFilesystem: true containers: - name: apprise image: caronc/apprise:latest imagePullPolicy: IfNotPresent securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] env: - name: APPRISE_STATEFUL_MODE value: simple - name: APPRISE_WORKER_COUNT value: "1" - name: APPRISE_DEFAULT_FORMAT value: "text" ports: - containerPort: 8000 name: http
# Les health checks exigent que /status renvoie HTTP 200 readinessProbe: httpGet: path: /status port: http initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3
livenessProbe: httpGet: path: /status port: http initialDelaySeconds: 20 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3
volumeMounts: # Données persistantes - name: config mountPath: /config - name: plugin mountPath: /plugin - name: attach mountPath: /attach
# Fichiers runtime et temporaires éphémères - name: tmp mountPath: /tmp
volumes: - name: config persistentVolumeClaim: claimName: apprise-config - name: plugin persistentVolumeClaim: claimName: apprise-plugin - name: attach persistentVolumeClaim: claimName: apprise-attach
# Le déploiement monte /tmp en emptyDir en mémoire ; c'est là que nginx, # gunicorn et supervisord stockent leurs pid, sockets et fichiers temporaires. # Ce volume est éphémère et stocké en mémoire. - name: tmp emptyDir: medium: MemorySuivez ces instructions pour exécuter l’API Apprise directement sur un hôte, sans Docker. Chaque installation utilise un environnement virtuel Python, le gestionnaire de services du système d’exploitation et Nginx. Dans ces exemples, Gunicorn n’écoute que sur l’adresse locale et Nginx expose le service en HTTP simple sur un réseau local ou de confiance. Pour une installation accessible depuis Internet, ajoutez HTTPS et l’authentification comme décrit dans Déploiement derrière un proxy.
Installez les paquets requis :
sudo apt updatesudo apt install -y python3 python3-pip python3-venv git nginxClonez l’API Apprise et installez ses dépendances Python :
cd /optsudo git clone https://github.com/caronc/apprise-api.gitsudo python3 -m venv /opt/apprise-api/venvsudo /opt/apprise-api/venv/bin/pip install --upgrade pipsudo /opt/apprise-api/venv/bin/pip install -r /opt/apprise-api/requirements.txtsudo install -d -o www-data -g www-data \ /var/lib/apprise/config /var/lib/apprise/attachCréez l’unité systemd à /etc/systemd/system/apprise.service :
[Unit]Description=Apprise API ServiceAfter=network.target
[Service]User=www-dataGroup=www-dataWorkingDirectory=/opt/apprise-apiEnvironment=APPRISE_CONFIG_DIR=/var/lib/apprise/configEnvironment=APPRISE_ATTACH_DIR=/var/lib/apprise/attachEnvironment=APPRISE_STATEFUL_MODE=simpleEnvironment=APPRISE_WORKER_COUNT=1Environment=APPRISE_DEFAULT_FORMAT=textEnvironment=TZ=Etc/UTCExecStart=/opt/apprise-api/venv/bin/gunicorn \ --no-control-socket \ --workers 1 \ --worker-class gevent \ --timeout 300 \ --bind 127.0.0.1:8000 \ --chdir /opt/apprise-api/apprise_api \ core.wsgi:applicationRestart=on-failure
[Install]WantedBy=multi-user.targetActivez-la et démarrez-la :
sudo systemctl daemon-reloadsudo systemctl enable --now appriseAPPRISE_STATEFUL_MODE=simple enregistre chaque configuration dans un fichier
lisible et permet au gestionnaire de configurations d’afficher vos clés
enregistrées. Un seul processus Gunicorn limite l’utilisation des ressources
pour un usage personnel ou une petite équipe.
Créez /etc/nginx/sites-available/appriseapi pour servir les fichiers
statiques et transmettre le reste à Gunicorn :
server { listen 80; server_name _;
client_max_body_size 500M;
location /s/ { alias /opt/apprise-api/apprise_api/static/; }
location / { proxy_pass http://127.0.0.1:8000; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $http_host; proxy_read_timeout 300s; proxy_send_timeout 300s; }}Activez le site et rechargez NGINX :
sudo ln -s /etc/nginx/sites-available/appriseapi /etc/nginx/sites-enabled/sudo rm -f /etc/nginx/sites-enabled/defaultsudo nginx -tsudo systemctl enable --now nginxVisitez http://your-server-ip/ (ou http://127.0.0.1/ en local). L’API
Apprise devrait se charger.
Journaux et fichiers
- Fichiers de l’application :
/opt/apprise-api - Configurations enregistrées :
/var/lib/apprise/config - Pièces jointes temporaires :
/var/lib/apprise/attach - Journaux de Gunicorn :
sudo journalctl -u apprise - Journaux de NGINX :
/var/log/nginx/
Gérer le service
sudo systemctl status apprisesudo systemctl restart apprisesudo systemctl stop appriseLes mêmes étapes fonctionnent sur Red Hat Enterprise Linux 10, Rocky Linux 10, et Oracle Linux 10.
Installez les paquets requis et démarrez NGINX :
sudo dnf install -y python3 python3-pip git nginxsudo systemctl enable --now nginxSi firewalld est actif, autorisez le trafic HTTP :
sudo firewall-cmd --permanent --add-service=httpsudo firewall-cmd --reloadClonez l’API Apprise et installez ses dépendances Python :
cd /optsudo git clone https://github.com/caronc/apprise-api.gitsudo python3 -m venv /opt/apprise-api/venvsudo /opt/apprise-api/venv/bin/pip install --upgrade pipsudo /opt/apprise-api/venv/bin/pip install -r /opt/apprise-api/requirements.txtsudo install -d -o nginx -g nginx \ /var/lib/apprise/config /var/lib/apprise/attachCréez l’unité systemd à /etc/systemd/system/apprise.service :
[Unit]Description=Apprise API ServiceAfter=network.target
[Service]User=nginxGroup=nginxWorkingDirectory=/opt/apprise-apiEnvironment=APPRISE_CONFIG_DIR=/var/lib/apprise/configEnvironment=APPRISE_ATTACH_DIR=/var/lib/apprise/attachEnvironment=APPRISE_STATEFUL_MODE=simpleEnvironment=APPRISE_WORKER_COUNT=1Environment=APPRISE_DEFAULT_FORMAT=textEnvironment=TZ=Etc/UTCExecStart=/opt/apprise-api/venv/bin/gunicorn \ --no-control-socket \ --workers 1 \ --worker-class gevent \ --timeout 300 \ --bind 127.0.0.1:8000 \ --chdir /opt/apprise-api/apprise_api \ core.wsgi:applicationRestart=on-failure
[Install]WantedBy=multi-user.targetActivez-la et démarrez-la :
sudo systemctl daemon-reloadsudo systemctl enable --now appriseAPPRISE_STATEFUL_MODE=simple enregistre chaque configuration dans un fichier
lisible et permet au gestionnaire de configurations d’afficher vos clés
enregistrées. Un seul processus Gunicorn limite l’utilisation des ressources
pour un usage personnel ou une petite équipe.
Copiez les fichiers statiques dans l’arborescence web de Nginx :
sudo install -d /usr/share/nginx/html/apprisesudo cp -R /opt/apprise-api/apprise_api/static/. \ /usr/share/nginx/html/apprise/Ces fichiers restent ainsi sous /usr/share/nginx/html, où la politique SELinux
standard autorise Nginx à les servir sans modifier le contexte de sécurité du
code source de l’application.
Créez /etc/nginx/default.d/apprise.conf :
La configuration Nginx fournie par Rocky charge ce fichier dans son bloc serveur par défaut. L’adresse IP du serveur fonctionne donc sans nom de domaine.
client_max_body_size 500M;
location /s/ { alias /usr/share/nginx/html/apprise/;}
location / { proxy_pass http://127.0.0.1:8000; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $http_host; proxy_read_timeout 300s; proxy_send_timeout 300s;}Laissez NGINX joindre Gunicorn. SELinux bloque par défaut ses connexions vers les autres ports locaux :
sudo setsebool -P httpd_can_network_connect 1Testez et rechargez NGINX :
sudo nginx -tsudo systemctl reload nginxVisitez http://your-server-ip/ (ou http://127.0.0.1/ en local). L’API
Apprise devrait se charger.
Journaux et fichiers
- Fichiers de l’application :
/opt/apprise-api - Configurations enregistrées :
/var/lib/apprise/config - Pièces jointes temporaires :
/var/lib/apprise/attach - Journaux de Gunicorn :
sudo journalctl -u apprise - Journaux de NGINX :
/var/log/nginx/
Gérer le service
sudo systemctl status apprisesudo systemctl restart apprisesudo systemctl stop appriseFreeBSD n’a pas systemd ; cette méthode utilise donc son propre gestionnaire
de services rc.d. Les commandes supposent que sudo est installé et que
votre compte est autorisé à l’utiliser. Sinon, ouvrez une session superutilisateur
avec su - et omettez sudo dans chaque commande.
Installez les paquets requis :
sudo pkg install -y python3 git nginx rust pkgconfpython_version="$(python3 -c \ 'import sys; print(f"{sys.version_info.major}{sys.version_info.minor}")')"sudo pkg install -y "py${python_version}-virtualenv"Sous FreeBSD, Python est compilé sans ensurepip. Le paquet virtualenv
correspondant à la version de Python est donc nécessaire pour créer un
environnement qui contient Pip. Rust et pkgconf permettent à Pip de compiler
des dépendances telles que cryptography, pour lesquelles aucun paquet binaire
Python n’est nécessairement disponible sous FreeBSD.
Clonez l’API Apprise et installez ses dépendances Python :
cd /usr/localsudo git clone https://github.com/caronc/apprise-api.gitsudo python3 -m virtualenv /usr/local/apprise-api/venvsudo /usr/local/apprise-api/venv/bin/pip install --upgrade pipsudo /usr/local/apprise-api/venv/bin/pip install \ -r /usr/local/apprise-api/requirements.txtsudo install -d -o www -g www \ /var/db/apprise/config /var/db/apprise/attachCréez le script de démarrage à /usr/local/etc/rc.d/apprise :
#!/bin/sh
# PROVIDE: apprise# REQUIRE: LOGIN# KEYWORD: shutdown
. /etc/rc.subr
name=apprisercvar=apprise_enable
load_rc_config $name
: ${apprise_enable:="NO"}: ${apprise_user:="www"}: ${apprise_dir:="/usr/local/apprise-api"}: ${apprise_venv:="${apprise_dir}/venv"}: ${apprise_pidfile:="/var/run/${name}.pid"}: ${apprise_logfile:="/var/log/${name}.log"}
pidfile=${apprise_pidfile}command="/usr/sbin/daemon"command_args="-f -r -P ${pidfile} -o ${apprise_logfile} -u ${apprise_user} -t ${name} /usr/bin/env APPRISE_CONFIG_DIR=/var/db/apprise/config APPRISE_ATTACH_DIR=/var/db/apprise/attach APPRISE_STATEFUL_MODE=simple APPRISE_WORKER_COUNT=1 APPRISE_DEFAULT_FORMAT=text TZ=Etc/UTC ${apprise_venv}/bin/gunicorn --no-control-socket --workers 1 --worker-class gevent --timeout 300 --bind 127.0.0.1:8000 --chdir ${apprise_dir}/apprise_api core.wsgi:application"
run_rc_command "$1"Rendez-le exécutable, activez-le au démarrage, et lancez-le :
sudo chmod +x /usr/local/etc/rc.d/apprisesudo sysrc apprise_enable=YESsudo service apprise startAPPRISE_STATEFUL_MODE=simple enregistre chaque configuration dans un fichier
lisible et permet au gestionnaire de configurations d’afficher vos clés
enregistrées. Un seul processus Gunicorn limite l’utilisation des ressources
pour un usage personnel ou une petite équipe. L’option -P enregistre le processus superviseur de
daemon ; service apprise stop peut ainsi arrêter le service sans que Gunicorn
soit aussitôt redémarré.
Remplacez le bloc serveur d’exemple dans la section http { } existante de
/usr/local/etc/nginx/nginx.conf par celui-ci :
server { listen 80; server_name _;
client_max_body_size 500M;
location /s/ { alias /usr/local/apprise-api/apprise_api/static/; }
location / { proxy_pass http://127.0.0.1:8000; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $http_host; proxy_read_timeout 300s; proxy_send_timeout 300s; }}Activez et démarrez NGINX :
sudo sysrc nginx_enable=YESsudo nginx -tsudo service nginx startVisitez http://your-server-ip/ (ou http://127.0.0.1/ en local). L’API
Apprise devrait se charger.
Journaux et fichiers
- Journal Apprise :
/var/log/apprise.log - Fichiers de l’application :
/usr/local/apprise-api - Configurations enregistrées :
/var/db/apprise/config - Pièces jointes temporaires :
/var/db/apprise/attach - Fichier PID :
/var/run/apprise.pid
Gérer le service
sudo service apprise startsudo service apprise stopsudo service apprise restartsudo service nginx restartUne fois déployés, l’API et l’interface web optionnelle sont disponibles à l’adresse :
http://localhost:8000/Stockage Persistant
Section intitulée « Stockage Persistant »L’API Apprise prend en charge le stockage persistant pour :
- les configurations enregistrées ;
- les métadonnées d’authentification mises en cache ;
- les pièces jointes téléversées.
Le conteneur attend les chemins inscriptibles suivants :
| Chemin | Rôle |
|---|---|
/config | Configurations enregistrées et état interne |
/attach | Pièces jointes téléversées |
/plugin | Plugins personnalisés optionnels |
/tmp | Fichiers runtime (sockets, buffers, temp) |
Pour la plupart des déploiements, monter uniquement /config et /attach suffit.
Mode avec État
Section intitulée « Mode avec État »Les fonctions persistantes dépendent du mode du serveur, du verrouillage de la configuration et de la connexion actuelle :
| État | Liste des Configurations | Déplacement / Suppression | Connexion de Configuration | Contenu de Configuration |
|---|---|---|---|---|
| Mode avec état désactivé | Indisponible | Indisponible | Indisponible | Indisponible |
| Authentification désactivée, configuration déverrouillée | Disponible avec APPRISE_STATEFUL_MODE=simple, sauf si APPRISE_ADMIN=no | Autorisé | Indisponible | Disponible |
| Authentification désactivée, configuration verrouillée | Masquée et refusée | Refusé | Indisponible | Masqué ; les notifications enregistrées fonctionnent toujours |
| Utilisateur de configuration, déverrouillée | Refusée | Peut déplacer son propre ID ; ne peut pas le supprimer | Peut modifier son propre mot de passe | Disponible pour son ID |
| Utilisateur de configuration, verrouillée | Refusée | Refusé | Peut modifier son propre mot de passe | Masqué ; les notifications enregistrées fonctionnent toujours |
| Administrateur, déverrouillée | Disponible avec APPRISE_STATEFUL_MODE=simple, sauf si APPRISE_ADMIN=no | Autorisé pour tous les ID | Peut gérer toutes les connexions | Disponible |
| Administrateur, verrouillée | Disponible avec APPRISE_STATEFUL_MODE=simple, sauf si APPRISE_ADMIN=no | Autorisé pour tous les ID | Peut gérer toutes les connexions | Disponible |
Lorsque le contenu est verrouillé, le formulaire Web de notification exige au moins un tag, car il ne peut pas afficher les destinations enregistrées.
Un administrateur authentifié conserve un accès complet aux configurations lorsque le verrouillage est activé. Les utilisateurs d’une configuration et les appelants non authentifiés ne peuvent pas ajouter, récupérer, inspecter, lister, déplacer ni supprimer une configuration. Un compte user peut toujours envoyer des notifications authentifiées avec ou sans état, tandis qu’un compte locked est limité aux notifications avec état et avec tag.
Les modes globaux sont toujours prioritaires. Même un administrateur ne peut pas envoyer de notification avec ou sans état lorsque le mode correspondant est désactivé. Les identifiants administrateur contournent uniquement l’accès propre à la configuration et son verrouillage.
Déploiements Durcis
Section intitulée « Déploiements Durcis »L’API Apprise permet également de durcir les processus et le système de fichiers. Ces mesures protègent le conteneur, mais n’ajoutent ni HTTPS, ni authentification, ni routage strict. Pour un serveur public ou multi-tenant, combinez-les avec le Déploiement derrière un proxy présenté ci-dessus.
Exemple de configuration conteneur durci :
services: apprise: image: caronc/apprise:latest container_name: apprise user: "1000:1000" read_only: true
cap_drop: - ALL
security_opt: - no-new-privileges:true
ports: - "8000:8000"
environment: APPRISE_STATEFUL_MODE: simple APPRISE_WORKER_COUNT: 1 APPRISE_DEFAULT_FORMAT: "text"
volumes: - ./config:/config - ./attach:/attach
tmpfs: - /tmpPoints importants :
/tmpdoit rester inscriptible ;- aucun fichier n’est écrit sous
/var/log; - tous les logs sont écrits vers stdout et stderr.
Notes de Durcissement pour Kubernetes
Section intitulée « Notes de Durcissement pour Kubernetes »Si vous déployez dans Kubernetes, consultez Démarrage Rapide -> Kubernetes -> Durci (rootless + lecture seule) pour un exemple prêt à l’emploi qui :
- s’exécute avec un utilisateur non-root ;
- supprime toutes les capacités Linux ;
- désactive l’escalade de privilèges ;
- utilise un système de fichiers racine en lecture seule ;
- monte
/tmpcommeemptyDiren mémoire.
Vérifications d’État
Section intitulée « Vérifications d’État »L’API Apprise expose un endpoint de santé :
GET /status- Renvoie HTTP
200lorsque le service est sain - Renvoie HTTP
417si un problème bloquant est détecté
Exemple :
curl http://localhost:8000/statusCet endpoint convient pour :
- les health checks Docker ;
- les probes de liveness Kubernetes ;
- les systèmes de supervision externes.
Reverse Proxies et Chemins de Base
Section intitulée « Reverse Proxies et Chemins de Base »Si l’API Apprise est hébergée derrière un proxy inverse ou servie sous un sous-chemin, définissez APPRISE_BASE_URL en conséquence.
Pour un exemple complet de proxy HTTPS avec un accès au conteneur limité à l’adresse locale, consultez Démarrage Rapide -> Docker + Nginx externe ci-dessus.
Exemple :
APPRISE_BASE_URL=/appriseCela garantit :
- une génération correcte des URL ;
- un routage correct de l’interface web ;
- des liens OpenAPI corrects.
Authentification et Contrôle d’Accès
Section intitulée « Authentification et Contrôle d’Accès »L’API Apprise ne requiert aucune authentification par défaut. Définissez APPRISE_AUTH_REQUIRED=yes pour protéger ses points de terminaison avec HTTP Basic. Seuls les ID de configuration rendus publics peuvent la contourner, uniquement pour les notifications avec tag.
| Mode | Paramètres | Résultat |
|---|---|---|
| Désactivé | APPRISE_AUTH_REQUIRED=no | Les requêtes restent ouvertes. Les paramètres d’administration et les connexions de configuration enregistrées sont ignorés. |
| Administrateur activé | APPRISE_AUTH_REQUIRED=yes avec APPRISE_PASSWORD | L’administrateur peut accéder à toutes les clés et gérer les connexions de configuration. APPRISE_USER est facultatif. |
| Administrateur désactivé | APPRISE_AUTH_REQUIRED=yes sans APPRISE_PASSWORD | Les utilisateurs existants accèdent uniquement à leurs propres clés. Aucune nouvelle connexion ne peut être créée tant qu’un mot de passe administrateur n’est pas configuré. |
APPRISE_USER sans APPRISE_PASSWORD produit un avertissement au démarrage et laisse le compte administrateur désactivé. Consultez les Variables d’Environnement.
APPRISE_BASIC_AUTH_REALM nomme le serveur dans les invites de connexion. Il ne modifie aucun identifiant. La valeur par défaut est Apprise API ; utilisez un nom différent pour chaque instance.
Utilisez HTTPS/TLS. L’authentification Basic ne chiffre pas les identifiants. HTTPS est indispensable en dehors de localhost ou d’un réseau de confiance.
Les clients API envoient Basic Auth avec chaque requête. Le serveur garde brièvement en mémoire les vérifications réussies pour accélérer les requêtes suivantes. Il ne conserve pas les identifiants et ne crée pas de session API.
Les pages Web utilisent une connexion signée afin que Déconnexion puisse fermer la session. Les appels API JSON et texte brut ne peuvent pas utiliser cette connexion Web.
Les clients avec état peuvent conserver des chemins comme /notify/{KEY}. Les points de terminaison compatibles acceptent aussi X-Apprise-Config-ID, ce qui garde la clé hors de l’URL.
Les configurations Nginx fournies exposent explicitement GET /qr,
/qr/{KEY} et /qr/@ pour configurer Apprise Mobile. Elles refusent les autres
méthodes, ignorent le corps de la requête, désactivent la mise en tampon du proxy
et marquent les réponses no-store. Le mode strict leur applique aussi la
limite de débit réservée aux routes protégées.
Le plugin apprise:// de la CLI Apprise envoie cet en-tête avec sa version 2, utilisée par défaut. Utilisez ?v=1 uniquement avec un ancien serveur qui exige /notify/{KEY}.
Les connexions Web expirent après 24 heures d’inactivité. Chaque requête authentifiée renouvelle ce délai. Modifier APPRISE_WEB_AUTH_SECRET déconnecte tous les navigateurs.
Le champ ID de configuration permet d’ouvrir une autre configuration sans afficher son ID dans la barre d’adresse. L’utilisateur doit se reconnecter si le nouvel ID utilise d’autres identifiants. Les administrateurs peuvent aussi choisir ou générer un ID avec Nouvelle Configuration.
Chaque ID de configuration utilise un mode d’accès :
| Accès | Utilisation des notifications | Utilisation de la configuration |
|---|---|---|
user | Exige ses identifiants. Les tags sont facultatifs. | L’utilisateur peut consulter, modifier, effacer et remplacer sa configuration. |
locked | Exige les identifiants et un tag précis, jamais all. | Masque le contenu. L’utilisateur peut changer son mot de passe et déplacer l’ID de configuration. |
public | Exige uniquement l’ID de configuration et un tag précis. | Masque le contenu. Les identifiants enregistrés conservent les droits locked, s’ils sont présents. |
disabled | Refuse les notifications de l’utilisateur de configuration. | Bloque l’utilisateur tout en conservant la configuration et les identifiants. |
L’accès public s’applique uniquement aux appels avec état POST /notify/{KEY}. Les autres points de terminaison exigent toujours des identifiants valides. Les pièces jointes restent prises en charge.
Pour POST /notify sans état, l’administrateur peut s’authentifier directement. Un utilisateur de configuration doit fournir des urls explicites, ses identifiants et l’en-tête X-Apprise-Config-ID correspondant ; l’accès doit être user. Sans urls, la forme v2 avec en-tête conserve l’envoi stateful avec la configuration enregistrée.
Les comptes user et locked peuvent consulter /status et /details avec leurs identifiants et leur ID de configuration. Un compte désactivé ne le peut pas. L’administrateur peut fournir un en-tête X-Apprise-Config-ID valide pour simplifier le client, mais cet en-tête n’est pas obligatoire.
Pour définir l’accès, ouvrez une configuration et sélectionnez son cadenas ou Authentification. Choisissez le mode d’accès, saisissez les identifiants lorsqu’ils sont requis, puis sélectionnez Enregistrer. Les administrateurs peuvent utiliser Générer Aléatoirement pour chaque identifiant.
L’ID de configuration et les identifiants sont des valeurs distinctes. Transmettez l’ID et les identifiants configurés à l’utilisateur. Le nom d’utilisateur est facultatif et le mot de passe enregistré n’est plus affiché.
Les clients API gèrent l’accès avec POST /auth/{KEY}. Le champ access
accepte user, locked, public ou disabled. Un nouvel enregistrement
utilise user par défaut, ou locked lorsque APPRISE_CONFIG_LOCK=yes. Un
accès user enregistré se comporte alors comme locked sans être réécrit.
L’accès public reste public, car il masque déjà le contenu de la
configuration. Un utilisateur de configuration peut changer uniquement son
mot de passe et doit répéter son nom d’utilisateur. Consultez les
Points de Terminaison de l’API.
Les verrous par clé sont ignorés lorsque APPRISE_AUTH_REQUIRED est désactivé, ce qui rétablit le fonctionnement ouvert d’origine. Leurs fichiers sont conservés et redeviennent actifs lorsque l’authentification est activée.
Déconnexion ferme la connexion Web signée. Les identifiants en cache du navigateur ne peuvent pas la rétablir silencieusement.
Les anciens verrous sans configuration sont supprimés après APPRISE_AUTH_PRUNE_SECONDS (30 jours par défaut). Lorsqu’un utilisateur user efface sa configuration, ses identifiants sont conservés et ce délai recommence afin qu’il puisse enregistrer une nouvelle configuration. Les verrous avec configuration sont conservés. Consultez Élagage.
Vérification de l’Origine du Navigateur
Section intitulée « Vérification de l’Origine du Navigateur »Les navigateurs ajoutent un en-tête Origin lorsqu’une page modifie des données. L’API Apprise vérifie cet en-tête et refuse les modifications envoyées depuis un autre site. Les requêtes provenant du même site sont autorisées.
L’API Apprise n’exige pas l’échange de jeton CSRF de Django. Les appels directs depuis curl, les applications mobiles et les autres programmes omettent normalement Origin et continuent de fonctionner.
Pour un site HTTPS derrière un proxy inverse, définissez APPRISE_TRUSTED_ORIGINS avec l’adresse publique complète, par exemple https://apprise.example.com. Séparez plusieurs adresses par des virgules.
Pour une défense en profondeur, vous pouvez ajouter des protections en dehors de l’application :
- exposer le conteneur uniquement par un proxy inverse de confiance ;
- ajouter une authentification au niveau du proxy ou de l’ingress ;
- restreindre l’accès avec un pare-feu ou une politique réseau.
Des fichiers de surcharge Nginx peuvent également être montés dans le conteneur pour répondre à des besoins particuliers de contrôle d’accès.
Un exemple Kubernetes utilisant un Secret (basic auth .htpasswd) et une ConfigMap (nginx location-override.conf) est disponible dans Démarrage Rapide -> Kubernetes -> Exemple Complet.
Le conteneur exécute chaque jour un cycle de nettoyage à faible priorité. Il couvre les deux domaines ci-dessous et dispose d’une limite de temps :
| Domaine | Ce qu’il élague | Paramètre de rétention |
|---|---|---|
| État persistant | Stockage d’état de notification Apprise (APPRISE_STORAGE_DIR). | APPRISE_STORAGE_PRUNE_DAYS (défaut 30 jours) |
| Authentification | Verrous Basic par clé sans configuration. | APPRISE_AUTH_PRUNE_SECONDS (défaut 2592000, soit 30 jours) |
APPRISE_PRUNE_INTERVAL_SECONDS contrôle la planification. Réglez APPRISE_PRUNE_ENABLED=no pour désactiver le nettoyage planifié. APPRISE_PRUNE_TIMEOUT_SECONDS modifie la limite de 8 heures. La commande combinée et les commandes individuelles restent exécutables manuellement :
docker exec -it apprise python manage.py prunedocker exec -it apprise python manage.py storeprune --days 30docker exec -it apprise python manage.py authprune --seconds 2592000Logging et Observabilité
Section intitulée « Logging et Observabilité »- Tous les logs sont émis vers stdout et stderr
- Aucun fichier log n’est écrit sur disque
- Des métriques Prometheus sont disponibles sur
/metrics - Les appels réussis à
/status,/metrics, au favicon et àrobots.txtsont omis des journaux d’accès ; les échecs et limitations restent visibles
Déploiements de Développement
Section intitulée « Déploiements de Développement »Pour le développement local, le dépôt inclut des surcharges Docker Compose qui :
- montent l’arborescence source locale ;
- rechargent les changements d’UI et de templates sans rebuild ;
- exposent l’API sur le port
8000.
Ce mode est destiné uniquement au développement et n’est pas recommandé en production.
Étapes Suivantes
Section intitulée « Étapes Suivantes »Une fois l’application déployée, vous pouvez :
- enregistrer des clés de configuration via l’interface web ou l’API ;
- envoyer des notifications avec
/notifyou/notify/{KEY}; - intégrer des systèmes externes via HTTP ou la CLI Apprise.
Questions ou commentaires ?
Documentation
Vous avez repéré une faute de frappe ou une erreur ?
Problèmes Techniques
Vous rencontrez un problème avec le code ? Ouvrez un ticket sur GitHub :