Granting a Custom Fedora Service Permission to Bind to Port 8080 with a SELinux Policy Module
Enable a user‑defined Fedora service to bind to port 8080 by creating a custom SELinux policy module, labeling the binary, and loading the module. Follow the step‑by‑step guide to keep SELinux enforcing and avoid common pitfalls.
03 Jun 2026, 20:44 UTC

Why You Need a Custom SELinux Module
Fedora ships with SELinux enabled in enforcing mode by default. When a user‑defined binary attempts to bind to a TCP port, SELinux checks whether the binary’s type is allowed to perform the name_bind operation on the port’s type. If the binary is labeled unconfined_t (the default for user binaries) and the port is http_port_t, the bind will be denied unless you give the binary explicit permission. The recommended, least‑privilege‑friendly way to do this is by creating a small policy module that grants the binary the necessary right on the specific port.
Step 1 – Verify SELinux is Enforcing
# sudo sestatus
# Current mode: enforcing
# SELinux status: enabled
If the output shows permissive or disabled, you must re‑enable enforcing before proceeding.
Step 2 – Prepare the Binary and Systemd Unit
Assume you have a simple Go binary located at /usr/local/bin/myapp that listens on 0.0.0.0:8080. Create a systemd unit that explicitly labels the binary with a new type myapp_t:
[Unit]
Description=My App Service
After=network.target
[Service]
ExecStart=/usr/local/bin/myapp
# Tell systemd to label the process
PrivateTmp=true
Type=simple
[Install]
WantedBy=multi-user.target
Save this as /etc/systemd/system/myapp.service and reload systemd:
# systemctl daemon-reload
Step 3 – Write the Policy Module
Create a new file myapp.te with the following contents:
module myapp 1.0;
require {
type myapp_t;
type http_port_t;
class tcp_socket { name_bind };
}
# Allow the myapp binary to bind to any http_port_t port
allow myapp_t http_port_t:tcp_socket name_bind;
This module declares the custom type myapp_t, imports the standard http_port_t type (used for ports 80, 443, and the unprivileged range 8000‑8999), and grants the name_bind permission on TCP sockets.
Compile and Load the Module
# checkmodule -M -m -o myapp.mod myapp.te
# semodule_package -o myapp.pp -m myapp.mod
# sudo semodule -i myapp.pp
After loading, verify the module is active:
# semodule -l | grep myapp
myapp 1.0
Step 4 – Label the Binary with the New Type
Use semanage fcontext to associate the binary path with myapp_t, then relabel the file:
# semanage fcontext -a -t myapp_t '/usr/local/bin/myapp'
# restorecon -v /usr/local/bin/myapp
Check the label:
# ls -Z /usr/local/bin/myapp
-rwxr-xr-x. root root unconfined_u:object_r:myapp_t:s0 /usr/local/bin/myapp
Step 5 – Start the Service and Verify Binding
# systemctl start myapp
# systemctl status myapp
● myapp.service - My App Service
Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
Active: active (running) since …
Confirm the process is listening on 8080:
# ss -tlnp | grep 8080
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:("myapp",pid=1234,fd=3)
If the service fails to start or you see an AVC denied entry in /var/log/audit/audit.log, run:
# audit2allow -w -a
and adjust the module accordingly.
Common Mistakes and Limits
- Using permissive mode –
setenforce 0temporarily disables checks but does not solve the underlying policy problem. Never rely on permissive mode in production. - Wrong file context – If you forget
semanage fcontextorrestorecon, the binary staysunconfined_tand SELinux will continue to block the bind. - Over‑permissive rules – Granting
any_fileorall_portsdefeats SELinux’s purpose. Always target the specific port type, e.g.,http_port_t. - Missing type declaration – The module must declare
myapp_tbefore it can be used. Omit this and the module will fail to compile. - Version mismatch – The example uses policy tools from Fedora 38+. If you’re on an older release, the
checkmodulesyntax may differ.
What to Check After Deployment
- Run
sestatusto confirm enforcing mode. - Use
semodule -l | grep myappto ensure the module is loaded. - Verify the binary label with
ls -Z /usr/local/bin/myapp. - Confirm the port is listening with
ss -tlnp | grep 8080. - Inspect
/var/log/audit/audit.logfor any new AVC denials; if present, refine the module.
Conclusion
By creating a small SELinux policy module, labeling the binary, and loading the module, you grant your custom service the exact permission it needs—binding to port 8080—without loosening system security. This approach follows the principle of least privilege and keeps the system audit‑friendly and maintainable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.