-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Service Support
A third party application packaged for Synology often provide a web user interface and users expect to get simple access to it thanks to a service shortcut.
A packager may consider running such a user interface as root is a non-affordable security risk and will push effort to get it run as non-privileged user.
As maintainer facing a large upgrade, work on packages created with copy-paste pattern of many similar files are both time consumming and error prone; so generated files from generic support appear as a requirement.
Thanks to a small set of spk Makefile variables, a package designer can
benefit from generic installer and start-stop-status scripts, with
possibility to adapt default behavior thanks to hooks as shell functions.
- User creation (
SERVICE_USER) and removal to run backgroup service process - Share folder creation based on wizard variable (
SERVICE_WIZARD_SHARE) - Group creation for managing access to share folder (
SERVICE_WIZARD_GROUP) - Service port (
SERVICE_PORT) configuration for firewall and DSM shortcut - TLS certificate (
SERVICE_CERT) integration with DSM's certificate management - Logging support in both
installerandstart-stop-statusscript - Hooks in package specific script (
SERVICE_SETUP) - A specific
start-stop-statusscript is provided for package withSTARTABLE=no
Support is enabled as far as a SERVICE_ variable is set in spk Makefile.
Package spk/demoservice is provided as non-arch example of how to design your
package and wizard screens.
If INSTALLER_SCRIPT is set with a installer script, it replaces generic one.
If SSS_SCRIPT is set with a specific start-stop script, it replaces generic one.
In any case, scripts/service-setup is generated from package variables and
SERVICE_SETUP, if provided.
For package that has been built without this new support, refer to migration guidelines.
An application shortcut is available when both SPK_ICON and SERVICE_PORT
are set in Makefile.
A single URL link is built from:
DISPLAY_NAMEDESCRIPTIONSERVICE_PORT-
SERVICE_PORT_PROTOCOL, defaults tohttp -
SERVICE_URL, defaults to/ -
SERVICE_PORT_ALL_USERS, defaults totrue
Generated ${DSM_UI_DIR}/config and icons are included in package.tgz. If
not set in Makefile, DSM_UI_DIR default value is app.
Setting NO_SERVICE_SHORTCUT prevents this file generation, typically when
SERVICE_PORT is not intended to be browsed.
For information, ADMIN_PORT, ADMIN_PROTOCOL and ADMIN_URL are also
available to generate administration link visible from Package Center entry.
To prevent user account name collision when migrating from previous busybox
usage, a prefix is added to package name to create service account:
-
sc-USERfor DSM 6 privilege framework -
svc-USERfor DSM 5synouseraccount
For usage in scripts, variable EFF_USER contains effective account name with
prefix.
conf/privilege is generated with username=sc-SPK_NAME if SERVICE_USER
variable is set, by defaults to auto.
In rare case package requires an alternate service account name, SERVICE_USER
value other than auto can be used.
For DSM 5 compatibility, installer script will create a system account with
synouser but prefixed with svc-. Script start-stop-status invokes su
to start SERVICE_COMMAND as non-priviliged user.
In case script start-stop-status has to run as root on DSM 6, package can
provide its own conf/privilege file as far as CONF_DIR variable is set.
conf/resource/SPK_NAME.sc is generated except if FWPORTS is provided in the
Makefile. By default, it configures SERVICE_PORT as tcp with port forwarding
enabled.
[SPK_NAME]
title="(SERVICE_PORT_TITLE:SPK_NAME)"
desc="(DISPLAY_NAME:SPK_NAME)"
port_forward="yes"
dst.ports="SERVICE_PORT/tcp"
If that default behaviour do not suit your need (for instance to declare two
ports), provide a package specific file relative path as FWPORTS
variable. File is then copied as conf/resource/SPK_NAME.sc and handled by
installer script as standard one.
This feature is reverse-engineered and undocumented in Synology's Package Developer Guide. Starting with DSM 7.0, packages using it even fail to install because they are using a function intended "only for Synology packages". Therefore, this functionality is ignored when building a DSM >= 7.0 package.
A configuration block is added to conf/resource if SERVICE_CERT is provided
in the Makefile. The value must be one of the service names defined in the
FWPORTS file, or the generated equivalent.
When a new certificate is assigned to the service by DSM (user change or
renewal), DSM can execute a script to cause the service to reload its
certificate. Such a script is service-specific and needs to be provided for
each package individually. The path given in the Makefile as
SERVICE_CERT_RELOAD is relative to the package directory layout after
installation, so you need copy it to the STAGING_DIR in an *_extra_install
target as appropriate.
Both generic installer and start-stop-status scripts source service-setup
script which is generated aggregating following variables and SERVICE_SETUP
script if set in spk Makefile
GROUP and SHARE_PATH can be set from wizard variable names declared in
Makefile variables SERVICE_WIZARD_GROUP and SERVICE_WIZARD_SHARE or
enforced in SERVICE_SETUP script.
When an application requires a storage location, use SHARE_PATH and
GROUP=sc-download
Open work-ARCH-TC/scripts/service-setup to read generated content if
interested in.
SERVICE_SETUP script can provide shell function invoked as hook when
installer steps are run by DSM: service_preinst, service_postinst,
service_preuninst, service_postuninst, service_preupgrade,
service_save, service_restore, service_postupgrade.
All output of above service_* functions goes to the installer log file.
To notify the user and optionally abort the installer with exit 1 there are some validate_* function provided:
validate_preinst, validate_preunint and validate_preupgrade. The user notificytion work
with DSM>=6 only.
For DSM 5 compatibility, scripts have to be designed to run with busybox.
The installer script and DSM package installer logs to /var/log/packages/${SPK_NAME}.log.
Only for DSM<=5 the installer script logs to /tmp/${SPK_NAME}_install.log and if successfully
installed file is copied as /var/packages/${SPK_NAME}/target/var/${SPK_NAME}_install.log.
By defaults on DSM 5, only var folder is writable by service account. If
required, add required commands in service_postinst shell function in package
specific SERVICE_SETUP script.
Wizard variables are stored in
/var/packages/${SPK_NAME}/etc/installer-variables so that they can be
retreived and used in uninstall or upgrade.
start-stop-status generic script starts SERVICE_COMMAND as non-privileged
user, account name defaults to package name SPK_NAME except if SERVICE_USER
is different from auto.
Package status feedback relies on pid file
/var/packages/${SPK_NAME}/target/var/${SPK_NAME}.pid available as PID_FILE
shell variable.
Service process is expected to fork in background and to provides PID_FILE
containing its own main process PID. Two means are available to do so:
-
if application supports such PID file generation,
service_postinstshell function should configure service fromPID_FILEvariable -
PID_FILEvariable has to be provided as command argument inSERVICE_COMMANDso that process writes down its own PID there, at least from shell special variable$!
Process standard output and error streams are aggregated into log file
/var/packages/${SPK_NAME}/target/var/${SPK_NAME}.log which is readable thanks
to Package Center "View Log" package action.
Script is verbose by default. This behavior can be switched off setting
variables in SERVICE_SETUP script:
-
SVC_NO_REDIRECT=yprevents process streams to be collected in package log -
SVC_QUIET=yprevents logging start/stop date and action -
SVC_KEEP_LOG=yprevent log content to be cleared before each startup
Following options can be set in SERVICE_SETUP script:
-
SERVICE_SHELLcan be used to replace default/bin/shon DSM 5 only -
SVC_WAIT_TIMEOUTis the delay for script to wait forPID_FILEto appear at process startup (and disappear when stopping). Default value is 20 seconds
In service-setup.sh, set SVC_BACKGROUND=y in addition to SERVICE_COMMAND
to get it started as background process (from shell thanks to &)
In case process is not able to write its own PID in a file thanks to command
line option, then set also SVC_WRITE_PID=y so that generic
start-stop-status script generates PID_FILE itself. This option only make
sense if SVC_BACKGROUND=y is set.
In case application binary does not support background execution, a work-around
is to execute command from service_prestart instead of setting
SERVICE_COMMAND. This prevents to create an additional script to do so.
SERVICE_USER = auto
SERVICE_SETUP = src/service-setup.sh
STARTABLE = yes
In src/service-setup.sh, replace generic command execution with shell
background execution and PID_FILE generation. LOG_FILE can be use to
collect stderr and stdout. Example from demoservice:
service_prestart ()
{
# Replace generic service startup, fork process in background
echo "Starting python -m SimpleHTTPServer ${SERVICE_PORT} at ${SYNOPKG_PKGDEST}" >> ${LOG_FILE}
COMMAND="python -m SimpleHTTPServer ${SERVICE_PORT}"
if [ $SYNOPKG_DSM_VERSION_MAJOR -lt 6 ]; then
su ${EFF_USER} -s /bin/sh -c "cd ${SYNOPKG_PKGDEST}; ${COMMAND}" >> ${LOG_FILE} 2>&1 &
else
cd ${SYNOPKG_PKGDEST};
${COMMAND} >> ${LOG_FILE} 2>&1 &
fi
echo "$!" > "${PID_FILE}"
}
In case application binary has to start as root and forks to non-privileged
user from parameter (with setuid syscall), it is possible to keep benefit of
SERVICE_USER support.
CONF_DIR = src/conf
SERVICE_USER = auto
SERVICE_SETUP = src/service-setup.sh
STARTABLE = yes
Provide a specific src/conf/privilege, using package name in sc-USER,
defaults remain package so that files are own by service user:
{
"defaults":{
"run-as": "package"
},
"username": "sc-USER",
"ctrl-script": [{
"action": "preinst",
"run-as": "root"
}, {
"action": "postinst",
"run-as": "root"
}, {
"action": "preuninst",
"run-as": "root"
}, {
"action": "postuninst",
"run-as": "root"
}, {
"action": "preupgrade",
"run-as": "root"
}, {
"action": "postupgrade",
"run-as": "root"
}, {
"action": "start",
"run-as": "root"
}, {
"action": "stop",
"run-as": "root"
}]
}
In SERVICE_SETUP, execute application specific startup command:
service_prestart ()
{
COMMAND="${SYNOPKG_PKGDEST}/bin/appservice --background --user ${EFF_USER} --pidfile ${PID_FILE}"
# Run as root in both DSM 5 and 6
${COMMAND} >> ${LOG_FILE} 2>&1
}
REMARKS: Since DSM 7 this is outdated and not supported anymore.
It is possible to replace generic start-stop-status support by usage of
BusyBox start-stop-daemon (for instance provided by Python package).
In package Makefile, provide following variables:
-
SERVICE_EXEis process executable absolute path -
SERVICE_OPTIONSis optional set of command line options to pass to process - Do not set
SERVICE_COMMAND
- Home
-
Packages
- Adminer
- Aria2
- Beets
- BicBucStriim
- Borgmatic
- cloudflared
- Comskip
- Debian Chroot
- Deluge
- Duplicity
- dnscrypt-proxy
- FFmpeg
- FFsync
- Flexget
- Gstreamer
- Google Authenticator
- Home Assistant Core
- Jellyfin
- Kiwix
- [matrix] Synapse homeserver
- MinIO
- Mono
- Mosh
- Mosquitto
- Node-Exporter
- OpenList
- ownCloud
- Radarr/Sonarr/Lidarr/Jackett
- rclone
- SaltStack
- SickBeard Custom
- SynoCLI-Disk
- SynoCLI-Devel
- SynoCLI-File
- SynoCLI-Kernel
- SynoCLI-Misc.
- SynoCLI-Monitor
- SynoCLI-NET
- Synogear
- Concepts
- Development
- Resources