ARAHLI(1)                   General Commands Manual                  ARAHLI(1)

NAME
     arahli - route TLS connections by SNI without terminating TLS

SYNOPSIS
     arahli [-config path]

DESCRIPTION
     The arahli utility listens for TLS connections, inspects the ClientHello
     to read the server name indication (SNI), and forwards the connection to
     a backend selected by configuration.

     arahli does not terminate TLS; the backend is expected to negotiate TLS
     with the client directly (for example, for mTLS).

     If no SNI is present, or if no exact match is found, the wildcard route
     "*" may be used as a default backend.

CONFIGURATION
     Configuration is in scfg: https://git.sr.ht/~emersion/scfg syntax and
     contains one or more listen directives:

     listen net addr
             Listener network and address as accepted by net.Listen(3) (e.g.,
             "tcp :8443" or "unix /path/to/socket").  When using "unix", any
             existing socket file at addr is removed before listening.

             The block is a routing table keyed by host name.  Each entry has
             the form:

                   hostname net addr

             The hostname must be lowercase ASCII DNS hostname syntax without
             a trailing dot; literal IP addresses are not permitted.  Use "*"
             to configure the default backend.

             For "tcp", "tcp4", "tcp6", and "unix", arahli proxies the
             connection to addr without terminating TLS.  If net is
             "scm_rights", addr must be a Unix socket.  In this mode, arahli
             passes the accepted client connection file descriptor to the
             backend using SCM_RIGHTS after sending a one-byte protocol
             version payload with value 0.  The backend receives the original
             connected socket; the ClientHello remains unconsumed.

     Each listen directive has its own routing table and backends.  If no
     listen directives are configured, the program exits with an error.

OPTIONS
     -config path
             Path to the configuration file.  Default:
             /etc/lindenii/arahli.conf.

EXAMPLES
           listen tcp :8443 {
                   a.lindenii.org tcp [::1]:8081
                   b.lindenii.org tcp [::1]:8082
                   c.lindenii.org scm_rights /var/run/c.sock
                   d.lindenii.org scm_rights /var/run/d.sock
                   * tcp [::1]:1234
           }

           listen tcp6 [::]:9443 {
                   c.lindenii.org tcp6 [::1]:9444
           }

BUGS
     Because arahli relies on reading the TLS ClientHello without terminating
     TLS, it is incompatible with Encrypted Client Hello (ECH).  If ECH is
     enabled for a hostname, SNI-based routing will fail.  If ECH is desired,
     consider either using one IP per service (which is only really feasible
     when IPv6 is truly widespread), or by using TLS-terminating reverse
     proxies.

     The SNI parsing depends on the kernel receive queue.  We need enough of
     the ClientHello bufferd at once to parse it.  If the ClientHello is
     larger than the socket receive buffer, routing fails.

     The current parser waits for the full ClientHello rather than just enough
     bytes to reach the SNI.

FILES
     /etc/lindenii/arahli.conf
             Default configuration file.

Lindenii Project               January 27, 2026               Lindenii Project
