Accès à distance

Par défaut, SkyView n'est accessible que sur le réseau local — dès que vous sortez, l'application mobile ne joint plus votre serveur. Ce chapitre présente trois façons d'exposer SkyView sans prendre de risque : l'accès direct public (recommandé), le VPN maillé et le reverse proxy, ainsi que les ports nécessaires à chacun. L'accès direct public ne demande qu'un domaine et une seule règle sur le routeur ; le certificat est demandé automatiquement depuis l'interface web.

À lire en premier

Il n'y a qu'une règle absolue pour exposer SkyView : HTTPS et un mot de passe solide. L'accès direct public de SkyView, c'est « un port TCP + TLS + authentification », et non vos caméras exposées telles quelles. En revanche, ne redirigez jamais les ports RTSP / ONVIF des caméras elles-mêmes, ni les ports de diffusion internes de SkyView (24214 / 23880) : aucune authentification ne les protège, les rediriger revient à offrir vos caméras à tous les scanners d'Internet.

Quelle méthode choisir

MéthodeCe qu'il fautTravail sur le routeurLatence du directPour qui
Accès direct publicUn domaine (un sous-domaine gratuit suffit), certificat automatiqueIPv4 : une redirection TCP. IPv6 : autoriser l'entrantWebRTC, moins de 0,5 sLignes avec IP publique ou IPv6 (recommandé)
VPN mailléLa même application installée sur chaque appareil utiliséRien du toutWebRTC, moins d'une secondeCGNAT sans IPv6, ou refus d'ouvrir le moindre port
Reverse proxy + domaineUn nginx / Caddy / Lucky déjà en placeRediriger le port du proxyHLS, environ 2,5 s (WebRTC avec un passage TCP)Ceux qui ont déjà un proxy et veulent tout sur 443

Les trois ne s'excluent pas : vous pouvez les activer en même temps. En cas de doute, procédez dans cet ordre : vérifiez d'abord si votre ligne dispose d'IPv6 — dans ce cas l'accès direct public ne demande même aucune redirection ; sans IPv6 mais avec une IP publique, c'est également l'accès direct public ; sans ni l'un ni l'autre (CGNAT), passez au VPN maillé.

Méthode 1 : accès direct public (recommandé)

SkyView regroupe l'interface web, l'API des applications et le flux en direct sur un seul port TCP : ce même port transporte le HTTPS et le canal vidéo WebRTC, le serveur faisant lui-même l'aiguillage. Il n'y a donc qu'une seule règle sur le routeur, sans redirection UDP supplémentaire pour WebRTC.

Ce que cela résout

Jusqu'ici, le direct à distance retombait forcément sur HLS (environ 2,5 s de latence) : WebRTC exigeait à la fois des ports redirigés en plus et une adresse réellement joignable annoncée par le serveur, deux conditions rarement réunies sur une ligne domestique — la négociation expirait et le flux se dégradait. Désormais un seul port suffit et le direct s'affiche en moins d'une seconde, ce qui change tout pour « voir qui sonne à la porte ».

Étape 1 : domaine et certificat (demande automatique)

L'accès direct public impose HTTPS : les applications mobiles refusent les certificats auto-signés, il vous faut donc votre propre domaine et un vrai certificat. Dans Réglages → Général → Certificat HTTPS, saisissez le domaine et la clé d'API de votre fournisseur DNS : SkyView demande alors un certificat Let's Encrypt et le renouvelle automatiquement avant expiration.

  • Le port 80 reste fermé. La validation se fait en DNS-01 (un enregistrement TXT temporaire sous votre domaine), donc même si l'entrant 80 est bloqué par l'opérateur.
  • Fournisseurs DNS pris en charge : Alibaba Cloud, Tencent Cloud DNSPod, Huawei Cloud, Cloudflare, AWS Route 53, Porkbun, deSEC, DuckDNS.
  • Pas de domaine à vous ? Ce n'est pas bloquant : deSEC et DuckDNS offrent des sous-domaines gratuits qui feront parfaitement l'affaire.
  • Vous avez déjà un certificat ? Déposez fullchain.pem et privkey.pem dans data/certs/ : SkyView les utilisera sans jamais écraser vos fichiers.
  • Avant la demande, lancez l'auto-test : il écrit réellement un enregistrement de test puis le supprime, ce qui valide la clé d'API et les droits sans consommer le quota de délivrance de Let's Encrypt.

