Skip to content

Instantly share code, notes, and snippets.

@carlosgrillet
Created April 15, 2026 21:00
Show Gist options
  • Select an option

  • Save carlosgrillet/afc5140429dac28fff5ab75fb0b3c59a to your computer and use it in GitHub Desktop.

Select an option

Save carlosgrillet/afc5140429dac28fff5ab75fb0b3c59a to your computer and use it in GitHub Desktop.
This guide outlines the "Fedora Way" for deploying manual services. It covers standard Linux permissions (DAC) and the stricter SELinux controls (MAC) required for Fedora 43.

Fedora Service Deployment Guide

1. System User Setup

Never run a service as root or a standard login user. Create a dedicated system user.

# -r: System account (no aging, UID in system range)
# -s /sbin/nologin: No interactive login shell for security
# -U: Create a group with the same name as the user
# -m -d: Create and set the home directory
sudo useradd -rs /sbin/nologin -Umd /var/lib/myservice myservice

2. Directory & Path Strategy

Fedora follows the Filesystem Hierarchy Standard (FHS). SELinux expects files in specific places:

  • Binaries: /usr/local/bin/ or /usr/bin/
  • Persistent Data/State: /var/lib/myservice/ (databases, models, runtime state)
  • Logs: /var/log/myservice/
  • Configuration: /etc/myservice/

Avoid /usr/share/ for mutable data; SELinux labels it as usr_t (read-only).

3. SELinux Labeling (The Proactive Step)

SELinux uses "labels" to decide what a process can touch. Even if chown is correct, a label mismatch causes "Permission Denied."

# 1. Tell SELinux /var/lib/myservice is for service data (var_lib_t)
sudo semanage fcontext -a -t var_lib_t "/var/lib/myservice(/.*)?"

# 2. Apply the labels to the existing files
sudo restorecon -Rv /var/lib/myservice

# 3. If your binary is in a custom path, ensure it has the correct executable label
sudo restorecon -v /usr/local/bin/myservice-binary

4. Systemd Unit Configuration

Create the file at /etc/systemd/system/myservice.service.

[Unit]
Description=My Custom Service
Wants=network-online.target
After=network-online.target

[Service]
Environment="DATA_PATH=/var/lib/myservice"
ExecStart=/usr/bin/myservice-binary
User=myservice
Group=myservice
Restart=always

# Security Hardening (optional but worth)
ProtectSystem=strict       # Makes entire filesystem read-only except /dev, /proc, /sys
PrivateTmp=true            # Isolated /tmp and /var/tmp
NoNewPrivileges=true       # Prevents privilege escalation via setuid/capabilities

[Install]
WantedBy=multi-user.target

After creating or modifying the file, reload systemd:

sudo systemctl daemon-reload
sudo systemctl enable --now myservice

5. Handling Network Access

By default, a custom service without its own SELinux policy runs in the unconfined_service_t domain, which generally permits outbound connections. However, if you write a custom SELinux policy for tighter confinement, network access must be explicitly granted.

If SELinux is blocking a connection (you will see AVC denials in the audit log):

  1. Run the service and let it fail
sudo systemctl start myservice
  1. Extract the specific AVC denial and generate a policy module
sudo ausearch -m AVC -c myservice | audit2allow -M myservice_net
sudo semodule -i myservice_net.pp

Note: audit2allow grants the minimum permissions needed for the observed denial. Review the generated .te file before loading it in production.

6. Troubleshooting Workflow

If your service starts but "cannot write" or "cannot connect":

  1. Check standard permissions: ls -l /var/lib/myservice
  2. Check SELinux labels: ls -Z /var/lib/myservice
  3. Search for AVC denials:
sudo ausearch -m AVC -c myservice
  1. Check the service journal for application-level errors:
sudo journalctl -u myservice -xe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment