A standard for webservers that's just right.
Go to file
AJ ONeal 983a6e2cd7 more descriptive error message 2017-08-03 15:56:19 -06:00
Library/LaunchDaemons scope node, npm, and module installs to /opt/goldilocks 2017-05-15 23:34:30 -05:00
admin/public misc small fixes 2017-06-23 17:47:04 -06:00
bin exposed a loopback test route in the api 2017-06-26 11:34:42 -06:00
etc added tunnel server 2017-06-14 10:58:56 -06:00
lib more descriptive error message 2017-08-03 15:56:19 -06:00
packages preventing DNS lookup error from erroring the paywall detection 2017-07-17 16:28:34 -06:00
var more comprehensive data model 2017-03-02 00:58:45 -07:00
.gitignore added what was a submodule to .gitignore 2017-06-07 10:54:41 -06:00
.gitmodules remove submodule 2017-06-06 21:01:42 +00:00
.jshintrc add .jshintrc 2017-04-13 15:48:35 -06:00
LICENSE.txt update LICENSE.txt 2017-02-22 16:36:23 -07:00
README.md Update README.md 2017-07-28 13:03:29 -06:00
install.sh use npm from install 2017-07-21 15:40:27 -06:00
package-lock.json updated localhost certificates 2017-08-02 18:08:04 -06:00
package.json updated localhost certificates 2017-08-02 18:08:04 -06:00
terms.sh example of adding terms 2017-02-24 17:59:58 -07:00
test-chain.sh add --sites option for multiple domains #10 and use localhost.daplie.me 2017-02-01 15:52:14 -07:00
uninstall.sh scope node, npm, and module installs to /opt/goldilocks 2017-05-15 23:34:30 -05:00
update-packages.sh fixed issue updating packages on mac (no realpath) 2017-07-13 12:39:38 -06:00

README.md

Goldilocks

The node.js netserver that's just right.

  • HTTPS Web Server with Automatic TLS (SSL) via ACME (Let's Encrypt)
    • Static Web Server
    • URL Redirects
    • SSL on localhost (with bundled localhost.daplie.me certificates)
    • Uses node cluster to take advantage of multiple CPUs (in progress)
  • 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)
  • UPnP / NAT-PMP forwarding and loopback testing (in progress)
  • Configurable via API
  • mDNS Discoverable (configure in home or office with mobile and desktop apps)
  • OAuth3 Authentication

Install Standalone

# 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
goldilocks
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)
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)

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:

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:

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:

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:

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:

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:

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

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

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:

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:

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.

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