How to Write PID Files in /var/run Without Root Group Permissions on Ubuntu


3 views

On Ubuntu systems, /var/run typically has these permissions:

drwxr-xr-x  9 root root  4096 Mar 15 09:00 /var/run

This means only root can create files directly in this directory. When your daemon (running as a non-root user) attempts to create a PID file there, you'll encounter:

touch: cannot touch /var/run/test.pid': Permission denied

Here are several solutions, ordered by recommended practice:

1. Use /run/user or Systemd's RuntimeDirectory

Modern systems provide better alternatives:

# For systemd services
RuntimeDirectory=myprogram
RuntimeDirectoryMode=0755

This creates /run/myprogram automatically.

2. Directory Ownership During Installation

If you're creating a package, set this in postinst:

#!/bin/sh
set -e
mkdir -p /var/run/myprogram
chown myprogram-user:myprogram-group /var/run/myprogram
chmod 755 /var/run/myprogram

3. Temporary Directory Approach

For non-package installations:

PID_DIR="/var/run/myprogram"
if [ ! -d "$PID_DIR" ]; then
    install -d -o myprogram-user -g myprogram-group -m 0755 "$PID_DIR"
fi

Here's how to properly implement this:

#!/bin/sh

PIDFILE="/var/run/myprogram/myprogram.pid"
DAEMON_USER="myprogram-user"

# Ensure PID directory exists
if [ ! -d "$(dirname "$PIDFILE")" ]; then
    install -d -o "$DAEMON_USER" -g "$DAEMON_USER" -m 0755 "$(dirname "$PIDFILE")"
fi

start-stop-daemon --start --chuid "$DAEMON_USER" \
    --pidfile "$PIDFILE" --make-pidfile \
    --exec /usr/bin/myprogram -- $OPTIONS

For systemd systems, create /etc/tmpfiles.d/myprogram.conf:

d /var/run/myprogram 0755 myprogram-user myprogram-group -

This directory will be created at boot with correct permissions.

When implementing PID file handling:

  • Never run your daemon as root just to write PID files
  • Avoid world-writable directories
  • Consider using abstract namespace sockets for modern applications
  • Implement proper file locking when writing PID files

If issues persist:

# Check directory permissions
ls -ld /var/run/myprogram

# Verify user can write
sudo -u myprogram-user touch /var/run/myprogram/test.tmp

# Check for SELinux/AppArmor
dmesg | grep avc
aa-status

On modern Ubuntu systems (using systemd), /var/run is typically a symlink to /run, which has the following permissions:

drwxr-xr-x 9 root root 180 Apr 10 15:30 /run

This directory is specifically designed for runtime variable data and traditionally requires root privileges for writing. For daemons that need to write PID files here, we have several approaches.

For systemd services, the recommended approach is to use PrivateTmp:

[Service]
User=my-program-user
PrivateTmp=yes
RuntimeDirectory=my-program
PIDFile=/run/my-program/pid

This automatically creates a subdirectory under /run with proper permissions.

If you're not using systemd, you can create a dedicated directory during package installation:

# In postinst script of your deb package
install -d -o my-program-user -g my-program-group /var/run/my-program
chmod 755 /var/run/my-program

When using start-stop-daemon with a non-root user, specify both the --pidfile and --make-pidfile options:

start-stop-daemon --start --chuid my-program-user \
  --pidfile /var/run/my-program.pid --make-pidfile \
  --exec /usr/sbin/my-program

For system persistence, create a configuration file in /etc/tmpfiles.d/my-program.conf:

d /run/my-program 0755 my-program-user my-program-group -

This ensures the directory is created with correct permissions at boot.

If you still encounter problems, check:

  • Effective permissions with namei -l /var/run/my-program.pid
  • Process capabilities with getcap /usr/sbin/my-program
  • SELinux/AppArmor denials in system logs