Dynamic Subdomain Management & Automated SSL with Node.js and Certbot

Introduction
Managing multiple subdomains dynamically while keeping the URL unchanged is a common requirement for SaaS platforms, multi-tenant applications, and personal website builders. Additionally, allowing users to add their own custom domains with automatic SSL (HTTPS) certificates ensures security and trust.
In this guide, we will explore:
Dynamically mapping subdomains to specific paths using Node.js.
Handling user-provided custom domains and automatically issuing SSL certificates using Certbot.
Using a reverse proxy to serve the correct content without URL changes.
1. Subdomain Mapping Without Redirection
To keep the URL (nishi.hello.com) unchanged while serving content from (hello.com/nishi), we need a reverse proxy. Instead of using Nginx, we will handle everything in Node.js.
1.1 Install Dependencies
npm install express http-proxy-middleware
1.2 Implement Subdomain Handling in Express
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// Middleware to handle subdomains
app.use((req, res, next) => {
const host = req.hostname; // e.g., "nishi.hello.com"
const mainDomain = "hello.com";
if (host.endsWith(`.${mainDomain}`)) {
const subdomain = host.split('.')[0]; // Extract the subdomain
if (subdomain !== "www") {
return createProxyMiddleware({
target: `https://${mainDomain}`,
changeOrigin: true,
pathRewrite: { '^/$': `/${subdomain}` },
})(req, res, next);
}
}
next(); // Continue to default routes if no subdomain
});
// Default main domain route
app.get('/', (req, res) => {
res.send('Welcome to hello.com!');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
1.3 Configure Wildcard DNS
Add an A or CNAME record for *.hello.com pointing to your server.
2. Adding Custom Domains with SSL (HTTPS)
Now, let’s allow users to connect their own domains (userdomain.com) and issue SSL certificates automatically.
2.1 Install Certbot
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
2.2 Allow Node.js to Bind Ports 80 & 443
sudo setcap 'cap_net_bind_service=+ep' $(which node)
2.3 Implement Custom Domain Handling in Express
const express = require('express');
const { exec } = require('child_process');
const fs = require('fs');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use(express.json());
const domains = {}; // Store user domains and target mappings
// Route to allow users to add their own domains
app.post('/add-domain', (req, res) => {
const { domain, target } = req.body;
if (!domain || !target) {
return res.status(400).json({ error: "Domain and target are required." });
}
// Store domain mapping
domains[domain] = target;
// Run Certbot to generate SSL certificate
exec(`sudo certbot certonly --nginx -d ${domain} --non-interactive --agree-tos --email admin@${domain}`, (err, stdout, stderr) => {
if (err) {
console.error(`Error generating SSL: ${stderr}`);
return res.status(500).json({ error: "SSL setup failed." });
}
console.log(`SSL issued for ${domain}`);
res.json({ message: `Domain ${domain} added with SSL.` });
});
});
// Middleware to proxy custom domains
app.use((req, res, next) => {
const host = req.hostname; // Get requested domain
if (domains[host]) {
return createProxyMiddleware({
target: domains[host],
changeOrigin: true
})(req, res, next);
}
next();
});
// Start HTTPS Server
const https = require('https');
const options = {
key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/example.com/fullchain.pem'),
};
https.createServer(options, app).listen(443, () => {
console.log("Secure server running on port 443");
});
// Start HTTP server for Certbot challenges
app.listen(80, () => {
console.log("Server listening on port 80");
});
3. Testing the Setup
3.1 Adding a Custom Domain
Users can add their domain via API:
curl -X POST http://yourserver.com/add-domain \
-H "Content-Type: application/json" \
-d '{"domain": "userdomain.com", "target": "https://example.com/user"}'
✔️ userdomain.com will now load example.com/user
✔️ HTTPS is automatically enabled
3.2 Verify DNS
Before adding a domain, users must point their domain to your server:
nslookup userdomain.com
Ensure it resolves to your server’s IP.
4. Automating SSL Renewal
Let’s Encrypt certificates expire every 90 days. Set up auto-renewal:
sudo crontab -e
Add:
0 0 * * * certbot renew --quiet
This renews SSL daily at midnight.
5. Additional Enhancements
✅ Database Storage: Store user domains in a database instead of an object.
✅ Authentication: Require API keys or user authentication.
✅ Load Balancing: Use Cloudflare or AWS Load Balancer for better scaling.
Conclusion
🎯 Now, we have a fully dynamic subdomain and custom domain management system in Node.js!
🚀 Users can add their domains, get SSL automatically, and have their domain proxy to the correct content.
🔐 Certbot handles HTTPS security without manual intervention.
This setup is perfect for multi-tenant apps, SaaS platforms, and website builders. Want to improve it further? Let me know in the comments! 🚀



