How to Execute Root Commands Before Service Startup with Systemd User Context Switching


7 views

When configuring systemd services that need to run under non-root users, we often encounter situations requiring privileged operations before service launch. The classic example is preparing runtime directories with specific ownership permissions - exactly what's happening with the svnserve scenario.

Systemd executes all commands in the [Service] section under the configured User by default, including ExecStartPre directives. This security feature prevents privilege escalation but creates our current challenge.

The most elegant approach uses systemd's ExecStartPre with User=root override:

[Service]
User=svn
ExecStartPre=+/bin/chown svn:svn /run/svnserve
ExecStart=/usr/bin/svnserve --daemon --pid-file=/run/svnserve/svnserve.pid -r /repos/svn

The + prefix before the command tells systemd to run this specific directive as root, while maintaining the user context for subsequent commands.

For more complex pre-launch requirements:

[Unit]
Description=SVN Server Directory Prep
DefaultDependencies=no
Before=svnserve.service

[Service]
Type=oneshot
ExecStart=/bin/chown svn:svn /run/svnserve

[Install]
WantedBy=svnserve.service

This creates a dedicated unit that executes before your main service with full root privileges.

When you need fine-grained control:

[Service]
User=svn
ExecStartPre=/usr/bin/sudo /bin/chown svn:svn /run/svnserve

Requires proper sudoers configuration:

svn ALL=(root) NOPASSWD: /bin/chown svn:svn /run/svnserve

For persistent directory configurations, consider systemd-tmpfiles:

# /etc/tmpfiles.d/svnserve.conf
d /run/svnserve 0755 svn svn -

This automatically creates and sets permissions during boot.

When troubleshooting permission issues:

# View service logs
journalctl -u yourservice.service

# Test commands manually
sudo -u svn /bin/sh -c "touch /run/svnserve/test"

Always minimize root operations:

  • Use specific directory targets instead of recursive chown
  • Consider filesystem ACLs for complex permission schemes
  • Validate all paths in privileged commands

When working with systemd services that need to run under non-root users, we often encounter permission-related initialization tasks that must be executed as root before the service starts. The classic case involves directory ownership changes or permission adjustments that can't be performed by the target service user.

systemd executes all commands in the [Service] section under the configured User by default, including ExecStartPre directives. This explains why your chown attempt failed with permission errors.

The proper approach involves using + prefix in commands that need root privileges:

[Service]
User=svn
ExecStartPre=+/usr/bin/mkdir -p /run/svnserve
ExecStartPre=+/usr/bin/chown svn:svn /run/svnserve
ExecStart=/usr/bin/svnserve --daemon --pid-file=/run/svnserve/svnserve.pid -r /repos/svn

For more complex pre-launch sequences, consider using sudo or runuser:

ExecStartPre=/usr/bin/sudo -u root /usr/bin/chown svn:svn /run/svnserve

Here's the full solution incorporating proper directory handling:

[Unit]
Description=Subversion Server
After=syslog.target network.target

[Service]
User=svn
Type=forking
Environment=HOME=/repos/svn
ExecStartPre=+/usr/bin/mkdir -p /run/svnserve
ExecStartPre=+/usr/bin/chown svn:svn /run/svnserve
ExecStartPre=+/usr/bin/chmod 750 /run/svnserve
ExecStart=/usr/bin/svnserve --daemon --pid-file=/run/svnserve/svnserve.pid -r /repos/svn
PIDFile=/run/svnserve/svnserve.pid

[Install]
WantedBy=multi-user.target

When using the + prefix:

  • Limit privileged commands to essential operations
  • Use absolute paths for all commands
  • Consider creating a separate systemd-tmpfiles configuration for persistent directory setup

If issues persist, try:

# View complete service output
journalctl -u svnserve -b

# Test commands manually
sudo -u svn /usr/bin/svnserve --foreground --pid-file=/run/svnserve/svnserve.pid -r /repos/svn