S6-TCPSERVER(8)
π NAME
s6-tcpserver β UCSPI tool[1] for TCP connections, i.e. a super-server. Yes bestie, that's the whole vibe: it's the manual page for s6-tcpserver, section 8, and it's lowkey iconic. π«Ά
β¨ SYNOPSIS
s6-tcpserver [-q | -Q | -v] [-1] [-c maxconn] [-C localmaxconn]
[-b backlog] [-G gidlist] [-g gid] [-u uid] [-U] ip port
prog...
πΈ DESCRIPTION
Okay so picture this: s6-tcpserver accepts connections from clients, and for each one it spawns a program to handle that connection. That's it. That's the job. π
It binds to the local IP address ip (which can be IPv4 or IPv6, no cap) and to port port.
It closes its stdin and stdout. Bye. π
Then for every single TCP connection to this address and port, it spawns a prog... child with stdin reading from the network socket and stdout writing to it. Literally the socket becomes that child's whole personality.
Depending on the verbosity level, it logs what it does to stderr. ποΈ
It runs until killed by a signal β and depending on the received signal, it may kill its children before exiting. Dramatic? Maybe. Necessary? Absolutely.
Unlike its ancestor tcpserver[2], s6-tcpserver performs just the barest minimum: the whole point is to have a very small and very fast process to serve connections with the least possible overhead. Features like access control and DNS resolution? Not here bestie β those are provided via the s6-tcpserver-access(8) +program. π§
Fun structural tea: s6-tcpserver is actually a wrapper that rewrites itself into a command line running:
s6-tcpserver-socketbinder(8), that binds the socket and listens to it. πs6-applyuidgid(8), that drops privileges. πβ‘οΈπs6-tcpserverd(8), the long-lived process that actually accepts the connections. So if you see in yourps(1)output that the name of the process is βs6-tcpserverdβ, that's why. Mystery solved, you're welcome. π
Important vibe check: s6-tcpserver treats IPv4 and IPv6 separately. If you want to listen on all the addresses of a machine no matter whether v4 or v6, then you need to run two s6-tcpserver processes: one on β0.0.0.0β and one on β::β. Two servers, one dream. π
Also, the option to make s6-tcpserver verbose is -v, without an argument. This is different from the s6-tcpserverd(8) interface, where that would be -v 2. The difference exists because s6-tcpserver follows the UCSPI tool[1] interface, whereas s6-tcpserverd(8) has no such constraint. Don't ask me to make them match, it's giving by design. π
π¨ Signals
SIGTERMβ Exit.SIGHUPβ Send aSIGTERMand aSIGCONTto all children.SIGQUITβ Send aSIGTERMand aSIGCONTto all children, then exit.SIGABRTβ Send aSIGKILLto all children, then exit.
π₯ OPTIONS
-qβ Be quiet. Only print fatal error messages to stderr. π€«-Qβ Be normally quiet. Print warnings and fatal error messages to stderr. This is the default. Lowkey the baseline behavior.-vβ Be verbose. Additionally to fatal errors and warnings, also print status and connection information for every client. Now we're nosy and we're thriving. π-1β Write port to stdout, before closing it, right after binding and listening to the network socket. If stdout is suitably redirected, this can be used by monitoring programs to check when the server is ready to accept connections. Very "text me when you're home" energy. π²-cmaxconn β Accept at most maxconn concurrent connections. Default is40. It is impossible to set it higher than1000. That's the ceiling, bestie, literally.-Clocalmaxconn β Accept at most localmaxconn connections from the same IP address. Default is40. It is impossible to set it higher than maxconn. No loopholes. π«-bbacklog β Set a maximum of backlog backlog connections on the socket. Extra connection attempts will rejected by the kernel. Rude, but efficient. π-Ggidlist β Changes6-tcpserver's supplementary group list to gidlist after binding the socket. This is only valid when run as root. gidlist must be a comma-separated list of numerical group IDs. π-ggid β Change s group id to gid after binding the socket. This is only valid when run as root.-uuid β Changes6-tcpserver's user id to uid after binding the socket. This is only valid when run as root. π-Uβ Changes6-tcpserver's user id, group id and supplementary group list according to the values of theUID,GIDandGIDLISTenvironment variables after binding the socket. This is only valid when run as root. This can be used with thes6-envuidgid(8)program to easily script a service that binds to a privileged socket then drops its privileges to those of a named non-root account. β¨ glow-down era.
πΏ ENVIRONMENT
For each connection, an instance of prog... is spawned with the following variables set:
PROTOβ Always set toTCP. Every time. No exceptions. π―TCPLOCALIPβ Set to the server's address. πTCPLOCALPORTβ Set to the server's port.TCPREMOTEIPβ Set to the client's address. π°οΈTCPREMOTEPORTβ Set to the client's port.TCPCONNNUMβ Set to the number of connections originating from the same IP address. Counting besties, one by one. π’
π SEE ALSO
ps(1), s6-applyuidgid(8), s6-envuidgid(8), s6-tcpclient(8), s6-tcpserver-access(8), s6-tcpserver-socketbinder(8), s6-tcpserverd(8)
[1] https://cr.yp.to/proto/ucspi.txt
[2] https://cr.yp.to/ucspi-tcp/tcpserver.html
This man page is ported from the authoritative documentation at: https://skarnet.org/software/s6-networking/s6-tcpserver.html
π AUTHORS
Laurent Bercot Alexis <flexibeast@gmail.com> (man page port)
And that's the whole page, bestie β sourced from Debian, dated November 20, 2023, sitting pretty in section 8 as S6-TCPSERVER(8). Slay, read, repeat. πβ¨
π¦ where this page comes from
- nixpkgs unstable: s6-networking 2.8.0.1
- nixpkgs unstable: s6-networking-man-pages 2.7.2.1.4
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms