In a development environment I installed radicale, a CalDAV/CardDAV server. I know I can install radicale via pkg or from ports, but this one I installed locally in a user account,
I created the according files and users:
So everything looks ok, but the service fails to start because it lacks permissions when executing initgroups():
And here I'm stuck, and so is grok. It works if I modify the rc script to run the radical service as the root user (just omitting the -u parameter of daemon():
but I really don't like having a service process run as root. So, how could I solve this? Why does initgroups fail?
/home/testuser/.local/bin/radicale (I did so by uv tool install radicale). Then, with the help of the grok AI, I wrote this script to start radicale as a service, this is in /usr/local/etc/rc.d/radicale:
sh:
#!/bin/sh
# PROVIDE: radicale
# REQUIRE: DAEMON NETWORKING
# KEYWORD: shutdown
. /etc/rc.subr
name="radicale"
rcvar="radicale_enable"
extra_commands="configtest reload"
load_rc_config $name
: ${radicale_enable:="NO"}
: ${radicale_user:="radicale"}
: ${radicale_group:="radicale"}
: ${radicale_command:="/home/testuser/.local/bin/radicale"}
: ${radicale_config:="/usr/local/etc/radicale/config"}
# Logging configuration
: ${radicale_syslog_tag:="radicale"}
: ${radicale_syslog_facility:="daemon"}
: ${radicale_syslog_priority:="info"}
# Extra flags for Radicale (e.g. --debug, -D, etc.)
: ${radicale_flags:=""}
pidfile="/var/run/radicale/${name}.pid"
command="/usr/sbin/daemon"
command_args="-f -P ${pidfile} \
-u ${radicale_user} \
-l ${radicale_syslog_facility} \
-s ${radicale_syslog_priority} \
-T ${radicale_syslog_tag} \
${radicale_command} \
${radicale_flags} \
-C ${radicale_config}"
# Prepare pid directory before starting
start_precmd="radicale_precmd"
radicale_precmd() {
install -d -o ${radicale_user} -g ${radicale_group} -m 700 /var/run/radicale
}
# Custom commands
radicale_configtest() {
echo "Performing config test for Radicale..."
if [ ! -f "${radicale_config}" ]; then
echo "ERROR: Config file not found: ${radicale_config}"
return 1
fi
if [ ! -r "${radicale_config}" ]; then
echo "ERROR: Config file is not readable: ${radicale_config}"
return 1
fi
echo "Config file found and readable: ${radicale_config}"
echo "Running basic verification..."
if su -m "${radicale_user}" -c "${radicale_command} --verify-storage -C ${radicale_config}" 2>&1 | head -n 30; then
echo "Storage verification passed."
return 0
else
echo "Storage verification completed (check output above for warnings)."
return 0
fi
echo "Config test completed."
}
radicale_reload() {
echo "Reloading Radicale configuration..."
if [ -f "${pidfile}" ]; then
kill -HUP $(cat "${pidfile}")
echo "Sent SIGHUP to Radicale."
else
echo "Radicale is not running (no pidfile)."
return 1
fi
}
oneconfigtest_cmd="radicale_configtest"
configtest_cmd="radicale_configtest"
reload_cmd="radicale_reload"
run_rc_command "$1"
I created the according files and users:
Code:
# getent passwd radicale
radicale:*:1003:1006:Radicale CalDAV server:/var/lib/radicale:/usr/sbin/nologin
# getent group radicale
radicale:*:1006
# service radicale oneconfigtest
Performing config test for Radicale...
Config file found and readable: /usr/local/etc/radicale/config
Running basic verification...
[2026-05-16 10:37:38 +0200] [41412] [INFO] Logging level set to: 'INFO'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Logging of backtrace is disabled in this loglevel
[2026-05-16 10:37:38 +0200] [41412] [INFO] Logging level set to: 'INFO'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Loaded default config
[2026-05-16 10:37:38 +0200] [41412] [INFO] Loaded config file '/usr/local/etc/radicale/config'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Verifying storage
[2026-05-16 10:37:38 +0200] [41412] [INFO] storage type is 'radicale.storage.multifilesystem'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage folder umask (from system): '0022'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location: '/var/lib/radicale/collections'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location permissions: path='/var/lib/radicale/collections' owner=radicale(1003) group=radicale(1006) mode=40700
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder: '/var/lib/radicale/collections/collection-root'
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder permissions: path='/var/lib/radicale/collections/collection-root' owner=radicale(1003) group=radicale(1006) mode=40755
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder softlink support: True
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder is collision free: True (case-sensitive=True no-short-filename=True)
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder supports unicode: True
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder supports trailing whitespace: True
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage location subfolder supports problematic chars: True
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage cache subfolder usage for 'item': False
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage cache subfolder usage for 'history': False
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage cache subfolder usage for 'sync-token': False
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage cache use mtime and size for 'item': False
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage item mtime resolution test result: 1 ns
[2026-05-16 10:37:38 +0200] [41412] [INFO] Storage cache using mtime and size for 'item' may be an option in case of performance issues
[2026-05-16 10:37:38 +0200] [41412] [INFO] Disable fsync during storage verification
[2026-05-16 10:37:38 +0200] [41412] [INFO] Verifying path ''
[2026-05-16 10:37:38 +0200] [41412] [INFO] Skip !collection ''
Storage verification passed.
So everything looks ok, but the service fails to start because it lacks permissions when executing initgroups():
Code:
# service radicale start
Starting radicale.
# service radicale status
radicale is not running.
# tail /var/log/messages | fgrep radicale
May 16 10:50:58 bedna radicale[41618]: initgroups(radicale,1006): Operation not permitted
And here I'm stuck, and so is grok. It works if I modify the rc script to run the radical service as the root user (just omitting the -u parameter of daemon():
sh:
# ...
command_args="-f -P ${pidfile} \
-l ${radicale_syslog_facility} \
-s ${radicale_syslog_priority} \
-T ${radicale_syslog_tag} \
${radicale_command} \
${radicale_flags} \
-C ${radicale_config}"
# ...
but I really don't like having a service process run as root. So, how could I solve this? Why does initgroups fail?