Votre application fonctionne sur localhost. Vous voulez maintenant la partager via un vrai nom de domaine, sans laisser votre ordinateur portable allumé. Il vous manque un VPS, un processus d’application géré, le DNS et un reverse proxy HTTPS.
Ce guide présente ce parcours avec une petite application Node.js. Claude Code peut vous aider à inspecter votre projet et à préparer la configuration pour relecture ; vous restez responsable des modifications apportées au serveur. Le modèle n’est pas installé sur le VPS, et l’accès à Claude ainsi que sa facturation sont distincts de l’hébergement.
Présentation animée. Le tableau de bord est une démonstration fictive, pas une supervision d’infrastructure en production.
Regardez l’aperçu du déploiement
Voir la présentation du déploiement (vidéo en anglais).
Ce que nous avons réellement testé : un vrai tableau de bord, créé à l’origine par Claude Code, a été déployé par notre opérateur sur un VPS Linux jetable. Nous avons vérifié le DNS public, le HTTPS de confiance, la redirection de HTTP vers HTTPS, les processus non-root de l’application et du proxy, ainsi que l’accès après le redémarrage du service de l’application. Aucun nouveau déploiement autonome par Claude n’a été effectué. Le prompt suggéré ci-dessous est pédagogique, pas une réponse enregistrée.
Avant de commencer
- Un VPS Linux avec systemd et un compte SSH disposant des droits sudo. Utilisez d’abord un VPS de test ; n’écrasez pas les services ni la configuration web d’un site existant.
- Un runtime Node.js LTS pris en charge installé sur le serveur, et Caddy installé comme service système. Installez ces prérequis avant de suivre les étapes de déploiement.
- Un domaine ou un sous-domaine dont vous pouvez modifier les enregistrements DNS.
- Une petite application autonome. Notre exemple sert
index.htmlviaserver.mjs, sans dépendance de paquets ni base de données.
Les applications basées sur un framework nécessitent leur propre commande de build, leur propre commande de démarrage, leurs dépendances et un plan de stockage. Ne supposez pas qu’un projet Next.js, Python ou adossé à une base de données puisse utiliser tel quel cet exemple à deux fichiers.
1. Demandez à Claude Code d’inspecter le projet avant de le modifier
Placez-vous dans le répertoire de votre projet local. Une première demande utile est :
Inspect this project without changing files. Identify its runtime,
build and start commands, configuration and secrets. Propose a Linux
VPS deployment using a non-root systemd service and Caddy HTTPS.
Bind the app to 127.0.0.1:3000. Explain each proposed file and
verification step. Do not connect to a server or edit DNS.
Les workflows documentés de Claude Code incluent la planification avant l’édition. Relisez les modifications proposées plutôt que d’accepter aveuglément des commandes de déploiement. Gardez les clés d’API, les identifiants de production et les clés SSH privées hors des prompts et des dépôts ; un accès en lecture seule ne rend pas confidentiels les fichiers sensibles.
2. Préparez et transférez l’application
Pour cet exemple minimal précis, enregistrez votre HTML sous index.html et utilisez le serveur suivant. Il écoute par défaut sur l’interface loopback et n’expose pas de fichiers arbitraires du projet :
import {createServer} from 'node:http';
import {readFileSync} from 'node:fs';
import {fileURLToPath} from 'node:url';
const page=readFileSync(new URL('./index.html',import.meta.url));
export function createAppServer(){
return createServer((req,res)=>{
const pathname=new URL(req.url,'http://localhost').pathname;
if(pathname!=='/' && pathname!=='/index.html'){
res.writeHead(404,{'Content-Type':'text/plain; charset=utf-8'});res.end('Not found');return;
}
res.writeHead(200,{'Content-Type':'text/html; charset=utf-8','X-Content-Type-Options':'nosniff'});res.end(page);
});
}
if(process.argv[1]===fileURLToPath(import.meta.url)){
const host=process.env.HOST||'127.0.0.1';const port=Number(process.env.PORT||3000);
const server=createAppServer();server.listen(port,host,()=>console.log(`Demo app listening on ${host}:${port}`));
process.on('SIGTERM',()=>server.close(()=>process.exit(0)));
}
Lancez-le en local avec node server.mjs, ouvrez http://127.0.0.1:3000, puis arrêtez-le avant de continuer. Sur un VPS qui utilise déjà le port 3000, choisissez un autre port privé, de façon cohérente dans le service et dans le proxy.
Depuis le répertoire de votre projet local, remplacez deploy et VPS_IP par votre compte SSH et l’adresse réelle de votre serveur :
ssh deploy@VPS_IP 'mkdir -p ~/my-app'
scp index.html server.mjs deploy@VPS_IP:~/my-app/
Sur le serveur, installez ces deux fichiers non secrets dans un répertoire d’application lisible :
sudo install -d -m 0755 /opt/my-app
sudo install -m 0644 ~/my-app/index.html ~/my-app/server.mjs /opt/my-app/
command -v node
Notez le chemin absolu de l’exécutable Node. Il doit être accessible en dehors de votre shell de connexion et de votre répertoire personnel. Une installation d’un gestionnaire de versions réservée à l’utilisateur sous /home ne convient pas au service durci ci-dessous. Ne copiez jamais un .env de développement, une clé privée ou un dump de base de données dans un répertoire web public.
3. Exécutez l’application comme service systemd non-root
Utilisez sudoedit /etc/systemd/system/my-app.service. Remplacez /ABSOLUTE/PATH/TO/node par le chemin réel de l’exécutable, valable pour tout le serveur, que vous venez de vérifier :
[Unit]
Description=My Node web app
After=network.target
[Service]
Type=simple
DynamicUser=true
WorkingDirectory=/opt/my-app
ExecStart=/ABSOLUTE/PATH/TO/node /opt/my-app/server.mjs
Environment=NODE_ENV=production
Environment=HOST=127.0.0.1
Environment=PORT=3000
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.target
Les contrôles d’exécution de systemd documentent le compte dynamique et les paramètres de durcissement. Ce profil convient à notre application en lecture seule ; les applications qui écrivent des uploads ou des bases de données exigent un stockage persistant et des permissions configurés délibérément.
sudo systemctl daemon-reload
sudo systemctl enable --now my-app.service
sudo systemctl status my-app.service --no-pager
curl -fsS http://127.0.0.1:3000/
Corrigez les erreurs de l’application avant de toucher au DNS. Un service activé est configuré pour démarrer au boot, mais ce n’est pas la preuve qu’un test de redémarrage a été réalisé.
4. Faites pointer un sous-domaine vers le VPS
Créez un enregistrement A pour le nom d’hôte choisi, par exemple app.example.com, ciblant l’adresse IPv4 publique de votre VPS. Avec Cloudflare, notre démonstration en direct sur le serveur utilisait DNS uniquement et un TTL automatique. Ne recopiez pas l’IP de notre démonstration dans les enregistrements de votre propre site.
Vérifiez la réponse publique avec dig +short A app.example.com. Inspectez aussi dig +short AAAA app.example.com : si un enregistrement IPv6 existe, il doit mener au même déploiement fonctionnel en IPv6. Le DNS ne fait que mapper une adresse ; il ne démarre pas votre application et ne configure pas le HTTPS.
5. Placez Caddy devant l’application privée
Gardez le service Node sur 127.0.0.1:3000. Rendez les ports web publics 80 et 443 accessibles via le pare-feu du fournisseur et celui de l’hôte, sans supprimer votre accès SSH. N’exposez pas le port 3000 sur Internet.
Ajoutez ce bloc de site à la configuration de votre service Caddy installé, en remplaçant le nom d’hôte d’exemple. Conservez les blocs de sites sans rapport :
app.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
}
La directive reverse_proxy transmet les requêtes publiques à l’application privée. Avec un nom d’hôte public éligible et des conditions de validation de certificat satisfaites, le HTTPS automatique de Caddy obtient et renouvelle les certificats, et redirige HTTP vers HTTPS.
Pour le service système Caddy standard et son chemin de configuration :
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl reload caddy
Notre VPS de tournage utilisait un service Caddy dédié et des chemins de configuration isolés plutôt que le service partagé standard ci-dessus. Le principe de routage est le même ; ces chemins et noms de service destinés aux lecteurs sont des adaptations, pas une transcription mot pour mot de l’installation.
6. Vérifiez le résultat public et le redémarrage du service
curl -I http://app.example.com/
curl -I https://app.example.com/
sudo systemctl restart my-app.service
curl --retry 5 --retry-delay 1 --retry-connrefused -I https://app.example.com/
Vérifiez la présence d’une redirection HTTP vers HTTPS, d’une réponse HTTPS réussie et d’un certificat valide dans le navigateur. N’utilisez pas curl -k pour masquer des erreurs de confiance. Ouvrez la page depuis un autre réseau, et pas seulement depuis l’intérieur du VPS.
Un échec de la vérification du redémarrage doit être analysé : consultez journalctl -u my-app.service -n 50 --no-pager ainsi que les journaux du service Caddy. Les erreurs DNS, un IPv6 incorrect, une application arrêtée, un mauvais port en amont et une validation de certificat bloquée sont autant de problèmes distincts.
Nous avons vérifié le redémarrage du service de l’application, pas un reboot du VPS ni une configuration haute disponibilité. Avant d’héberger une vraie application d’entreprise, prévoyez aussi les mises à jour, les sauvegardes, la supervision, la gestion des secrets et les éventuelles données persistantes.
Du projet local à une adresse publique
Le parcours complet est simple : préparer le projet, le transférer sur le VPS, le faire tourner comme service géré non-root, faire pointer le DNS vers le serveur et terminer le HTTPS public au niveau du reverse proxy. Claude Code peut aider à préparer et à expliquer ces éléments ; la relecture et les contrôles opérationnels restent indispensables.
Découvrez les offres VPS Linux de SharpHeberg lorsque vous êtes prêt à mettre un projet local en ligne. L’hébergement fournit l’environnement serveur, pas un abonnement Claude inclus ni un modèle Claude hébergé localement.