Le domaine doit vous appartenir

SkyView n'héberge pas de domaine à votre place (ni DDNS intégré, ni sous-domaine officiel) : le domaine et sa zone DNS restent à votre nom, nous n'automatisons que le certificat — exactement comme certbot ou acme.sh. Si vous n'avez pas de domaine, deSEC et DuckDNS (ci-dessus) sont gratuits.

Étape 2 : choisir un port public

Sur une ligne résidentielle, méfiez-vous du 443

En Chine continentale, les ports 80 et 443 entrants sont largement bloqués sur les lignes résidentielles (pour empêcher l'hébergement de sites non déclarés). Reprendre un tutoriel étranger qui recommande 443 produit la panne la plus pénible qui soit : la règle du routeur est parfaitement correcte, la connexion n'arrive tout simplement jamais, et aucune erreur n'apparaît nulle part. Dans ce cas, utilisez un port haut — le 23443 par défaut convient très bien. Sur un serveur cloud ou dans la plupart des autres régions, aucune restriction : 443 fonctionne et évite d'écrire le port dans l'URL.

Saisissez le port public dans le même panneau et enregistrez : l'effet est immédiat. Le backend se reconfigure puis vérifie que le port est réellement passé à l'écoute — sans redémarrer le conteneur ni toucher au fichier compose. Si le port est déjà pris par un autre programme ou entre en conflit avec un port interne, l'enregistrement est refusé sur-le-champ plutôt que d'échouer silencieusement ensuite.

Étape 3 : le routeur

  • IPv4 (adresse publique) : ajoutez une redirection envoyant le 23443/tcp public vers le 23443 de la machine SkyView. C'est la seule règle nécessaire : inutile de rediriger 23515 ou quoi que ce soit d'autre.
  • IPv6 : pas de NAT, donc rien à rediriger. Autorisez simplement les connexions entrantes vers 23443/tcp dans le pare-feu IPv6 du routeur.
  • DNS : un enregistrement A pour l'IPv4 publique, un AAAA pour l'IPv6. Les adresses résidentielles changent : confiez la mise à jour à un client DDNS.

Étape 4 : vérifier

Ouvrez https://<votre-domaine>:23443/, connectez-vous et allez sur le direct. L'image doit apparaître en moins d'une seconde, via WebRTC.

Le même panneau propose un auto-test d'accessibilité publique : il vérifie l'adresse vers laquelle pointe le domaine, l'ouverture du port et la validité du certificat, puis vous indique directement l'étape qui bloque — sans capture réseau.

Et si l'opérateur ne fournit pas d'IP publique

Si l'auto-test signale que votre adresse publique se trouve dans une plage CGNAT (NAT d'opérateur), la redirection de ports ne fonctionnera jamais, quelle que soit la configuration : ce n'est pas une erreur de votre part. Deux issues : utiliser l'IPv6 (désormais très répandue, et sans aucune redirection), ou passer au VPN maillé ci-dessous. Vous pouvez aussi demander une IP publique à votre opérateur ; beaucoup l'activent gratuitement.

Méthode 2 : VPN maillé (aucun port ouvert)

Les outils de maillage (Tailscale / WireGuard / ZeroTier, etc.) créent un tunnel chiffré entre votre téléphone et votre serveur domestique, de sorte que le téléphone accède à SkyView via l'adresse interne exactement comme à la maison — aucun port à ouvrir sur le routeur, et le serveur n'est absolument pas exposé sur Internet.

  1. 1

    Installer le client de maillage sur le serveur

    Installez Tailscale sur la machine exécutant SkyView (ou un routeur logiciel sur le même réseau local), puis exécutez tailscale up pour vous connecter. WireGuard / ZeroTier fonctionnent de façon similaire.

    bash
    curl -fsSL https://tailscale.com/install.sh | sh
    sudo tailscale up
  2. 2

    Installer la même application sur votre téléphone et vous connecter au même compte

    Installez l'application Tailscale / ZeroTier correspondante sur le téléphone et connectez-vous avec le même compte que le serveur ; les deux extrémités se trouvent désormais sur le même réseau local virtuel.

  3. 3

    Saisir l'adresse de maillage dans l'application

    Définissez l'adresse du serveur dans l'application SkyView sur l'IP attribuée par le maillage — Tailscale utilise 100.x.x.x, ZeroTier utilise 10.x.x.x — le port reste :23406, par ex. http://100.x.x.x:23406.

  4. 4

    Terminé

    Une fois à l'extérieur, le téléphone peut y accéder même en 4G/5G, exactement comme à la maison. Aucune IP publique, aucun nom de domaine, aucun certificat HTTPS n'est nécessaire.

