Port Forwarding with xinetd – a flexible solution under Linux

In Linux systems, binding a non-root process to a privileged port (which are ports <1024) is not allowed by default. This can be inconvenient when you need to run a server on a standard port without root privileges. xinetd offers a solution to this problem by providing a flexible port forwarding mechanism.
In my case, I had to set it up because I wanted to run a non-root server on external port 443 and I didn't want to start it with root privileges.
Key reasons to use xinetd
- Bind non-root processes to privileged ports
- Enhance security by avoiding running server processes as root
- Provide a workaround when running a process with root privileges is not possible or advisable
Installing xinetd (I did this on Ubuntu 22.04)
sudo apt-get update
sudo apt-get install xinetd
Configuring forwarding
First, create a configuration file for your service. In my case, I did set up port forwarding for a ThingsBoard HTTPS server listening on port 8443 (localhost only). xinetd is configured to listen on (external) port 443 and is forwarding traffic to the (internal / localhost-only) port 8443.

You can use nano (or pico, vi, vim, etc.) to edit the configuration. To add a configuration place it in
sudo nano /etc/xinetd.d/thingsboard-https
Name your config file according to your preferences and needs. I named mine according to the server-process name, but basically anything else is also fine.
service thingsboard-https
{
disable = no
flags = REUSE
wait = no
user = root
socket_type = stream
protocol = tcp
port = 443
redirect = localhost 8443
log_on_success -= PID HOST DURATION EXIT
}

Brief config parameter explanation
- disable = no: enables the service
- flags = REUSE: allows reuse of the socket
- wait = no: xinetd will start a new process for each connection
- user = root: service runs as root (necessary for binding to port 443)
- socket_type = stream: uses TCP
- protocol = tcp: specifies TCP protocol
- port = 443: port xinetd will listen on
- redirect = localhost 8443: forwards connections to localhost on port 8443
- log_on_success -= PID HOST DURATION EXIT: reduces logging verbosity
Adding the "new" service to system services
sudo nano /etc/services
Add / Edit the following line, name it according to your service name you just used above (with xinetd):
https 443/tcp thingsboard-https # http protocol over TLS/SSL
This step ensures that the service name is recognized system-wide and can be referenced by other applications. By default https 443/tcp
, it is already set but is used with another service name.
Save this config and restart your server (restarting xinetd
only is enough in most cases). Anyhow, I recommend restarting the whole server by doing a sudo reboot now
.
sudo systemctl restart xinetd
# or
sudo reboot now
Verifying the configuration
To verify the configuration, I am using the ss
command (short for socket statistics) to show listening sockets on my machine:
sudo ss -tulp | grep https
# or
sudo ss -tulpn | grep 443
We see the output indicating that xinetd is listening on port 443 (https). Everything is working as expected!
Here is a brief reminder of what the parameters we passed to ss
do:
- -t: display TCP sockets
- -u: display UDP sockets, when used together with -t, it will display both TCP and UDP sockets
- -l: stands for "listening" and shows only sockets that are listening for incoming connections
- -n: prevent DNS lookups, which can speed up the command by not resolving IP addresses to hostnames
- -p: show the PID and name of the program to which each socket belongs