capy à travers tout internet. Une machine chez toi est cachée derrière ta box : personne ne peut la joindre directement depuis l'extérieur. capy.network contourne ça avec un relais, un petit programme qui tourne sur une machine joignable depuis internet (un VPS, un serveur loué quelques euros par mois).
Le serveur (chez toi) se connecte au relais et y reste branché, sous un nom. Le client (n'importe où) demande au relais de transmettre son appel à ce nom. Le relais fait passer la demande et la réponse.
Comme c'est le serveur qui appelle le relais, aucun port à ouvrir sur ta box. Seul le VPS doit avoir un port ouvert. Tout est chiffré de bout en bout jusqu'au relais, et le relais demande une clé (un mot de passe).
Choisis une clé longue et aléatoire (voir l'astuce juste en dessous).
Ouvre le port dans le pare-feu : sudo ufw allow 3879/tcp.
Lance le relais, et note l'empreinte qu'il affiche (si capy n'est pas trouvé sur le VPS : python3 -m capy.network 3879 …).
terminal
capy relay 3879 MA_CLE_SECRETE
résultat
Relais capy.network en écoute sur le port 3879, chiffré (TLS), avec clé
Empreinte : 9b734c758696262e758f8664db40fafe3601f3804ced5dc331527704319f3049
💡Générer une bonne clé
python3 -c "import secrets; print(secrets.token_urlsafe(24))" donne une clé impossible à deviner. La même clé va ensuite dans le relais, dans les serveurs et dans les clients.
⚠️Sans clé, le relais est ouvert à tous
capy relay 3879 (sans clé) marche, mais n'importe qui peut alors brancher un serveur ou appeler les tiens. Le relais le rappelle au démarrage : SANS clé : ouvert à tous.
import capy.network
capy.network.use("mon-vps.fr:3879", key="MA_CLE_SECRETE")
api = capy.network.Server("maison")
@api.action("test")
deftest():
return {"text": "Hello"}
api.run() # se reconnecte tout seul si le relais redémarre ou si internet coupe
résultat
Connecté au relais mon-vps.fr:3879 sous le nom 'maison' (chiffré)
réseau → {"action": "test"}
Avec fingerprint=, le client vérifie dès la 1re connexion qu'il parle bien à ton relais. Sans, il retient l'empreinte à la 1re connexion (comme SSH) et ne vérifie qu'à partir de la 2e.
💡Tout dans un capy.config.json
{"name": "maison", "relay": "mon-vps.fr:3879", "key": "$CAPY_KEY", "fingerprint": "9b73…"} dans un capy.config.json : plus besoin de use(), ni de recopier l'adresse et la clé dans chaque fichier. capy.project().server() côté serveur, capy.project().call("test") côté client. La clé reste dans la variable d'environnement CAPY_KEY.
capy network call maison test --relay mon-vps.fr:3879 --key "$CAPY_KEY"
résultat
{
"text": "Hello"
}
Le relais et la clé peuvent venir d'ailleurs que des options : du capy.config.json du dossier (mode network), ou des variables d'environnement CAPY_RELAY et CAPY_KEY. Avec export CAPY_RELAY=mon-vps.fr:3879 dans ~/.zshrc, c'est juste capy network call maison test.
--fingerprint … vérifie l'empreinte du relais dès le 1er appel.
Lancer un relais : capy network relay 3879 CLÉ, ou plus court capy relay 3879 CLÉ.
Dans un projet en mode network, cy call test passe par le relais de capy.config.json.
le relais n'est pas lancé, mauvais port, ou le pare-feu du VPS bloque
mauvaise clé pour ce relais
la clé de use() n'est pas celle donnée au relais
aucun serveur 'maison' sur le relais (connectés : salon)
le serveur n'est pas lancé, ou il a un autre nom
nom déjà utilisé, un autre serveur est connecté au relais sous le nom 'maison'
un autre serveur (souvent le tien, encore ouvert ailleurs) a déjà ce nom
'maison' s'est déconnecté
le serveur s'est arrêté pendant l'appel
capy.network.SecurityError
l'empreinte du relais a changé : ce n'est peut-être pas ton relais
📌Un nom libéré tout seul
Si l'ancien serveur ne répond plus (programme tué, ordi éteint), le relais s'en rend compte et laisse le nouveau prendre le nom. Le message « nom déjà utilisé » ne s'affiche que si l'autre répond encore.
Lancé dans un terminal ssh, le relais s'arrête quand tu fermes la session. Pour qu'il tourne toujours et redémarre tout seul (même après un redémarrage du VPS), fais-en un service systemd : voir l'exemple « Garder le relais allumé (systemd) » plus bas.
💡Voir ce qui passe par le relais
Le relais affiche les connexions (+ maison connecté, - maison déconnecté) et chaque demande transmise. Les mots de passe y sont masqués ("***"), comme sur un serveur capy. Avec systemd : journalctl -u capy-relay -f.
Sans capy.network.use(...) avant Server ou call, capy le rappelle : ValueError: capy.network : aucun relais, utilise capy.network.use("ip:port").
💡Plusieurs serveurs, un seul relais
Chaque serveur a son nom ("maison", "garage", "pi"…) et le client choisit qui appeler. Le même client peut appeler tous les serveurs du relais.
🔒Ne mets pas l'IP de ton VPS dans un dépôt public
Mets-la plutôt dans une variable d'environnement ou un fichier ignoré par git, avec la clé. Un nom de domaine (mon-vps.fr) est encore plus pratique : tu peux changer de VPS sans toucher au code.
Le relais peut-il lire mes données ?
Le relais déchiffre les messages pour savoir à qui les transmettre, puis les rechiffre vers le serveur. C'est ton relais, sur ta machine : garde-le pour toi, et ne branche pas tes serveurs sur le relais de quelqu'un d'autre.
Quelle différence avec capy.wifi ?
capy.wifi marche sans rien installer d'autre, mais seulement sur le même wifi. capy.network marche partout, mais il lui faut un relais sur une machine joignable depuis internet.
Exemples
capy.network : à travers tout internet, chiffré
Un relais tourne sur une machine joignable depuis internet (un VPS). Les serveurs s'y connectent même derrière une box, les clients les appellent par leur nom.
1. Sur le VPS : ouvrir le port, puis lancer le relais (il affiche son empreinte)
relais.sh
ufw allow 3879/tcp
capy relay 3879 motdepasse
# Relais capy.network en écoute sur le port 3879, chiffré (TLS), avec clé
# Empreinte : 9b734c758696262e758f8664db40fafe3601f3804ced5dc331527704319f3049
2. Le serveur : chez toi, derrière ta box, il se connecte au relais
serveur.py
import capy
import capy.network
capy.network.use("mon-vps.fr:3879", key="motdepasse")
api = capy.network.Server("maison")
@api.action("temperature")
deftemperature():
return {"salon": 20.5}
api.run() # Se reconnecte tout seul si le relais redémarre
3. Le client : n'importe où dans le monde
fingerprint = l'empreinte affichée par le relais : sûr dès la 1re connexion
Sur le VPS : le relais tourne en fond, redémarre s'il plante et se relance au démarrage du VPS. Remplace MA_CLE_SECRETE par ta clé, et /root si capy est installé pour un autre utilisateur.
relais_systemd.sh
sudo tee /etc/systemd/system/capy-relay.service > /dev/null <<'SERVICE'[Unit]
Description=Relais capy.network
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/bin/python3 -u -m capy.network 3879 MA_CLE_SECRETE
WorkingDirectory=/root
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
SERVICE
sudo systemctl daemon-reload
sudo systemctl enable --now capy-relay # Lancer maintenant + à chaque démarrage
systemctl status capy-relay # Il doit être "active (running)"journalctl -u capy-relay -f # Voir son journal en direct (Ctrl+C pour sortir)
Un projet complet : capy.config.json
On décrit le projet une fois (nom, version, port, adresse, chiffrement, fichiers…) ; serveur et client le lisent avec capy.project(), et cy lance ses scripts et ses fichiers (comme npm).
1. Créer le projet (modes : local, wifi ou network), puis tout lancer d'un coup
creer_le_projet.sh
capy new mon-jeu
cd mon-jeu
cy # Voir ce que capy a compris
# mon-jeu v1.0
# mode local (localhost:4000)
# tls oui (chiffré)
# server server.py ✓
# client client.py ✓
cy run # Serveur en fond + client, puis arrêt du serveur
# server │ API en écoute sur le port 4000, chiffrée (TLS) · empreinte : …
# Bonjour toi !
cy server # Ou chacun dans son terminal
cy client
2. Le serveur : pas de port écrit dans le code, il vient du fichier
serveur.py
import capy
app = capy.project() # Lit capy.config.json (à côté du script, ou dans un dossier au-dessus)
server = app.server() # capy.Server, capy.wifi.Server ou capy.network.Server selon "mode"@server.action("hello")
defhello(nom="monde"):
return {"message": f"Bonjour {nom} !"}
server.run()
3. Le client : pas d'IP, pas de port, pas de relais