minetd is a clean, modern, POSIX‑compliant re‑imagining of classic
Unix superdaemons like inetd and xinetd.
It focuses on simplicity, safety, clarity, and maintainability,
while providing the powerful "run a program per connection" model that
made inetd timeless.
minetd is ideal for:
- lightweight TCP services
- internal automation
- embedded systems
- development environments
- secure, auditable deployments
- anywhere you need inetd‑style behavior without bloat
- Single‑file C implementation
- Strictly POSIX APIs (portable across Linux, BSD, macOS, embedded)
- No threads, no opaque magic, no complexity
For each new TCP connection:
accept()fork()- child's stdin/stdout/stderr become the socket
- child runs your program via
execvp()
Your server programs require zero networking code.
minetd supports live reloading via SIGHUP, preserving existing
connections.
Just run:
minetd --reloadOn reload:
- New services are added immediately
- Removed services stop accepting connections
- Running child processes continue untouched
- If the config is invalid, minetd safely keeps the old configuration
minetd writes its PID to:
/var/run/minetd.pid
This allows clean control operations such as reload, integration with tools, and automation.
The PID file is owned for the daemon's whole lifetime:
- It is opened without truncating and without following symlinks
(
O_NOFOLLOW), and created with mode 0644 if missing. - The open descriptor must be a regular file with a single link, owned by the daemon's effective user and not group/world writable; anything else is refused.
- A nonblocking exclusive
fcntl()record lock is taken before the PID is written. If another instance holds the lock, startup fails with a diagnostic naming the path and the existing file is left untouched. - Any PID-file failure is fatal:
minetdexits nonzero before accepting connections. In background mode the launching command exits nonzero as well, and the diagnostic is printed before stderr is detached. - The descriptor, and with it the lock, stays open until shutdown. It is close-on-exec and record locks are per-process, so service children never hold it. Standard descriptors 0-2 are reserved at startup so the PID file can never occupy one and be closed when stdio is redirected.
- On shutdown the file is unlinked only if the path still names the locked inode; a file someone else created there is left alone.
Stale files left by a crash are reclaimed, since no process holds their
lock. The lock proves a live owner of the path; minetd --reload still
trusts the PID stored in the file and does not verify that it belongs to a
live minetd.
Each service can specify a maximum number of connections per minute to avoid fork floods:
service daytime 0.0.0.0:7001 30 /usr/local/bin/daytime-server
- Every child process receives a clean FD environment
- Listener FDs are never shared across services
- Zombies are reaped immediately
- Reloading never corrupts global state
- No permanent privilege escalation
minetd reads a small, clean config file:
service <name> <host:port> <max_conn_per_min> <program> [args...]
Example:
service echo 0.0.0.0:7000 60 /usr/local/bin/echo-server
service daytime 0.0.0.0:7001 30 /usr/local/bin/daytime-server
Lines beginning with # are comments.
make
sudo make installservice daytime 0.0.0.0:7001 10 /usr/local/bin/daytime-server
service echo 0.0.0.0:7002 60 /usr/local/bin/echo-server
Foreground (debug):
minetd -f -c /etc/minetd.conf
Background:
minetd -c /etc/minetd.conf
minetd --reload
#include <stdio.h>
#include <time.h>
int main(void) {
time_t now = time(NULL);
struct tm tm;
gmtime_r(&now, &tm);
char buf[128];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC\n", &tm);
fputs(buf, stdout);
return 0;
}Compile:
cc -O2 daytime-server.c -o /usr/local/bin/daytime-serverminetd aims to be secure by simplicity:
- Clean child FD sandbox
- Rate limiting
- Predictable signal handling
- Zero shared state between reloads
- Minimal code surface area
Optional (recommended):
- Dedicated service users
chrootsetrlimit- MAC frameworks
- Minimal but correct
- Simple but powerful
- Secure by design
- Portable and predictable
- Auditable by a single human
MIT License
Contributions welcome. Please follow the minimalistic and security‑oriented philosophy.
Inspired by:
- The original inetd
- OpenBSD daemon culture
- The Unix philosophy: "do one thing well"