systemd Socket Activation Explained

systemd Socket Activation Explained

Our service file guide covers running a daemon. Socket activation changes when it runs.

systemd creates the listening socket. The service starts when something connects.

The mechanism

Normally a daemon starts, calls socket(), bind(), and listen(), then accepts connections. Anything connecting before that sequence completes gets connection refused.

With socket activation, systemd does the first three steps at boot. The socket is listening immediately. When a connection arrives, systemd starts the service and hands it the already-listening socket as file descriptor 3.

Two properties follow, and the second is more valuable than the first.

Services need not run when idle. A service used twice a day consumes nothing in between.

Startup ordering mostly disappears. The socket exists from boot, so a client connecting before the service has started has its connection queued by the kernel rather than refused. The client blocks briefly and then succeeds.

That second property is the real win. A great deal of systemd unit dependency ordering exists to make sure a server is up before its clients try to reach it, and socket activation makes that unnecessary.

A worked example

# /etc/systemd/system/myapp.socket
[Unit]
Description=Socket for myapp

[Socket]
ListenStream=0.0.0.0:8080
Accept=no

[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp.service
[Unit]
Description=My application
Requires=myapp.socket
After=myapp.socket

[Service]
ExecStart=/usr/local/bin/myapp
StandardInput=socket
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.socket
sudo systemctl status myapp.socket

Enable the socket, not the service. The service starts on demand. This mirrors the cron versus timers rule where you enable the timer rather than the service.

Accept=no means one long-running service accepts many connections, which is what you almost always want. Accept=yes spawns a process per connection, inetd-style, which is expensive and only suits very low-traffic services.

ss -tlnp | grep 8080      # listening, even with the service stopped
systemctl status myapp    # inactive
curl localhost:8080       # this starts it

Idle timeouts

The combination that makes it genuinely useful on a small machine:

[Service]
ExecStart=/usr/local/bin/myapp
# in the .socket
[Socket]
ListenStream=8080

Many daemons accept an idle-exit option. Where they do, the service starts on demand, serves requests, exits after a period of inactivity, and starts again on the next connection. Memory is consumed only while in use.

On a small VPS running a dozen rarely-used services, that is a real saving.

Where you already use it

Worth knowing how common this is.

systemctl list-sockets
LISTEN                    UNIT                        ACTIVATES
/run/dbus/system_bus_socket dbus.socket               dbus.service
/run/docker.sock          docker.socket               docker.service
[::]:22                   sshd.socket                 sshd@.service
/run/systemd/journal/...  systemd-journald.socket     systemd-journald.service

Cockpit uses it, which our Cockpit guide notes is why an idle server carries no cost from having it installed.

Docker uses it for its API socket.

sshd can be socket-activated, though most distributions run it conventionally because SSH is the thing you need working when everything else is broken, and a cold start adds latency exactly when you are stressed.

Services that do not support it

The service must accept a pre-opened descriptor rather than creating its own. systemd passes it as descriptor 3 with LISTEN_FDS=1 set.

For software that cannot, there is a bridge:

# myapp-proxy.service
[Unit]
Requires=myapp.service
After=myapp.service

[Service]
ExecStart=/usr/lib/systemd/systemd-socket-proxyd 127.0.0.1:9000

systemd-socket-proxyd accepts the activated socket and forwards to the service’s own port. You get on-demand starting for software with no socket activation support, at the cost of a proxy hop.

Other socket types

ListenStream=/run/myapp.sock       # Unix socket
ListenDatagram=0.0.0.0:514         # UDP
ListenFIFO=/run/myapp.fifo         # named pipe
ListenNetlink=kobject-uevent 1     # netlink

Unix sockets get filesystem permissions, which is a genuinely good access control mechanism:

[Socket]
ListenStream=/run/myapp.sock
SocketUser=myapp
SocketGroup=myapp-clients
SocketMode=0660

Only members of myapp-clients can connect. No network exposure, no authentication code in the application, and the kernel enforces it. Our permissions guide covers the model.

Where it does not help

Busy services. A web server serving constant traffic should just run. Paying cold-start latency on the first request after each idle period is worse than the memory it saves.

Services with expensive startup. Something that loads a large model or warms a cache takes seconds to start, and a client connecting will wait all of it.

Anything you need working during recovery. SSH is the example. When you are debugging a broken machine, you want the daemon already running.

The honest scope: socket activation is excellent for intermittent services on constrained machines, and for removing dependency ordering headaches. It is not a general performance improvement, and applying it to a busy service makes things worse rather than better.

Frequently Asked Questions

What is socket activation?

systemd creates and listens on the socket itself, then starts the service only when a connection arrives, passing it the already-listening socket. The service does not create its own socket, so connections made before it is ready are queued by the kernel rather than refused.

Does socket activation make boot faster?

It can, because services do not need to start at boot at all, and those that do can start in parallel without waiting for each other. The larger benefit on a small system is that idle services consume no memory until something actually connects to them.

How does socket activation fix startup ordering?

The socket exists from the moment systemd creates it, so a client connecting before the service has started gets its connection queued rather than refused. This removes most dependency ordering between services, because a client no longer needs the server to be fully started first.

Does the application need to support socket activation?

It needs to accept a pre-opened file descriptor rather than creating its own socket, which systemd passes as descriptor 3 with the LISTEN_FDS environment variable set. Many daemons support this natively, and systemd-socket-proxyd can bridge for those that do not.

What is the difference from inetd?

inetd started a new process per connection and connected it to stdin and stdout, which is expensive and limits the process to one connection. systemd passes a listening socket to a persistent service that accepts many connections, so it combines on-demand start with normal daemon behaviour.

Should I socket activate everything?

No. It suits services used intermittently, where the delay of a cold start is acceptable and the memory saving is real. A busy web server should just be running, because paying startup latency on the first request after every idle timeout is a worse experience than using the memory.