Skip to content
TLS with HTTP/2 proxying, demultiplexed with SSH, on your port 443
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
demux
keepalive
noop
unixsock
util
.gitignore
443d.go
CODE_OF_CONDUCT.md
COPYING
README.md
UNLICENSE
backend.go

README.md

443d unlicense

This is

  • a reverse HTTP(S) proxy
  • written in Go
  • that proxies to HTTP/1.1 via TCP or UNIX Domain Sockets,
  • runs CGI apps (because cgit is great),
  • serves static files,
  • supports HTTP/2 over TLS, like nghttpx
  • and does TLS/SSH demultiplexing, like sslh.

Basically, it's an nginx replacement for websites that don't need advanced load balancing or request modification, but would like good security, easy configuration and deployment (single static binary, thanks to Go).

It's rather small and simple, so it has the following limitations:

  • no support for different certificates per domain via SNI (TODO go-vhost);
  • no websockets (TODO?);
  • no configuration reloading;
  • no markdown, no templating, no built-in git pulling, no basic auth, etc. (by design -- try Caddy instead).

Also, it uses Go's TLS library, which currently doesn't support the chacha20-poly1305 ciphersuite. On the other hand, it's a modern, clean library, not a pile of legacy C code (not even a cleaned-up pile of legacy C code).

Installation

Binaries might be available someday.

If you have a Go setup:

$ go get github.com/myfreeweb/443d

Usage

You need to write a simple configuration file. The syntax is YAML. Here's an example:

tls: # 443d will serve TLS there
  listen: :443 # IPv6 will magically work too
  ssh: 127.0.0.1:22 # When 443d sees an SSH connection instead of TLS, proxy there
  cert: /etc/certs/server.crt
  key: /etc/certs/server.key
  hsts: # Add the Strict-Transport-Security header
    seconds: 31536000 # max-age
    subdomains: true # includeSubdomains
  hpkp: # Add the Public-Key-Pins header
    seconds: 5184000 # max-age
    subdomains: true # includeSubdomains
    backup_keys: # You must have at least one hash here!
      - aaaogjIWd0KuaCsQa9Zon7aTON0JapN1fonHra2bdGk=

http: # 443d will serve non-TLS HTTP there
  # (for debugging or to provide access through a Tor hidden service)
  listen: 127.0.0.1:8080

redirector: # 443d will serve 301 redirects to HTTPS there
  listen: :80

hosts: # 443d will proxy to the following virtual hosts
  - hostnames: ["*.example.com", "example.com", "example.com:*"] # Host header matching
      # (supports glob patterns; if there's a port in the header, it's not removed automatically)
    paths: # URL path prefix matching for this hostname, longer prefixes are matched first
      /git/: # The ending slash is important!!!
        - type: unix # default is http
          address: /var/run/gitweb/gitweb.sock # format depends on the type
          cut_path: true # means the backend will see /git as /, /git/path as /path, etc. default is false
      /cgit/:
        - type: cgi
          exec: /usr/local/www/cgit/cgit.cgi
          cut_path: true # means the backend will see /git as /, /git/path as /path, etc. default is false
          # configure cgit: virtual-root=/cgit/ css=/cgit/cgit.css logo=/cgit/cgit.png
      /static/:
        - type: file
          address: /var/www/static
      /:
        # You can have multiple backends, requests will be load-balanced randomly
        - address: localhost:8080
        - address: localhost:8081
        - address: localhost:8082

defaulthost: example.com # Where to proxy when no Host header is sent

Now run the binary:

$ 443d -config="/usr/local/etc/443d.yaml"

Use supervisord or something like that to run in production, it does not daemonize itself & logs to stderr.

Do not run as root, instead...

  • FreeBSD: Use mac_portacl(4) to allow the 443d user to bind to port 80 and 443. e.g. uid 80 (user www):
$ kldload mac_portacl && echo 'mac_portacl_load="YES"' >>/boot/loader.conf
$ echo >>/etc/sysctl.conf 'security.mac.portacl.rules="uid:80:tcp:80,uid:80:tcp:443"
net.inet.ip.portrange.reservedhigh=0'
$ service sysctl reload
  • Linux: allow it to bind to low port numbers: setcap 'cap_net_bind_service=+ep' $(which 443d)
  • anywhere: run on a different port and redirect ports in the firewall

You can make a chroot for it easily, you only need /dev/urandom.

Contributing

Please feel free to submit pull requests! Bugfixes and simple non-breaking improvements will be accepted without any questions :-)

By participating in this project you agree to follow the Contributor Code of Conduct.

License

This is free and unencumbered software released into the public domain.
For more information, please refer to the UNLICENSE file or unlicense.org.

You can’t perform that action at this time.