diff --git a/README.md b/README.md
index 41e5cf8..774094e 100644
--- a/README.md
+++ b/README.md
@@ -24,431 +24,18 @@ systemd support, transparent proxying,
chroot, logging, IPv4 and IPv6, a fork-based and a
select-based model, and more.
+Install
+=======
-Compile and install
-===================
-
-Dependencies
-------------
-
-`sslh` uses [libconfig](http://www.hyperrealm.com/libconfig/)
-and [libwrap](http://packages.debian.org/source/unstable/tcp-wrappers).
-
-For Debian, these are contained in packages `libwrap0-dev` and
-`libconfig8-dev`.
-
-For OpenSUSE, these are contained in packages libconfig9 and
-libconfig-dev in repository
-
-
-For Fedora, you'll need packages `libconfig` and
-`libconfig-devel`:
-
- yum install libconfig libconfig-devel
-
-If you can't find `libconfig`, or just don't want a
-configuration file, set `USELIBCONFIG=` in the Makefile.
-
-If you want to rebuild `sslh-conf.c` (after a `make
-distclean` for example), you will also need to add
-[conf2struct](https://www.rutschle.net/tech/conf2struct/README.html)
-to your path.
-
-Compilation
------------
-
-After this, the Makefile should work:
-
- make install
-
-There are a couple of configuration options at the beginning
-of the Makefile:
-
-* `USELIBWRAP` compiles support for host access control (see
- `hosts_access(3)`), you will need `libwrap` headers and
- library to compile (`libwrap0-dev` in Debian).
-
-* `USELIBCONFIG` compiles support for the configuration
- file. You will need `libconfig` headers to compile
- (`libconfig8-dev` in Debian).
-
-* `USESYSTEMD` compiles support for using systemd socket activation.
- You will need `systemd` headers to compile (`systemd-devel` in Fedora).
-
-Binaries
---------
-
-The Makefile produces two different executables: `sslh-fork`
-and `sslh-select`:
-
-* `sslh-fork` forks a new process for each incoming connection.
-It is well-tested and very reliable, but incurs the overhead
-of many processes.
-If you are going to use `sslh` for a "small" setup (less than
-a dozen ssh connections and a low-traffic https server) then
-`sslh-fork` is probably more suited for you.
-
-* `sslh-select` uses only one thread, which monitors all connections
-at once. It is more recent and less tested, but only incurs a 16
-byte overhead per connection. Also, if it stops, you'll lose all
-connections, which means you can't upgrade it remotely.
-If you are going to use `sslh` on a "medium" setup (a few thousand ssh
-connections, and another few thousand ssl connections),
-`sslh-select` will be better.
-
-If you have a very large site (tens of thousands of connections),
-you'll need a vapourware version that would use libevent or
-something like that.
-
-
-Installation
-------------
-
-* In general:
-
- make
- cp sslh-fork /usr/local/sbin/sslh
- cp basic.cfg /etc/sslh.cfg
- vi /etc/sslh.cfg
-
-* For Debian:
-
- cp scripts/etc.init.d.sslh /etc/init.d/sslh
-
-* For CentOS:
-
- cp scripts/etc.rc.d.init.d.sslh.centos /etc/rc.d/init.d/sslh
-
-
-You might need to create links in /etc/rc.d so that the server
-start automatically at boot-up, e.g. under Debian:
-
- update-rc.d sslh defaults
+Please refer to the [install guide](doc/INSTALL.md).
Configuration
=============
-If you use the scripts provided, sslh will get its
-configuration from /etc/sslh.cfg. Please refer to
-example.cfg for an overview of all the settings.
+Please refer to the [configuration guide](doc/config.md).
-A good scheme is to use the external name of the machine in
-`listen`, and bind `httpd` to `localhost:443` (instead of all
-binding to all interfaces): that way, HTTPS connections
-coming from inside your network don't need to go through
-`sslh`, and `sslh` is only there as a frontal for connections
-coming from the internet.
-Note that 'external name' in this context refers to the
-actual IP address of the machine as seen from your network,
-i.e. that that is not `127.0.0.1` in the output of
-`ifconfig(8)`.
-
-Libwrap support
----------------
-
-Sslh can optionally perform `libwrap` checks for the sshd
-service: because the connection to `sshd` will be coming
-locally from `sslh`, `sshd` cannot determine the IP of the
-client.
-
-OpenVPN support
----------------
-
-OpenVPN clients connecting to OpenVPN running with
-`-port-share` reportedly take more than one second between
-the time the TCP connection is established and the time they
-send the first data packet. This results in `sslh` with
-default settings timing out and assuming an SSH connection.
-To support OpenVPN connections reliably, it is necessary to
-increase `sslh`'s timeout to 5 seconds.
-
-Instead of using OpenVPN's port sharing, it is more reliable
-to use `sslh`'s `--openvpn` option to get `sslh` to do the
-port sharing.
-
-Using proxytunnel with sslh
----------------------------
-
-If you are connecting through a proxy that checks that the
-outgoing connection really is SSL and rejects SSH, you can
-encapsulate all your traffic in SSL using `proxytunnel` (this
-should work with `corkscrew` as well). On the server side you
-receive the traffic with `stunnel` to decapsulate SSL, then
-pipe through `sslh` to switch HTTP on one side and SSL on the
-other.
-
-In that case, you end up with something like this:
-
- ssh -> proxytunnel -e ----[ssh/ssl]---> stunnel ---[ssh]---> sslh --> sshd
- Web browser -------------[http/ssl]---> stunnel ---[http]--> sslh --> httpd
-
-Configuration goes like this on the server side, using `stunnel3`:
-
- stunnel -f -p mycert.pem -d thelonious:443 -l /usr/local/sbin/sslh -- \
- sslh -i --http localhost:80 --ssh localhost:22
-
-* stunnel options:
- * `-f` for foreground/debugging
- * `-p` for specifying the key and certificate
- * `-d` for specifying which interface and port
- we're listening to for incoming connexions
- * `-l` summons `sslh` in inetd mode.
-
-* sslh options:
- * `-i` for inetd mode
- * `--http` to forward HTTP connexions to port 80,
- and SSH connexions to port 22.
-
-Capabilities support
---------------------
-
-On Linux (only?), you can compile sslh with `USELIBCAP=1` to
-make use of POSIX capabilities; this will save the required
-capabilities needed for transparent proxying for unprivileged
-processes.
-
-Alternatively, you may use filesystem capabilities instead
-of starting sslh as root and asking it to drop privileges.
-You will need `CAP_NET_BIND_SERVICE` for listening on port 443
-and `CAP_NET_ADMIN` for transparent proxying (see
-`capabilities(7)`).
-
-You can use the `setcap(8)` utility to give these capabilities
-to the executable:
-
- sudo setcap cap_net_bind_service,cap_net_admin+pe sslh-select
-
-Then you can run sslh-select as an unpriviledged user, e.g.:
-
- sslh-select -p myname:443 --ssh localhost:22 --ssl localhost:443
-
-Caveat: `CAP_NET_ADMIN` does give sslh too many rights, e.g.
-configuring the interface. If you're not going to use
-transparent proxying, just don't use it (or use the libcap method).
-
-Transparent proxy support
--------------------------
-
-On Linux and FreeBSD you can use the `--transparent` option to
-request transparent proxying. This means services behind `sslh`
-(Apache, `sshd` and so on) will see the external IP and ports
-as if the external world connected directly to them. This
-simplifies IP-based access control (or makes it possible at
-all).
-
-Linux:
-
-`sslh` needs extended rights to perform this: you'll need to
-give it `CAP_NET_ADMIN` capabilities (see appropriate chapter)
-or run it as root (but don't do that).
-
-The firewalling tables also need to be adjusted as follows.
-I don't think it is possible to have `httpd` and `sslh` both listen to 443 in
-this scheme -- let me know if you manage that:
-
- # Set route_localnet = 1 on all interfaces so that ssl can use "localhost" as destination
- sysctl -w net.ipv4.conf.default.route_localnet=1
- sysctl -w net.ipv4.conf.all.route_localnet=1
-
- # DROP martian packets as they would have been if route_localnet was zero
- # Note: packets not leaving the server aren't affected by this, thus sslh will still work
- iptables -t raw -A PREROUTING ! -i lo -d 127.0.0.0/8 -j DROP
- iptables -t mangle -A POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP
-
- # Mark all connections made by ssl for special treatment (here sslh is run as user "sslh")
- iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
-
- # Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
- iptables -t mangle -A OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
-
- # Configure routing for those marked packets
- ip rule add fwmark 0x1 lookup 100
- ip route add local 0.0.0.0/0 dev lo table 100
-
-Tranparent proxying with IPv6 is similarly set up as follows:
-
- # Set route_localnet = 1 on all interfaces so that ssl can use "localhost" as destination
- # Not sure if this is needed for ipv6 though
- sysctl -w net.ipv4.conf.default.route_localnet=1
- sysctl -w net.ipv4.conf.all.route_localnet=1
-
- # DROP martian packets as they would have been if route_localnet was zero
- # Note: packets not leaving the server aren't affected by this, thus sslh will still work
- ip6tables -t raw -A PREROUTING ! -i lo -d ::1/128 -j DROP
- ip6tables -t mangle -A POSTROUTING ! -o lo -s ::1/128 -j DROP
-
- # Mark all connections made by ssl for special treatment (here sslh is run as user "sslh")
- ip6tables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
-
- # Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
- ip6tables -t mangle -A OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
-
- # Configure routing for those marked packets
- ip -6 rule add fwmark 0x1 lookup 100
- ip -6 route add local ::/0 dev lo table 100
-
-Explanation:
-To be able to use `localhost` as destination in your sslh config along with transparent proxying
-you have to allow routing of loopback addresses as done above.
-This is something you usually should not do (see [this stackoverflow post](https://serverfault.com/questions/656279/how-to-force-linux-to-accept-packet-with-loopback-ip/656484#656484))
-The two `DROP` iptables rules emulate the behaviour of `route_localnet` set to off (with one small difference:
-allowing the reroute-check to happen after the fwmark is set on packets destined for sslh).
-See [this diagram](https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg) for a good visualisation
-showing how packets will traverse the iptables chains.
-
-Note:
-You have to run `sslh` as dedicated user (in this example the user is also named `sslh`), to not mess up with your normal networking.
-These rules will allow you to connect directly to ssh on port
-22 (or to any other service behind sslh) as well as through sslh on port 443.
-
-Also remember that iptables configuration and ip routes and
-rules won't be necessarily persisted after you reboot. Make
-sure to save them properly. For example in CentOS7, you would
-do `iptables-save > /etc/sysconfig/iptables`, and add both
-`ip` commands to your `/etc/rc.local`.
-
-FreeBSD:
-
-Given you have no firewall defined yet, you can use the following configuration
-to have ipfw properly redirect traffic back to sslh
-
- /etc/rc.conf
- firewall_enable="YES"
- firewall_type="open"
- firewall_logif="YES"
- firewall_coscripts="/etc/ipfw/sslh.rules"
-
-
-/etc/ipfw/sslh.rules
-
- #! /bin/sh
-
- # ssl
- ipfw add 20000 fwd 192.0.2.1,443 log tcp from 192.0.2.1 8443 to any out
- ipfw add 20010 fwd 2001:db8::1,443 log tcp from 2001:db8::1 8443 to any out
-
- # ssh
- ipfw add 20100 fwd 192.0.2.1,443 log tcp from 192.0.2.1 8022 to any out
- ipfw add 20110 fwd 2001:db8::1,443 log tcp from 2001:db8::1 8022 to any out
-
- # xmpp
- ipfw add 20200 fwd 192.0.2.1,443 log tcp from 192.0.2.1 5222 to any out
- ipfw add 20210 fwd 2001:db8::1,443 log tcp from 2001:db8::1 5222 to any out
-
- # openvpn (running on other internal system)
- ipfw add 20300 fwd 192.0.2.1,443 log tcp from 198.51.100.7 1194 to any out
- ipfw add 20310 fwd 2001:db8::1,443 log tcp from 2001:db8:1::7 1194 to any out
-
-General notes:
-
-
-This will only work if `sslh` does not use any loopback
-addresses (no `127.0.0.1` or `localhost`), you'll need to use
-explicit IP addresses (or names):
-
- sslh --listen 192.168.0.1:443 --ssh 192.168.0.1:22 --ssl 192.168.0.1:4443
-
-This will not work:
-
- sslh --listen 192.168.0.1:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:4443
-
-Transparent proxying means the target server sees the real
-origin address, so it means if the client connects using
-IPv6, the server must also support IPv6. It is easy to
-support both IPv4 and IPv6 by configuring the server
-accordingly, and setting `sslh` to connect to a name that
-resolves to both IPv4 and IPv6, e.g.:
-
- sslh --transparent --listen :443 --ssh insideaddr:22
-
- /etc/hosts:
- 192.168.0.1 insideaddr
- 201::::2 insideaddr
-
-Upon incoming IPv6 connection, `sslh` will first try to
-connect to the IPv4 address (which will fail), then connect
-to the IPv6 address.
-
-Systemd Socket Activation
--------------------------
-If compiled with `USESYSTEMD` then it is possible to activate
-the service on demand and avoid running any code as root.
-
-In this mode any listen configuration options are ignored and
-the sockets are passed by systemd to the service.
-
-Example socket unit:
-
- [Unit]
- Before=sslh.service
-
- [Socket]
- ListenStream=1.2.3.4:443
- ListenStream=5.6.7.8:444
- ListenStream=9.10.11.12:445
- FreeBind=true
-
- [Install]
- WantedBy=sockets.target
-
-Example service unit:
-
- [Unit]
- PartOf=sslh.socket
-
- [Service]
- ExecStart=/usr/sbin/sslh -v -f --ssh 127.0.0.1:22 --ssl 127.0.0.1:443
- KillMode=process
- CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_SETGID CAP_SETUID
- PrivateTmp=true
- PrivateDevices=true
- ProtectSystem=full
- ProtectHome=true
- User=sslh
-
-
-With this setup only the socket needs to be enabled. The sslh service
-will be started on demand and does not need to run as root to bind the
-sockets as systemd has already bound and passed them over. If the sslh
-service is started on its own without the sockets being passed by systemd
-then it will look to use those defined on the command line or config
-file as usual. Any number of ListenStreams can be defined in the socket
-file and systemd will pass them all over to sslh to use as usual.
-
-To avoid inconsistency between starting via socket and starting directly
-via the service Requires=sslh.socket can be added to the service unit to
-mandate the use of the socket configuration.
-
-Rather than overwriting the entire socket file drop in values can be placed
-in /etc/systemd/system/sslh.socket.d/.conf with additional ListenStream
-values that will be merged.
-
-In addition to the above with manual .socket file configuration there is an
-optional systemd generator which can be compiled - systemd-sslh-generator
-
-This parses the /etc/sslh.cfg (or /etc/sslh/sslh.cfg file if that exists
-instead) configuration file and dynamically generates a socket file to use.
-
-This will also merge with any sslh.socket.d drop in configuration but will be
-overriden by a /etc/systemd/system/sslh.socket file.
-
-To use the generator place it in /usr/lib/systemd/system-generators and then
-call systemctl daemon-reload after any changes to /etc/sslh.cfg to generate
-the new dynamic socket unit.
-
-Fail2ban
---------
-
-If using transparent proxying, just use the standard ssh
-rules. If you can't or don't want to use transparent
-proxying, you can set `fail2ban` rules to block repeated ssh
-connections from an IP address (obviously this depends
-on the site, there might be legitimate reasons you would get
-many connections to ssh from the same IP address...)
-
-See example files in scripts/fail2ban.
Comments? Questions?
====================