Le compromis

Aucun port ouvert signifie une surface d'attaque publique nulle — les scanners ne vous voient même pas — et cela ne dépend pas d'une IP publique, donc cela fonctionne derrière un CGNAT. Dans le maillage, votre téléphone est traité comme s'il était sur le réseau local : le direct emprunte donc toujours le canal WebRTC à faible latence. En contrepartie, chaque appareil doit installer l'application et s'y connecter, ce qui rend le partage ponctuel avec la famille moins pratique qu'une simple URL.

Méthode 3 : reverse proxy + domaine

Si vous disposez d'une IP publique + d'un nom de domaine et souhaitez y accéder via une adresse du type https://cam.example.com (pratique pour l'envoyer à des proches qui ne peuvent pas facilement installer l'application de maillage), vous pouvez placer une couche nginx / Caddy devant SkyView pour la terminaison HTTPS. Le conteneur SkyView inclut déjà une couche nginx en interne, le proxy externe n'a donc qu'à rediriger tout le trafic vers :23406.

Ce que devient le direct derrière un proxy

Un reverse proxy HTTP classique relaie l'interface et l'API, et le direct passe alors en HLS (environ 2,5 s) — tout reste fonctionnel. Pour retrouver le WebRTC en moins d'une seconde, faites passer un port en couche TCP (bloc stream de nginx, plugin layer4 de Caddy) directement vers le port public de SkyView. Les deux cohabitent très bien : l'interface via le proxy sur 443, le direct via le port en passe-through.

Configuration nginx

Enregistrez le contenu ci-dessous intégralement sous /etc/nginx/sites-available/skyview.conf, remplacez <your-domain>, puis créez un lien symbolique (ln -s) vers sites-enabled/ — un seul fichier suffit, aucun extrait séparé n'est nécessaire. Les blocs proxy_set_header des deux location / sont identiques : le proxy_set_header de nginx écrase au lieu d'hériter, donc chaque location doit porter sa propre copie — copiez-le simplement tel quel.

nginx
# Transmission de l'en-tête WebSocket Upgrade — doit être dans le contexte http {}
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name <your-domain>;
    # certbot --nginx réécrira ce bloc en redirection 301 vers https
    location / {
        proxy_pass http://127.0.0.1:23406;
        proxy_http_version 1.1;
        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  $host;
        proxy_set_header X-Forwarded-Port  $server_port;
        proxy_set_header X-Forwarded-Proto $scheme;        # ★ Si omis, les déploiements HTTPS tombent dans une boucle de connexion
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        $connection_upgrade;
        proxy_buffering       off;
        proxy_connect_timeout 60s;
        proxy_send_timeout    1d;
        proxy_read_timeout    1d;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name <your-domain>;

    ssl_certificate     /etc/letsencrypt/live/<your-domain>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<your-domain>/privkey.pem;

    # Les exports d'enregistrements et les imports groupés de la bibliothèque de visages peuvent faire plusieurs centaines de Mo ; les cookies JWT longs sont volumineux, évite les erreurs 414
    client_max_body_size        200m;
    client_header_buffer_size   4k;
    large_client_header_buffers 8 16k;

    location / {
        proxy_pass http://127.0.0.1:23406;
        proxy_http_version 1.1;
        # ↓ Identique à la location :80 ci-dessus, copiez ligne par ligne (proxy_set_header n'hérite pas)
        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  $host;
        proxy_set_header X-Forwarded-Port  $server_port;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        $connection_upgrade;
        proxy_buffering       off;
        proxy_connect_timeout 60s;
        proxy_send_timeout    1d;
        proxy_read_timeout    1d;
    }
}
/etc/nginx/sites-available/skyview.conf

