Socket activation lets systemd bind a listening endpoint before the service process exists, which reduces idle resource use and keeps a local port or socket path ready until the first real client arrives. That model fits small helper services, compatibility daemons, and on-demand tools that should start only when traffic reaches a known endpoint.
In systemd, a *.socket unit defines the listening endpoint and triggers a matching service when traffic arrives. Current upstream systemd.socket rules require a matching foo.service when Accept=no, or a matching foo@.service template when Accept=yes spawns one service instance per connection. The example below uses demo-echo.socket on 127.0.0.1:9091 with Accept=yes plus a simple template that echoes client input back through the accepted connection by using StandardInput=socket and StandardOutput=socket.
Current upstream systemd documentation recommends Accept=no for new daemons that can consume socket activation directly, but Accept=yes remains the clearest way to demonstrate inetd-style activation and one-connection-per-instance behavior. Binding the sample socket to 127.0.0.1 keeps the first test local to the host; move it to another address or a Unix socket path only after the service behavior, firewall policy, and authentication requirements are understood.
[Unit] Description=Per-connection echo service for demo-echo.socket [Service] ExecStart=/bin/cat StandardInput=socket StandardOutput=socket StandardError=journal
With Accept=yes, the triggered unit must be a template named after the socket basename, here demo-echo@.service. Current systemd.exec behavior allows StandardInput=socket only for socket-activated services and requires Accept=yes or a single configured socket.
[Unit] Description=Socket unit for demo-echo [Socket] ListenStream=127.0.0.1:9091 Accept=yes [Install] WantedBy=sockets.target
ListenStream= accepts TCP ports, IPv6 addresses, Unix socket paths, and similar stream endpoints. The WantedBy=sockets.target install stanza follows current upstream systemd.special guidance for socket units that should be active after boot.
When the daemon is written to consume the inherited listening socket itself, use Accept=no and a matching non-template demo-echo.service instead.
$ sudo systemd-analyze verify /etc/systemd/system/demo-echo@.service /etc/systemd/system/demo-echo.socket
No output means the unit files parsed cleanly and the name relationship is acceptable to systemd.
$ sudo systemctl daemon-reload
This rereads the definitions from disk and rebuilds the dependency tree before the new socket can be enabled or started.
$ sudo systemctl enable --now demo-echo.socket Created symlink /etc/systemd/system/sockets.target.wants/demo-echo.socket → /etc/systemd/system/demo-echo.socket.
Enable the *.socket unit, not the template service. Socket activation starts the matching service instances only when a client connects.
$ systemctl status --no-pager --full demo-echo.socket | head -n 6
● demo-echo.socket - Socket unit for demo-echo
Loaded: loaded (/etc/systemd/system/demo-echo.socket; enabled; preset: enabled)
Active: active (listening) since Mon 2026-04-13 21:20:48 +08; 17ms ago
Listen: 127.0.0.1:9091 (Stream)
Accepted: 0; Connected: 0;
Tasks: 0 (limit: 4543)
The success state for the socket unit itself is active (listening). A service process may not exist yet because no client has connected.
$ printf 'socket activation works\n' | nc -N 127.0.0.1 9091
socket activation works
$ systemctl status --no-pager --full demo-echo.socket | head -n 7
● demo-echo.socket - Socket unit for demo-echo
Loaded: loaded (/etc/systemd/system/demo-echo.socket; enabled; preset: enabled)
Active: active (listening) since Mon 2026-04-13 21:20:48 +08; 93ms ago
Listen: 127.0.0.1:9091 (Stream)
Accepted: 1; Connected: 0;
Tasks: 0 (limit: 4543)
Memory: 4.0K (peak: 264.0K)
The echoed line proves that systemd accepted the connection and started the matching service instance on demand. On a real application socket, replace the nc test with the protocol-specific client that the service expects.
$ sudo journalctl -u demo-echo.socket -n 10 --no-pager Apr 13 21:20:48 host systemd[1]: Listening on demo-echo.socket - Socket unit for demo-echo.
Manager messages confirm whether the socket bound successfully. Service-side errors normally appear under the triggered unit rather than the socket unit, so inspect the matching service journal when the bind works but the request still fails.