How to Configure Internet Super Server (xinetd) in Linux: Complete Service Management Guide

how to configure internet super server in linux

xinetd is one of those pieces of Linux infrastructure that quietly does its job in the background of older systems, rarely gets a second thought, and then becomes a genuine puzzle the first time you need to add a new service to it and can’t remember the config syntax. It’s the “extended internet services daemon,” a super-server that listens on behalf of multiple network services and only launches the actual service process when a connection actually arrives — a resource-conservation and access-control pattern that predates the always-running-daemon model most modern services use under systemd.

What a Super-Server Does and Why It Existed

Before xinetd (and its predecessor, the original inetd), every network service — telnet, FTP, finger, talk, and dozens of smaller utilities — had to run as its own persistent daemon, sitting in memory and listening on its port continuously, whether or not anyone was actually using it. On systems with limited memory (which was essentially every system, historically), this was wasteful.

The super-server model solves this: one process, xinetd, listens on all the ports for configured services simultaneously. When a connection arrives on one of those ports, xinetd accepts it, forks, and executes the actual service binary to handle that specific connection, then the service process exits when the connection ends — no persistent per-service daemon required.

This model has genuinely fallen out of favor for most workloads, replaced by systemd socket activation (which does something conceptually similar but integrates with the modern service manager) or simply running services as always-on daemons on systems with plenty of RAM to spare. But xinetd is still present, actively used, and worth understanding on older RHEL/CentOS systems, embedded distributions, and specific service categories (like certain TFTP, time, or diagnostic services) that still default to it.

Installing xinetd

Debian/Ubuntu:

sudo apt update
sudo apt install xinetd

RHEL/CentOS/Fedora:

sudo dnf install xinetd

Enable and start it:

sudo systemctl enable --now xinetd
sudo systemctl status xinetd

Configuration Structure

xinetd’s configuration lives in two places:

  • /etc/xinetd.conf — global defaults applied to all services unless overridden.
  • /etc/xinetd.d/ — a directory containing one file per service, each defining that service’s specific settings.

Global Config Example (/etc/xinetd.conf)

defaults
{
    instances       = 60
    log_type        = SYSLOG authpriv
    log_on_success  = HOST PID
    log_on_failure  = HOST
    cps             = 25 30
}

includedir /etc/xinetd.d
  • instances — max simultaneous instances of any one service.
  • log_type — where logs go (typically syslog’s authpriv facility).
  • log_on_success/log_on_failure — what detail to log for successful/failed connection attempts.
  • cps — connections-per-second rate limiting: cps 25 30 allows 25 connections/second, then waits 30 seconds if that rate is exceeded, a basic built-in DoS mitigation.
  • includedir — pulls in every service definition file from /etc/xinetd.d/.

Per-Service Configuration File Structure

Each file in /etc/xinetd.d/ follows this pattern:

service SERVICE_NAME
{
    disable         = no
    socket_type     = stream
    protocol        = tcp
    wait            = no
    user            = root
    server          = /path/to/server/binary
    server_args     = arguments
    port            = PORT_NUMBER
    only_from       = allowed hosts/networks
    no_access       = denied hosts/networks
    log_on_success  += extra logging options
    log_on_failure  += extra logging options
}

Key Directive Reference

DirectiveMeaning
disableyes/no — whether this service is active
socket_typestream (TCP), dgram (UDP), raw, seqpacket
protocoltcp, udp
waityes (single-threaded, service handles its own concurrency) or no (xinetd forks a new instance per connection)
user/groupWhich local user/group the service process runs as
serverFull path to the executable
server_argsArguments passed to the executable
portWhich port to listen on
only_fromWhitelist of allowed client addresses/networks
no_accessBlacklist of denied client addresses/networks
access_timesTime-of-day window the service is available
instancesPer-service override of the global max instance count
bind/interfaceBind to a specific local interface/IP only

Example: Configuring a TFTP Server

TFTP is one of the more common services still legitimately run under xinetd today, particularly for PXE network boot environments.

sudo dnf install tftp-server    # RHEL/Fedora
sudo apt install tftpd-hpa      # Debian/Ubuntu (note: Debian's tftpd-hpa typically uses its own init/systemd unit rather than xinetd by default)

/etc/xinetd.d/tftp (RHEL-style):

service tftp
{
    socket_type     = dgram
    protocol        = udp
    wait            = yes
    user            = root
    server          = /usr/sbin/in.tftpd
    server_args     = -s /var/lib/tftpboot
    disable         = no
    per_source      = 11
    cps             = 100 2
    flags           = IPv4
}

Restart xinetd to apply:

sudo systemctl restart xinetd

Access Control Within xinetd

