mirror of
				https://github.com/therootcompany/greenlock-express.js.git
				synced 2024-11-16 17:28:59 +00:00 
			
		
		
		
	example server: add proxy and wildcard support
This commit is contained in:
		
							parent
							
								
									4d400a9828
								
							
						
					
					
						commit
						ada2b9ccfe
					
				
							
								
								
									
										13
									
								
								config.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								config.js
									
									
									
									
									
								
							| @ -5,5 +5,16 @@ module.exports = { | |||||||
| 	email: "jon.doe@example.com", | 	email: "jon.doe@example.com", | ||||||
| 	configDir: path.join(__dirname, "acme"), | 	configDir: path.join(__dirname, "acme"), | ||||||
| 	srv: "/srv/www/", | 	srv: "/srv/www/", | ||||||
| 	api: "/srv/api/" | 	api: "/srv/api/", | ||||||
|  | 	proxy: { | ||||||
|  | 		"example.com": "http://localhost:4080", | ||||||
|  | 		"*.example.com": "http://localhost:4080" | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	// DNS-01 challenges only
 | ||||||
|  | 	challenges: { | ||||||
|  | 		"*.example.com": require("acme-dns-01-YOUR_DNS_HOST").create({ | ||||||
|  | 			token: "xxxx" | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										77
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										77
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -4,16 +4,16 @@ | |||||||
| 	"lockfileVersion": 1, | 	"lockfileVersion": 1, | ||||||
| 	"requires": true, | 	"requires": true, | ||||||
| 	"dependencies": { | 	"dependencies": { | ||||||
| 		"@coolaj86/urequest": { |  | ||||||
| 			"version": "1.3.7", |  | ||||||
| 			"resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.7.tgz", |  | ||||||
| 			"integrity": "sha512-PPrVYra9aWvZjSCKl/x1pJ9ZpXda1652oJrPBYy5rQumJJMkmTBN3ux+sK2xAUwVvv2wnewDlaQaHLxLwSHnIA==" |  | ||||||
| 		}, |  | ||||||
| 		"@root/mkdirp": { | 		"@root/mkdirp": { | ||||||
| 			"version": "1.0.0", | 			"version": "1.0.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", | 			"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", | ||||||
| 			"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" | 			"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" | ||||||
| 		}, | 		}, | ||||||
|  | 		"@root/request": { | ||||||
|  | 			"version": "1.3.11", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz", | ||||||
|  | 			"integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw==" | ||||||
|  | 		}, | ||||||
| 		"accepts": { | 		"accepts": { | ||||||
| 			"version": "1.3.5", | 			"version": "1.3.5", | ||||||
| 			"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", | 			"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", | ||||||
| @ -38,12 +38,12 @@ | |||||||
| 			"integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w==" | 			"integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w==" | ||||||
| 		}, | 		}, | ||||||
| 		"acme-v2": { | 		"acme-v2": { | ||||||
| 			"version": "1.7.7", | 			"version": "1.8.2", | ||||||
| 			"resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.7.7.tgz", | 			"resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.8.2.tgz", | ||||||
| 			"integrity": "sha512-Pg0EQ45h8N2e4K2goYedutCgWxAmtcruwDHr6hgPBgAWEORVb5SQEdXjtEhCrn+APtr7MyFPryyzXpYpDD5ecA==", | 			"integrity": "sha512-uYGA+DuTnA44EsGXE413XnbTotGHCzkucXjMk23QRwGnaGlnr0lNBoYjByyeIVLSzj0W6Y9FqA9h+15+H+ltMw==", | ||||||
| 			"requires": { | 			"requires": { | ||||||
| 				"@coolaj86/urequest": "^1.3.6", | 				"@root/request": "^1.3.11", | ||||||
| 				"rsa-compat": "^2.0.6" | 				"rsa-compat": "^2.0.8" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| 		"array-flatten": { | 		"array-flatten": { | ||||||
| @ -175,6 +175,12 @@ | |||||||
| 			"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", | 			"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", | ||||||
| 			"dev": true | 			"dev": true | ||||||
| 		}, | 		}, | ||||||
|  | 		"eventemitter3": { | ||||||
|  | 			"version": "3.1.2", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", | ||||||
|  | 			"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", | ||||||
|  | 			"dev": true | ||||||
|  | 		}, | ||||||
| 		"express": { | 		"express": { | ||||||
| 			"version": "4.16.4", | 			"version": "4.16.4", | ||||||
| 			"resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", | 			"resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", | ||||||
| @ -237,6 +243,32 @@ | |||||||
| 				"unpipe": "~1.0.0" | 				"unpipe": "~1.0.0" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"follow-redirects": { | ||||||
|  | 			"version": "1.7.0", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", | ||||||
|  | 			"integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", | ||||||
|  | 			"dev": true, | ||||||
|  | 			"requires": { | ||||||
|  | 				"debug": "^3.2.6" | ||||||
|  | 			}, | ||||||
|  | 			"dependencies": { | ||||||
|  | 				"debug": { | ||||||
|  | 					"version": "3.2.6", | ||||||
|  | 					"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", | ||||||
|  | 					"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", | ||||||
|  | 					"dev": true, | ||||||
|  | 					"requires": { | ||||||
|  | 						"ms": "^2.1.1" | ||||||
|  | 					} | ||||||
|  | 				}, | ||||||
|  | 				"ms": { | ||||||
|  | 					"version": "2.1.2", | ||||||
|  | 					"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||||||
|  | 					"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", | ||||||
|  | 					"dev": true | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
| 		"forwarded": { | 		"forwarded": { | ||||||
| 			"version": "0.1.2", | 			"version": "0.1.2", | ||||||
| 			"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", | 			"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", | ||||||
| @ -250,13 +282,13 @@ | |||||||
| 			"dev": true | 			"dev": true | ||||||
| 		}, | 		}, | ||||||
| 		"greenlock": { | 		"greenlock": { | ||||||
| 			"version": "2.7.24", | 			"version": "2.8.2", | ||||||
| 			"resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.7.24.tgz", | 			"resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.8.2.tgz", | ||||||
| 			"integrity": "sha512-GQb2LMF6IiEzhp01F6eIN7HlPVlUWpWsBZZn7DOIo9upFAWhFpn2w1PStjGb17VmTkg+lgxzcajqcy6AJhCHUQ==", | 			"integrity": "sha512-pCAYjgVova1ZoUHhuCfIw/3Rs5tE6DK1YF2LI7Cyh15QFBZJNU7pngMvDfeFft3It4WqnHezNgyDWAeV2pWFaw==", | ||||||
| 			"requires": { | 			"requires": { | ||||||
| 				"acme": "^1.3.0", | 				"acme": "^1.3.0", | ||||||
| 				"acme-dns-01-cli": "^3.0.0", | 				"acme-dns-01-cli": "^3.0.0", | ||||||
| 				"acme-v2": "^1.7.7", | 				"acme-v2": "^1.8.1", | ||||||
| 				"cert-info": "^1.5.1", | 				"cert-info": "^1.5.1", | ||||||
| 				"greenlock-store-fs": "^3.0.2", | 				"greenlock-store-fs": "^3.0.2", | ||||||
| 				"keypairs": "^1.2.14", | 				"keypairs": "^1.2.14", | ||||||
| @ -287,6 +319,17 @@ | |||||||
| 				"statuses": ">= 1.4.0 < 2" | 				"statuses": ">= 1.4.0 < 2" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"http-proxy": { | ||||||
|  | 			"version": "1.17.0", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", | ||||||
|  | 			"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", | ||||||
|  | 			"dev": true, | ||||||
|  | 			"requires": { | ||||||
|  | 				"eventemitter3": "^3.0.0", | ||||||
|  | 				"follow-redirects": "^1.0.0", | ||||||
|  | 				"requires-port": "^1.0.0" | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
| 		"iconv-lite": { | 		"iconv-lite": { | ||||||
| 			"version": "0.4.23", | 			"version": "0.4.23", | ||||||
| 			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", | 			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", | ||||||
| @ -467,6 +510,12 @@ | |||||||
| 				"escape-html": "^1.0.3" | 				"escape-html": "^1.0.3" | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"requires-port": { | ||||||
|  | 			"version": "1.0.0", | ||||||
|  | 			"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", | ||||||
|  | 			"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", | ||||||
|  | 			"dev": true | ||||||
|  | 		}, | ||||||
| 		"rsa-compat": { | 		"rsa-compat": { | ||||||
| 			"version": "2.0.8", | 			"version": "2.0.8", | ||||||
| 			"resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz", | 			"resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz", | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
| 		"example": "examples" | 		"example": "examples" | ||||||
| 	}, | 	}, | ||||||
| 	"dependencies": { | 	"dependencies": { | ||||||
| 		"greenlock": "^2.7.24", | 		"greenlock": "^2.8.2", | ||||||
| 		"redirect-https": "^1.1.5" | 		"redirect-https": "^1.1.5" | ||||||
| 	}, | 	}, | ||||||
| 	"files": [ | 	"files": [ | ||||||
| @ -18,6 +18,7 @@ | |||||||
| 		"spdy": "^3.4.7" | 		"spdy": "^3.4.7" | ||||||
| 	}, | 	}, | ||||||
| 	"devDependencies": { | 	"devDependencies": { | ||||||
|  | 		"http-proxy": "^1.17.0", | ||||||
| 		"express": "^4.16.3", | 		"express": "^4.16.3", | ||||||
| 		"express-basic-auth": "^1.2.0", | 		"express-basic-auth": "^1.2.0", | ||||||
| 		"finalhandler": "^1.1.1", | 		"finalhandler": "^1.1.1", | ||||||
|  | |||||||
							
								
								
									
										124
									
								
								server.js
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								server.js
									
									
									
									
									
								
							| @ -58,6 +58,31 @@ if (require.main === module) { | |||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function matchConfig(thing, domain) { | ||||||
|  | 	if (!thing) { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	if (thing[domain]) { | ||||||
|  | 		return domain; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var keys = Object.keys(thing); | ||||||
|  | 	var result = null; | ||||||
|  | 	keys.some(function(k) { | ||||||
|  | 		if ("*" !== k[0]) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// "foo.whatever.com".endsWith("*.whatever.com".slice(1))
 | ||||||
|  | 		if (domain.endsWith(k.slice(1).toLowerCase())) { | ||||||
|  | 			result = k; | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function myApproveDomains(opts) { | function myApproveDomains(opts) { | ||||||
| 	console.info("SNI:", opts.domain); | 	console.info("SNI:", opts.domain); | ||||||
| 	// In this example the filesystem is our "database".
 | 	// In this example the filesystem is our "database".
 | ||||||
| @ -67,6 +92,52 @@ function myApproveDomains(opts) { | |||||||
| 	var domains = []; | 	var domains = []; | ||||||
| 	var original = opts.domain; | 	var original = opts.domain; | ||||||
| 	var bare = original.replace(/^(www|api)\./, ""); | 	var bare = original.replace(/^(www|api)\./, ""); | ||||||
|  | 	var challenger = matchConfig(config.challenges, original); | ||||||
|  | 	if (challenger) { | ||||||
|  | 		opts.challenges = { | ||||||
|  | 			"dns-01": config.challenges[challenger] | ||||||
|  | 		}; | ||||||
|  | 		domains.push(challenger); | ||||||
|  | 		return approveThem(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (matchConfig(config.proxy, original)) { | ||||||
|  | 		console.log("debug: found proxy for", original); | ||||||
|  | 		domains.push(original); | ||||||
|  | 		return approveThem(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	function approveThem() { | ||||||
|  | 		console.info("Approved domains:", domains); | ||||||
|  | 		opts.domains = domains; | ||||||
|  | 		//opts.email = email;
 | ||||||
|  | 		opts.agreeTos = true; | ||||||
|  | 		// pick the shortest (bare) or latest (www. instead of api.) to be the subject
 | ||||||
|  | 		opts.subject = opts.domains.sort(function(a, b) { | ||||||
|  | 			var len = a.length - b.length; | ||||||
|  | 			if (0 !== len) { | ||||||
|  | 				return len; | ||||||
|  | 			} | ||||||
|  | 			if (a < b) { | ||||||
|  | 				return 1; | ||||||
|  | 			} else { | ||||||
|  | 				return -1; | ||||||
|  | 			} | ||||||
|  | 		})[0]; | ||||||
|  | 
 | ||||||
|  | 		if (!opts.challenges) { | ||||||
|  | 			opts.challenges = {}; | ||||||
|  | 		} | ||||||
|  | 		opts.challenges["http-01"] = require("le-challenge-fs"); | ||||||
|  | 		//opts.challenges['dns-01'] = require('le-challenge-dns');
 | ||||||
|  | 
 | ||||||
|  | 		// explicitly set account id and certificate.id
 | ||||||
|  | 		opts.account = { id: opts.email }; | ||||||
|  | 		opts.certificate = { id: opts.subject }; | ||||||
|  | 
 | ||||||
|  | 		return Promise.resolve(opts); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// The goal here is to support both bare and www domains
 | 	// The goal here is to support both bare and www domains
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// dns:example.com + fs:www.example.com => both
 | 	// dns:example.com + fs:www.example.com => both
 | ||||||
| @ -77,7 +148,6 @@ function myApproveDomains(opts) { | |||||||
| 	//
 | 	//
 | ||||||
| 	// dns:example.com + fs:example.com => example.com
 | 	// dns:example.com + fs:example.com => example.com
 | ||||||
| 	// dns:www.example.com + fs:www.example.com => www.example.com
 | 	// dns:www.example.com + fs:www.example.com => www.example.com
 | ||||||
| 	//
 |  | ||||||
| 	return checkWwws(bare) | 	return checkWwws(bare) | ||||||
| 		.then(function(hostname) { | 		.then(function(hostname) { | ||||||
| 			// hostname is either example.com or www.example.com
 | 			// hostname is either example.com or www.example.com
 | ||||||
| @ -116,34 +186,7 @@ function myApproveDomains(opts) { | |||||||
| 				return Promise.reject(new Error("no bare, www., or api. domain matching '" + opts.domain + "'")); | 				return Promise.reject(new Error("no bare, www., or api. domain matching '" + opts.domain + "'")); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			console.info("Approved domains:", domains); | 			return approveThem(); | ||||||
| 			opts.domains = domains; |  | ||||||
| 			//opts.email = email;
 |  | ||||||
| 			opts.agreeTos = true; |  | ||||||
| 			// pick the shortest (bare) or latest (www. instead of api.) to be the subject
 |  | ||||||
| 			opts.subject = opts.domains.sort(function(a, b) { |  | ||||||
| 				var len = a.length - b.length; |  | ||||||
| 				if (0 !== len) { |  | ||||||
| 					return len; |  | ||||||
| 				} |  | ||||||
| 				if (a < b) { |  | ||||||
| 					return 1; |  | ||||||
| 				} else { |  | ||||||
| 					return -1; |  | ||||||
| 				} |  | ||||||
| 			})[0]; |  | ||||||
| 
 |  | ||||||
| 			if (!opts.challenges) { |  | ||||||
| 				opts.challenges = {}; |  | ||||||
| 			} |  | ||||||
| 			opts.challenges["http-01"] = require("le-challenge-fs"); |  | ||||||
| 			//opts.challenges['dns-01'] = require('le-challenge-dns');
 |  | ||||||
| 
 |  | ||||||
| 			// explicitly set account id and certificate.id
 |  | ||||||
| 			opts.account = { id: opts.email }; |  | ||||||
| 			opts.certificate = { id: opts.subject }; |  | ||||||
| 
 |  | ||||||
| 			return Promise.resolve(opts); |  | ||||||
| 		}); | 		}); | ||||||
| } | } | ||||||
| exports.myApproveDomains = myApproveDomains; | exports.myApproveDomains = myApproveDomains; | ||||||
| @ -213,12 +256,35 @@ function checkWwws(_hostname) { | |||||||
| } | } | ||||||
| exports.checkWwws = checkWwws; | exports.checkWwws = checkWwws; | ||||||
| 
 | 
 | ||||||
|  | var httpProxy = require("http-proxy"); | ||||||
|  | 
 | ||||||
|  | var proxy = httpProxy.createProxyServer({ | ||||||
|  | 	xfwd: true | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | proxy.on("error", function(req, res) { | ||||||
|  | 	res.statusCode = 500; | ||||||
|  | 	res.end("500: Server Error"); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| function myVhostApp(req, res) { | function myVhostApp(req, res) { | ||||||
| 	req.on("error", function(err) { | 	req.on("error", function(err) { | ||||||
| 		console.error("HTTPS Request Network Connection Error:"); | 		console.error("HTTPS Request Network Connection Error:"); | ||||||
| 		console.error(err); | 		console.error(err); | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
|  | 	// this is protected by greenlock-express from domain fronting attacks
 | ||||||
|  | 	var host = req.headers.host; | ||||||
|  | 	// ex: example.com
 | ||||||
|  | 	// ex: example.com:4080
 | ||||||
|  | 	console.log("debug: host is", host); | ||||||
|  | 	var domain = matchConfig(config.proxy, host); | ||||||
|  | 	if (domain) { | ||||||
|  | 		console.log("debug: forwarding to", config.proxy[domain]); | ||||||
|  | 		proxy.web(req, res, { target: config.proxy[domain] }); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// SECURITY greenlock pre-sanitizes hostnames to prevent unauthorized fs access so you don't have to
 | 	// SECURITY greenlock pre-sanitizes hostnames to prevent unauthorized fs access so you don't have to
 | ||||||
| 	// (also: only domains approved above will get here)
 | 	// (also: only domains approved above will get here)
 | ||||||
| 	console.info(""); | 	console.info(""); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user