X-Forwarded-Proto / X-Forwarded-Host doivent être transmis et inclus dans chaque location

Le nginx du conteneur écoute uniquement en HTTP ; il s'appuie sur X-Forwarded-Proto pour connaître le schéma réel du client et sur X-Forwarded-Host pour connaître le domaine externe. Omettre X-Forwarded-Proto → sur les déploiements HTTPS, vous êtes renvoyé à la page de connexion juste après vous être connecté, et la vue en direct est bloquée par le navigateur en tant que contenu mixte (Mixed Content) ; omettre X-Forwarded-Host → les liens de lecture / téléchargement / export d'enregistrements sont construits avec de mauvaises adresses et le client ne peut pas les ouvrir. Le modèle nginx ci-dessus et Caddy (qui transmet ces deux en-têtes par défaut) couvrent tous les deux ce cas — il suffit de le copier. Vous n'avez pas besoin de définir X-Forwarded-Port manuellement ; le nginx du conteneur gère automatiquement les scénarios « reverse proxy externe / accès direct par IP nue ». De plus, le proxy_set_header de nginx écrase au lieu d'ajouter : si une location en écrit ne serait-ce qu'un seul, tous les set_header du niveau supérieur cessent de s'appliquer — chaque location doit donc include l'extrait complet.

Obtenez un certificat (la machine doit être joignable depuis Internet sur le port :80) :

bash
certbot --nginx -d <your-domain> -m <your-email> --agree-tos --no-eff-email --redirect

Configuration Caddy (plus simple)

Caddy émet / renouvelle automatiquement les certificats Let's Encrypt sans certbot, et la configuration est bien plus courte. /etc/caddy/Caddyfile :

caddyfile
<your-domain> {
    reverse_proxy 127.0.0.1:23406 {
        # Caddy transmet X-Forwarded-{For,Proto,Host} par défaut
        # Pour les connexions longue durée (WS de conversation / SSE d'événements / flux en direct), augmentez flush + les délais d'expiration
        flush_interval -1
        transport http {
            read_timeout  24h
            write_timeout 24h
        }
    }
    request_body {
        max_size 200MB
    }
}
/etc/caddy/Caddyfile

Tableau des ports

PortProtocoleUsageÀ ouvrir sur Internet ?
23443TCPAccès direct public : interface + API + direct (HTTPS, port modifiable)Oui — le seul port requis par cette méthode
23406TCPPoint d'entrée local (HTTP en clair)Non — pour l'accès distant, utilisez 23443 ci-dessus
23515UDP + TCPFlux média du direct (LAN / maillage / IPv6 direct)Non
23880TCPRTSP, pour les lecteurs externes sur le réseau localNon
24214TCPService de diffusion interneJamais

Ne redirigez jamais les ports internes

24214 (service de diffusion interne) et 23880 (RTSP) ne sont protégés par aucune authentification : l'autorisation des flux se fait au point d'entrée 23406 / 23443. Les exposer contourne entièrement l'authentification et rend vos caméras publiques. Même chose pour rediriger 23406 tel quel : c'est du HTTP en clair, les mots de passe circulent en clair sur Internet, et les navigateurs comme Android 9+ refusent l'accès à la caméra sur une page non sécurisée. Pour l'accès distant, utilisez l'accès direct public (23443, HTTPS) décrit plus haut.

Comment vérifier après la configuration

bash
# 1. Redirection HTTP→HTTPS (scénario reverse proxy)
curl -sSI http://<your-domain>/healthz | head -1      # attendu : 301

# 2. Vérification de santé
curl -sS https://<your-domain>/healthz                 # attendu : {"code":0,...}

# 3. Accéder à un point de terminaison protégé sans être connecté
curl -sS -o /dev/null -w '%{http_code}\n' \
     https://<your-domain>/api/cameras                 # attendu : 401

Enfin, parcourez tout le flux dans un navigateur : connexion → voir le flux en direct → aucune erreur de contenu mixte (Mixed Content) dans la console du navigateur. Si vous êtes renvoyé à la page de connexion juste après vous être connecté, ou si la vue en direct signale du Mixed Content, c'est dans 99 % des cas que X-Forwarded-Proto n'a pas été transmis correctement. Pour plus de dépannage, consultez Dépannage.