Beyond the older TCP Wrappers integration (xinetd can be compiled with libwrap support, honoring /etc/hosts.allow//etc/hosts.deny in addition to its own rules), xinetd has native access control directives that don’t depend on that separate mechanism:

service telnet
{
    disable     = no
    only_from   = 192.168.1.0/24 10.0.0.5
    no_access   = 192.168.1.100
    access_times = 08:00-18:00
}

This example allows telnet only from the 192.168.1.0/24 subnet and 10.0.0.5, explicitly blocks 192.168.1.100 even though it’s inside that subnet (a more specific rule overriding a broader one), and only during business hours.

Rate Limiting and DoS Mitigation

xinetd includes several built-in protections worth knowing:

per_source  = 5      # max simultaneous connections from a single source IP
cps         = 25 30  # max connections per second globally, then pause N seconds if exceeded
max_load    = 4       # refuse new connections if system load average exceeds this

These are genuinely useful defenses against simple flooding attacks targeting a specific service, applied before the connection ever reaches the actual service binary.

Logging

Check what xinetd has logged:

sudo journalctl -u xinetd
sudo grep xinetd /var/log/syslog       # Debian/Ubuntu
sudo grep xinetd /var/log/messages      # RHEL/CentOS

Increase verbosity for troubleshooting by adding to the service block:

log_on_success += DURATION
log_on_failure += RECORD

Enabling and Disabling Individual Services

Rather than editing files by hand every time, RHEL-family systems traditionally provided a helper:

sudo chkconfig telnet on
sudo chkconfig telnet off

On systems without chkconfig, edit the disable line directly and restart xinetd:

sudo sed -i 's/disable.*=.*yes/disable = no/' /etc/xinetd.d/telnet
sudo systemctl restart xinetd

Always verify the actual running state after any change:

sudo ss -tulnp | grep xinetd

The wait Directive: A Deeper Look at Concurrency Handling

The wait directive is one of the more commonly misunderstood settings, and getting it wrong produces genuinely confusing behavior — either a service that can’t handle concurrent connections at all, or one that spawns far more instances than intended.

wait = yes (single-threaded mode) — xinetd hands off the listening socket itself to the service and then stops managing that socket entirely until the service process exits. The service is fully responsible for its own concurrency (accepting multiple simultaneous connections on the same socket itself). This mode is appropriate for datagram-based services like TFTP, where the “connection” is really a self-contained series of independent request/response exchanges the daemon manages internally.

wait = no (multi-threaded mode) — xinetd keeps managing the listening socket itself, and for every new connection, forks a fresh instance of the service to handle just that one connection, then continues listening for the next. This is the appropriate mode for typical connection-oriented services like a shell or FTP session, where each client genuinely needs its own separate, isolated process.

# Verify which mode a running instance is actually configured for
grep wait /etc/xinetd.d/tftp

Getting this backwards for a stream-oriented service (setting wait = yes when it should be no) typically manifests as the service handling only one client at a time, with subsequent connection attempts hanging until the first client disconnects — a symptom that looks like a completely different kind of bug until you check this specific setting.

A Complete Walkthrough: Adding a New Custom Service to xinetd

Beyond configuring existing packaged services, it’s worth walking through adding an entirely custom service — a pattern that comes up when integrating a small internal tool that doesn’t ship its own systemd unit or standalone daemon mode.

Suppose you have a simple diagnostic script at /usr/local/bin/status-check.sh that you want reachable on a specific internal port, restricted to your monitoring subnet:

sudo tee /etc/xinetd.d/status-check <<'EOF'
service status-check
{
    disable         = no
    type            = UNLISTED
    socket_type     = stream
    protocol        = tcp
    port            = 9999
    wait            = no
    user            = nobody
    server          = /usr/local/bin/status-check.sh
    only_from       = 10.0.5.0/24
    log_on_success  += DURATION
    log_on_failure  += HOST
}
EOF

The type = UNLISTED directive is required for any service not already registered in /etc/services under that exact name — without it, xinetd refuses to start the service, since it can’t resolve the service name against the standard services database. You’d also add a matching entry to /etc/services if you want the port to have a friendly name for other tools’ benefit:

echo "status-check    9999/tcp" | sudo tee -a /etc/services

Restart and verify:

sudo systemctl restart xinetd
sudo ss -tulnp | grep 9999

Environment and Resource Controls Per Service

Beyond access control, xinetd can constrain the resource footprint of each service it manages, which is genuinely useful for preventing one misbehaving service from starving the whole system:

service heavy-tool
{
    disable      = no
    rlimit_cpu   = 60
    rlimit_as    = 256M
    nice         = 10
    env          = PATH=/usr/local/bin:/usr/bin
    passenv      = LANG
}
  • rlimit_cpu — maximum CPU seconds a single instance may consume before being killed.
  • rlimit_as — maximum virtual memory (address space) a single instance may use.
  • nice — process scheduling priority adjustment, useful for de-prioritizing a background/diagnostic service relative to more important workloads.
  • env/passenv — explicitly set or pass through specific environment variables to the launched service, rather than inheriting xinetd’s own full environment by default.

Interfacing xinetd With systemd on Modern Distros

On systemd-based systems, xinetd itself runs as a regular systemd-managed service (xinetd.service), which means it benefits from systemd’s own dependency ordering, restart policies, and logging integration even though the services xinetd itself manages don’t get individual systemd units of their own.

systemctl cat xinetd

This shows xinetd’s own unit file — worth checking if you need to adjust its restart behavior, resource limits at the xinetd process level itself (as opposed to per-service limits configured within xinetd’s own config), or startup ordering relative to networking being fully available.

[Unit]
Description=xinetd Service
After=network.target

[Service]
ExecStart=/usr/sbin/xinetd -stayalive -pidfile /run/xinetd.pid
Type=forking
PIDFile=/run/xinetd.pid

[Install]
WantedBy=multi-user.target

If you need to override any of this (a common override being adding Restart=on-failure for extra resilience), use systemctl edit xinetd rather than modifying the packaged unit file directly, so your customization survives package upgrades.

Comparing xinetd Service Definitions Across Distro Conventions

A subtlety worth knowing if you maintain configs across both Debian and RHEL-family systems: while the xinetd configuration syntax itself is identical (it’s the same upstream project), the packaged default service files that ship with common daemons sometimes differ slightly in default settings between distros — RHEL-family packages have historically been somewhat more conservative with default only_from and logging settings than some Debian-packaged equivalents. Always read the actual shipped file after installing a package rather than assuming a configuration you’ve seen on one distro applies identically on another.

diff <(cat /etc/xinetd.d/tftp) <(ssh other-distro-host cat /etc/xinetd.d/tftp)

Troubleshooting

Service enabled in config but not responding — confirm xinetd itself is running and was restarted after the config change:

sudo systemctl status xinetd
sudo systemctl restart xinetd

“Address already in use” errors — another process (possibly a standalone daemon for the same service) is already bound to that port:

sudo ss -tulnp | grep :PORT

Connections accepted but immediately dropped — check server path is correct and the binary is actually executable by the configured user:

ls -l /path/to/server/binary

only_from/no_access rules not behaving as expected — remember more specific rules can override broader ones; test carefully and check logs (log_on_failure) to confirm which rule actually matched a given connection attempt.

xinetd vs systemd Socket Activation

Modern systemd provides a conceptually similar mechanism — socket units (.socket files) that listen on a port and start the associated service unit on first connection. The philosophical difference: systemd socket activation is meant primarily for startup efficiency and dependency ordering on services that will typically run continuously once started, while xinetd’s model assumes services genuinely start and stop per connection, with more built-in per-connection access control and rate limiting baked directly into the super-server itself.

For new deployments on systemd-based distros, socket activation is generally the more idiomatic choice; xinetd remains relevant primarily for maintaining existing configurations, embedded systems, and specific legacy services that ship with xinetd definitions by default.

Security Implications

  • xinetd centralizes exposure for every service it manages — a misconfiguration in /etc/xinetd.conf (like default log_on_success settings, or an overly permissive only_from) can weaken every service under its control at once.
  • Because many of the classic xinetd-managed services (telnet, tftp, finger, rsh-related daemons) are themselves legacy plaintext protocols, running xinetd at all is sometimes a signal worth auditing — the question isn’t just “is xinetd configured securely” but “should this particular service exist on this network at all.”
  • Combine xinetd’s own access controls with kernel-level firewall rules (iptables/firewalld) rather than relying on xinetd’s only_from/no_access as your only line of defense — defense in depth matters here as much as anywhere else.

Summary

xinetd is a super-server that listens on behalf of multiple network services and launches them on demand, configured through /etc/xinetd.conf for global defaults and per-service files in /etc/xinetd.d/. It provides genuinely useful built-in access control (only_from/no_access/access_times) and rate limiting (cps/per_source/max_load) beyond what the underlying services might implement themselves. While largely superseded by always-on daemons and systemd socket activation for new deployments, it remains actively relevant for services like TFTP and for maintaining legacy infrastructure.

References

Total
3
Shares

Leave a Reply

Previous Post
how to turn off standalone services in linux

How to Turn Off Standalone Services in Linux: Complete Service Disabling and Security Hardening Guide

Next Post
how to configure TCP Wrapper Security in Linux

How to Configure TCP Wrapper Security in Linux: Complete Host-Based Access Control Guide

Related Posts