Goldilocks ========== The node.js netserver that's just right. * **HTTPS Web Server** with Automatic TLS (SSL) via ACME ([Let's Encrypt](https://letsencrypt.org)) * Static Web Server * URL Redirects * SSL on localhost (with bundled localhost.daplie.me certificates) * Uses node cluster to take advantage of multiple CPUs * **TLS** name-based (SNI) proxy * **TCP** port-based proxy * WS **Tunnel Server** (i.e. run on Digital Ocean and expose a home-firewalled Raspberry Pi to the Internet) * WS **Tunnel Client** (i.e. run on a Raspberry Pi and connect to a Daplie Tunnel) * Configurable via API * mDNS Discoverable (configure in home or office with mobile and desktop apps) * OAuth3 Authentication Install Standalone ------- ```bash # v1 in npm npm install -g goldilocks # v1 in git (via ssh) npm install -g git+ssh://git@git.daplie.com:Daplie/goldilocks.js#v1 # v1 in git (unauthenticated) npm install -g git+https://git@git.daplie.com:Daplie/goldilocks.js#v1 ``` ```bash goldilocks ``` ```bash Serving /Users/foo/ at https://localhost.daplie.me:8443 ``` Install as a System Service (daemon-mode) We have service support for * systemd (Linux, Ubuntu) * launchd (macOS) ```bash curl https://git.daplie.com/Daplie/goldilocks.js/raw/master/install.sh | bash ``` Modules & Configuration ----- Goldilocks has several core systems, which all have their own configuration and some of which have modules: ``` * http - static - redirect - proxy (reverse proxy) * tls - acme - proxy (reverse proxy) * tcp - forward * tunnel_server * tunnel_client * mdns * api ``` ### http The HTTP system handles plain http (TLS / SSL is handled by the tls system) ```yml http: trust_proxy: true # allow localhost, 192.x, 10.x, 172.x, etc to set headers allow_insecure: false # allow non-https even without proxy https headers primary_domain: example.com # attempts to access via IP address will redirect here # modules can be nested in domains domains: - names: - example.com modules: - name: static root: /srv/www/:hostname # The configuration above could also be represented as follows: modules: - name: static domains: - example.com root: /srv/www/:hostname ``` ### http.static - how to serve a web page The static module is for serving static web pages and assets and has the following options: ``` root The path to serve as a string. The template variable `:hostname` represents the HTTP Host header without port information ex: `root: /srv/www/example.com` would load the example.com folder for any domain listed ex: `root: /srv/www/:hostname` would load `/srv/www/example.com` if so indicated by the Host header ``` Example config: ```yml http: modules: - name: static domains: - example.com root: /srv/www/:hostname ``` ### http.proxy - how to reverse proxy (ruby, python, etc) The proxy module is for reverse proxying, typically to an application on the same machine. It has the following options: ``` host The DNS-resolvable hostname (or IP address) of the system to which the request will be proxied ex: localhost ex: 192.168.1.100 port The port on said system to which the request will be proxied ex: 3000 ex: 80 ``` Example config: ```yml http: modules: - name: proxy domains: - example.com host: localhost port: 3000 ``` ### http.redirect - how to redirect URLs The redirect module is for, you guessed it, redirecting URLs. It has the following options: ``` status The HTTP status code to issue (301 is usual permanent redirect, 302 is temporary) ex: 301 from The URL path that was used in the request. The `*` wildcard character can be used for matching a full segment of the path ex: /photos/ ex: /photos/*/*/ to The new URL path which should be used. If wildcards matches were used they will be available as `:1`, `:2`, etc. ex: /pics/ ex: /pics/:1/:2/ ``` Example config: ```yml http: modules: - name: proxy domains: - example.com status: 301 from: /archives/*/*/*/ to: https://example.net/year/:1/month/:2/day/:3/ ``` ### tls The tls system handles encrypted connections, including fetching certificates, and uses ServerName Indication (SNI) to determine if the connection should be handled by the http system, a tls system module, or rejected. It has the following options: ``` acme.email The default email address for ACME certificate issuance ex: john.doe@example.com acme.server The default ACME server to use ex: https://acme-v01.api.letsencrypt.org/directory ex: https://acme-staging.api.letsencrypt.org/directory acme.challenge_type The default ACME challenge to request ex: http-01, dns-01, tls-01 acme.approved_domains The domains for which to request certificates ex: example.com ``` Example config: ```yml tls: acme: email: 'joe.shmoe@example.com' # IMPORTANT: Switch to in production 'https://acme-v01.api.letsencrypt.org/directory' server: 'https://acme-staging.api.letsencrypt.org/directory' challenge_type: 'http-01' approved_domains: - example.com - example.net modules: - name: proxy domains: - example.com - example.net address: '127.0.0.1:6443' ``` Certificates are saved to `~/acme`, which may be `/var/www/acme` if Goldilocks is run as the www-data user. ### tls.acme The acme module overrides the acme defaults of the tls system and uses the same options except that `approved_domains` (in favor of the domains in the scope of the module). Example config: ```yml tls: modules: - name: acme domains: - example.com - example.net email: 'joe.shmoe@example.com' server: 'https://acme-staging.api.letsencrypt.org/directory' challenge_type: 'http-01' ``` ### tls.proxy The proxy module routes the traffic based on the ServerName Indication (SNI) **without decrypting** it. It has the following options: ``` address The hostname (or IP) and port of the system or application that should receive the traffic ``` Example config: ```yml tls: modules: - name: proxy domains: - example.com address: '127.0.0.1:5443' ``` ### tcp The tcp system handles all tcp network traffic **before decryption** and may use port numbers or traffic sniffing to determine how the connection should be handled. It has the following options: ``` bind An array of numeric ports on which to bind ex: 80 ``` Example Config ```yml tcp: bind: - 22 - 80 - 443 modules: - name: forward ports: - 22 address: '127.0.0.1:2222' ``` ### tcp.forward The forward module routes traffic based on port number **without decrypting** it. It has the following options: ``` ports A numeric array of source ports ex: 22 address The destination hostname and port ex: 127.0.0.1:2222 ``` Example Config ```yml tcp: bind: - 22 - 80 - 443 modules: - name: forward ports: - 22 address: '127.0.0.1:2222' ``` ### tunnel\_server The tunnel server system is meant to be run on a publicly accessible IP address to server tunnel clients which are behind firewalls, carrier-grade NAT, or otherwise Internet-connect but inaccessible devices. It has the following options: ``` secret A 128-bit or greater string to use for signing tokens (HMAC JWT) ex: abc123 servernames An array of string servernames that should be captured as the tunnel server, ignoring the TLS forward module ex: api.tunnel.example.com ``` Example config: ```yml tunnel_server: secret: abc123def456ghi789 servernames: - 'api.tunnel.example.com' ``` ### tunnel The tunnel client is meant to be run from behind a firewalls, carrier-grade NAT, or otherwise inaccessible devices to allow them to be accessed publicly on the internet. It has no options per se, but is rather a list of tokens that can be used to connect to tunnel servers. If the token does not have an `aud` field it must be provided in an object with the token provided in the `jwt` field and the tunnel server url provided in the `tunnelUrl` field. Example config: ```yml tunnel: - 'some.jwt_encoded.token' - jwt: 'other.jwt_encoded.token' tunnelUrl: 'wss://api.tunnel.example.com/' ``` ### ddns TODO ### mdns enabled by default Although it does not announce itself, Goldilocks is discoverable via mDNS with the special query `_cloud._tcp.local`. This is so that it can be easily configured via Desktop and Mobile apps when run on devices such as a Raspberry Pi or SOHO servers. ```yaml mdns: disabled: false port: 5353 broadcast: '224.0.0.251' ttl: 300 ``` You can discover goldilocks with `mdig`. ``` npm install -g git+https://git.daplie.com/Daplie/mdig.git mdig _cloud._tcp.local ``` ### api The API system is intended for use with Desktop and Mobile clients. It must be accessed using one of the following domains as the Host header: ``` admin.invalid localhost.admin.daplie.me ``` @tigerbot: How are the APIs used (in terms of URL, Method, Headers, etc)? TODO ---- * http - nowww module * http - Allow match styles of `www.*`, `*`, and `*.example.com` equally * http - redirect based on domain name (not just path) * tcp - bind should be able to specify localhost, uniquelocal, private, or ip * tcp - if destination host is omitted default to localhost, if dst port is missing, default to src * sys - handle SIGHUP * sys - `curl https://daplie.me/goldilocks | bash -s example.com` * oauth3 - `example.com/.well-known/domains@oauth3.org/directives.json` * oauth3 - commandline questionnaire * modules - use consistent conventions (i.e. address vs host + port) * tls - tls.acme vs tls.modules.acme * tls - forward should be able to match on source port to reach different destination ports