- 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).
Binaries might be available someday.
If you have a Go setup:
$ go get github.com/myfreeweb/443d
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
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.
This is free and unencumbered software released into the public domain.
For more information, please refer to the
UNLICENSE file or unlicense.org.