Dynamic reverse proxy with self-registration API - applications can register themselves and receive an automatically assigned port
npm install dynamic-self-register-proxy

Un reverse proxy Node.js avec API d'auto-enregistrement, permettant à vos applications de s'enregistrer dynamiquement et de recevoir un port automatiquement attribué.
- Conteneur Docker unique exposant un seul port vers l'extérieur
- Microservices dynamiques qui démarrent/s'arrêtent sans configuration manuelle
- Environnement de développement avec plusieurs applications Node.js
``bash`
npm install dynamic-self-register-proxy
Ou pour une installation globale :
`bash`
npm install -g dynamic-self-register-proxy
`bashVia npx (sans installation globale)
npx dynamic-self-register-proxy
Le proxy démarre par défaut sur le port
3000.$3
Créez un fichier
.env à la racine du projet (voir .env.example) :`env
PROXY_NAME=Mon Proxy Dev
PROXY_PORT=3000
`$3
`bash
Windows PowerShell
$env:PROXY_PORT="3002"; npx dynamic-self-register-proxyLinux/Mac
PROXY_PORT=3002 npx dynamic-self-register-proxy
`$3
Votre application doit s'enregistrer au démarrage :
`javascript
const response = await fetch('http://localhost:3000/proxy/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
path: '/myapp', // Chemin d'accès via le proxy
name: 'My App' // Nom de l'application (optionnel)
})
});const { port } = await response.json();
// port = 4000 (attribué automatiquement)
// Démarrez votre serveur sur ce port
app.listen(port);
`$3
`
http://localhost:3000/myapp/ → votre application sur le port 4000
`Page d'accueil
L'URL racine
/ affiche une page listant tous les serveurs enregistrés avec des liens pour y accéder.Le nom du proxy (configurable via
PROXY_NAME) est affiché dans le titre et l'en-tête de la page.- Navigateurs (
Accept: text/html) → Page HTML avec interface moderne
- Clients API (Accept: application/json) → Réponse JSON`bash
Accès navigateur : ouvrir http://localhost:3000/
Accès API
curl -H "Accept: application/json" http://localhost:3000/
`Réponse JSON :
`json
{
"name": "Proxy Server",
"status": "healthy",
"uptime": 3600,
"count": 2,
"routes": [
{
"path": "/api",
"port": 4000,
"name": "API Server",
"registeredAt": "2026-01-27T10:00:00.000Z",
"target": "http://localhost:4000"
}
],
"availablePorts": 998
}
`API du Proxy
| Endpoint | Méthode | Description |
|----------|---------|-------------|
|
/ | GET | Page d'accueil (HTML ou JSON selon Accept header) |
| /proxy/register | POST | Enregistre une nouvelle route |
| /proxy/unregister | DELETE | Supprime une route |
| /proxy/routes | GET | Liste toutes les routes |
| /proxy/health | GET | Health check du proxy |$3
Enregistre une nouvelle route et attribue un port.
Request:
`json
{
"path": "/myapp",
"name": "My Application",
"port": 4005
}
`| Champ | Type | Requis | Description |
|-------|------|--------|-------------|
|
path | string | ✅ | Chemin URL pour accéder à l'app |
| name | string | ❌ | Nom descriptif |
| port | number | ❌ | Port spécifique (sinon auto-attribué) |Response (201):
`json
{
"success": true,
"path": "/myapp",
"port": 4000,
"name": "My Application",
"message": "Route registered. Start your server on port 4000"
}
`Erreurs:
-
400 - Path manquant
- 409 - Path ou port déjà utilisé$3
Supprime une route enregistrée.
Request:
`json
{
"path": "/myapp"
}
`Response (200):
`json
{
"success": true,
"path": "/myapp",
"freedPort": 4000
}
`$3
Liste toutes les routes enregistrées.
Response:
`json
{
"count": 2,
"routes": [
{
"path": "/api",
"port": 4000,
"name": "API Server",
"registeredAt": "2026-01-27T10:00:00.000Z",
"target": "http://localhost:4000"
},
{
"path": "/web",
"port": 4001,
"name": "Web App",
"registeredAt": "2026-01-27T10:01:00.000Z",
"target": "http://localhost:4001"
}
],
"availablePorts": 998
}
`$3
Vérifie l'état du proxy.
Response:
`json
{
"name": "Proxy Server",
"status": "healthy",
"uptime": 3600,
"registeredRoutes": 2,
"usedPorts": 2
}
`Intégration dans votre application
$3
`javascript
const express = require('express');const PROXY_URL = process.env.PROXY_URL || 'http://localhost:3000';
const APP_PATH = process.env.APP_PATH || '/myapp';
const APP_NAME = process.env.APP_NAME || 'My App';
async function start() {
// 1. S'enregistrer auprès du proxy
const res = await fetch(
${PROXY_URL}/proxy/register, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path: APP_PATH, name: APP_NAME })
});
const { port } = await res.json();
// 2. Créer l'application
const app = express();
app.get('/', (req, res) => {
res.json({ message: 'Hello!' });
});
// 3. Démarrer sur le port attribué
const server = app.listen(port, () => {
console.log(App accessible via ${PROXY_URL}${APP_PATH});
});
// 4. Se désenregistrer à l'arrêt
process.on('SIGTERM', async () => {
await fetch(${PROXY_URL}/proxy/unregister, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path: APP_PATH })
});
server.close();
});
}start();
`$3
Le package inclut un client helper pour faciliter l'enregistrement :
`javascript
const ProxyClient = require('dynamic-self-register-proxy');const proxy = new ProxyClient('http://localhost:3000');
const { port } = await proxy.register('/myapp', 'My App');
app.listen(port);
// Arrêt propre automatique
proxy.setupGracefulShutdown(server);
`Méthodes disponibles :
-
register(path, name, port?) - Enregistre une route
- unregister() - Supprime l'enregistrement
- listRoutes() - Liste toutes les routes
- health() - Vérifie l'état du proxy
- setupGracefulShutdown(server) - Configure l'arrêt propre
- setupHealthRoute(app, options?) - Ajoute la route de health checkDocker
$3
`bash
Build
npm run docker:buildDémarrer (proxy + 2 apps exemples)
npm run docker:upArrêter
npm run docker:down
`$3
- Proxy :
http://localhost:8081
- App 1 : http://localhost:8081/app1
- App 2 : http://localhost:8081/app2
- Routes : http://localhost:8081/proxy/routes$3
Dans
docker-compose.yml :`yaml
services:
my-service:
build: ./my-service
environment:
- PROXY_URL=http://proxy:3000
- APP_PATH=/my-service
- APP_NAME=My Service
depends_on:
- proxy
networks:
- proxy-network
`Health Check Polling
Le proxy vérifie périodiquement que les serveurs enregistrés sont toujours actifs. Si un serveur ne répond pas correctement, il est automatiquement désenregistré.
$3
Chaque application enregistrée doit implémenter la route
GET /proxy/health qui retourne un code 200 :`javascript
// Avec Express
app.get('/proxy/health', (req, res) => {
res.status(200).json({ status: 'healthy' });
});
`$3
Le helper
ProxyClient fournit une méthode pour ajouter automatiquement cette route :`javascript
const ProxyClient = require('dynamic-self-register-proxy');const proxy = new ProxyClient('http://localhost:3000');
const app = express();
// Ajoute automatiquement GET /proxy/health
proxy.setupHealthRoute(app);
// Ou avec un health check personnalisé
proxy.setupHealthRoute(app, {
healthCheck: async () => {
// Vérifier la connexion à la DB, etc.
const dbOk = await checkDatabase();
return dbOk;
}
});
`$3
- Période de grâce : les nouveaux serveurs ont 60 secondes après l'enregistrement avant d'être vérifiés (laisse le temps au serveur de démarrer)
- Le proxy vérifie tous les serveurs toutes les 30 secondes (par défaut)
- Timeout de 5 secondes par requête de health check
- Si la réponse n'est pas un code 200, le serveur est automatiquement désenregistré
- Les erreurs de connexion (serveur arrêté, timeout) entraînent aussi le désenregistrement
Configuration MCP (Cursor / Claude Desktop)
Pour utiliser ce proxy comme serveur MCP, ajoutez la configuration suivante :
$3
Dans votre fichier
.cursor/mcp.json :`json
{
"mcpServers": {
"dynamic-proxy": {
"command": "npx",
"args": ["dynamic-self-register-proxy"],
"env": {
"PROXY_PORT": "3000"
}
}
}
}
`$3
Dans votre fichier de configuration Claude Desktop (
claude_desktop_config.json) :`json
{
"mcpServers": {
"dynamic-proxy": {
"command": "npx",
"args": ["dynamic-self-register-proxy"],
"env": {
"PROXY_PORT": "3000"
}
}
}
}
`$3
`json
{
"mcpServers": {
"dynamic-proxy": {
"command": "npx",
"args": ["dynamic-self-register-proxy"],
"env": {
"PROXY_NAME": "MCP Gateway",
"PROXY_PORT": "8080",
"HEALTH_CHECK_INTERVAL": "60000",
"HEALTH_CHECK_TIMEOUT": "10000",
"HEALTH_CHECK_GRACE_PERIOD": "120000"
}
}
}
}
`Configuration
Le proxy charge automatiquement le fichier
.env s'il existe (voir .env.example pour un template).$3
| Variable | Défaut | Description |
|----------|--------|-------------|
|
PROXY_NAME | Proxy Server | Nom affiché sur la page d'accueil |
| PROXY_PORT | 3000 | Port d'écoute du proxy |
| HEALTH_CHECK_INTERVAL | 30000 | Intervalle du health check polling (ms) |
| HEALTH_CHECK_TIMEOUT | 5000 | Timeout pour chaque health check (ms) |
| HEALTH_CHECK_GRACE_PERIOD | 60000 | Période de grâce pour les nouveaux serveurs (ms) |$3
| Variable | Défaut | Description |
|----------|--------|-------------|
|
PROXY_URL | http://localhost:3000 | URL du proxy (pour les apps) |
| APP_PATH | /example | Chemin de l'application |
| APP_NAME | Example App | Nom de l'application |Plage de ports
Par défaut, le proxy attribue des ports entre 4000 et 5000 (1000 ports disponibles).
Pour modifier cette plage, éditez
proxy.js :`javascript
const INTERNAL_PORT_START = 4000;
const INTERNAL_PORT_END = 5000;
`Fonctionnalités
- Attribution sécurisée des ports : utilisation d'un mutex pour éviter les conflits lors d'enregistrements simultanés
- Période de grâce : les nouveaux serveurs ne sont pas vérifiés immédiatement, leur laissant le temps de démarrer
- Négociation de contenu : l'URL racine
/ retourne HTML pour les navigateurs, JSON pour les API
- Health check automatique : désenregistrement automatique des serveurs non répondants📝 Logs et Débogage
Le serveur enregistre ses activités (requêtes, erreurs, enregistrements) dans un fichier de log persistant :
- Windows :
C:\var\log\proxy-server\server.log
- Linux/Mac : /var/log/proxy-server/server.logLe format des logs inclut la date, l'heure, le PID et le tag
[PROXY].Limitations
- Les routes sont stockées en mémoire (perdues au redémarrage du proxy)
- Pas de persistance des enregistrements
- Pas d'authentification sur l'API de registration
- Les applications doivent implémenter
GET /proxy/health` pour ne pas être désenregistrées automatiquementISC