Solved MeshCentral RC service script help

I've formulated an rc script for meshcentral, and have a question.

Why would this work
Code:
#!/bin/sh
#
# MeshCentral FreeBSD Service Script
#
#

# PROVIDE: meshcentral
# REQUIRE: NETWORKING
# KEYWORD: shutdown

. /etc/rc.subr

name=meshcentral
desc="MeshCentral Computer Management"
rcvar=meshcentral_enable

load_rc_config $name

: ${meshcentral_enable:="NO"}
: ${meshcentral_args:=""}
: ${meshcentral_chdir:="/usr/local/meshcentral"}
: ${meshcentral_rundir:="/var/run/${name}"}
: ${meshcentral_logdir:="/var/log/${name}"}
: ${meshcentral_pidfile:="${meshcentral_rundir}/${name}.pid"}
: ${meshcentral_logfile:="${meshcentral_logdir}/${name}.log"}

user="meshcentral"
group="meshcentral"
node="/usr/local/bin/node"
command="/usr/sbin/daemon"
command_args="-u ${user} -P ${meshcentral_pidfile} -H -o ${meshcentral_logfile} ${node} node_modules/${name} ${meshcentral_args}"

start_precmd="meshcentral_startprecmd"

meshcentral_startprecmd()
{
    if [ ! -d ${meshcentral_rundir} ]; then
        install -d -o ${user} -g ${group} ${meshcentral_rundir};
    else
        chown -R ${user}:${group} ${meshcentral_rundir};
    fi
    if [ ! -d ${meshcentral_logdir} ]; then
        install -d -o ${user} -g ${group} ${meshcentral_logdir};
    else
        chown -R ${user}:${group} ${meshcentral_logdir};
    fi
}

run_rc_command "$1"

But this wont
Code:
#!/bin/sh
#
# MeshCentral FreeBSD Service Script
#
#

# PROVIDE: meshcentral
# REQUIRE: NETWORKING
# KEYWORD: shutdown

. /etc/rc.subr

name=meshcentral
desc="MeshCentral Computer Management"
rcvar=meshcentral_enable

load_rc_config $name

: ${meshcentral_enable:="NO"}
: ${meshcentral_args:=""}
: ${meshcentral_chdir:="/usr/local/meshcentral"}
: ${meshcentral_rundir:="/var/run/${name}"}
: ${meshcentral_logdir:="/var/log/${name}"}
: ${meshcentral_pidfile:="${meshcentral_rundir}/${name}.pid"}
: ${meshcentral_logfile:="${meshcentral_logdir}/${name}.log"}
: ${meshcentral_group:="meshcentral"}
: ${meshcentral_user:="meshcentral"}

node="/usr/local/bin/node"
command="/usr/sbin/daemon"
command_args="-u ${meshcentral_user} -P ${meshcentral_pidfile} -H -o ${meshcentral_logfile} ${node} node_modules/${name} ${meshcentral_args}"

start_precmd="meshcentral_startprecmd"

meshcentral_startprecmd()
{
    if [ ! -d ${meshcentral_rundir} ]; then
        install -d -o ${meshcentral_user} -g ${meshcentral_group} ${meshcentral_rundir};
    else
        chown -R ${meshcentral_user}:${meshcentral_group} ${meshcentral_rundir};
    fi
    if [ ! -d ${meshcentral_logdir} ]; then
        install -d -o ${meshcentral_user} -g ${meshcentral_group} ${meshcentral_logdir};
    else
        chown -R ${meshcentral_user}:${meshcentral_group} ${meshcentral_logdir};
    fi
}

run_rc_command "$1"

The only thing that changed is the user variable. When I use the first script, things just work.
But when I try to use the second one, daemon start complaining "could not set user environment" or "initgroup meshcentral failed"

The user was created with
pw user add meshcentral -c meshcentral -u 6374 -s /usr/sbin/nologin -d /home/meshcentral -m

Or would it be best not to run it as a daemon, and use “su -m ${meshcentral_user}” instead?
 
And tips for improving it are also welcome...

Also, what is best practice for running services? Custom user? Root? And why?
 
Also, what is best practice for running services?
Depends on the service. Apache for example is started as root but drops privileges on its own. Other services never drop privileges and directly started on some user account. Judging by the -u option of meshcentral it will drop privileges on its own?
 
Seems to have something to do with the name being the same as the service in the default variable config, because it works when simply using “user=“

If there are no objections, I’ll just use the one that I shared in the OP.
 
And further testing shows that just setting the "meshcentral_user" variable results in the same error. Oh well. Putting this to rest as it does work by just using "user" variable.
 
I see what is happening. According to https://man.freebsd.org/cgi/man.cgi?query=rc.subr(8)&sektion=&manpath=freebsd-release-ports if the "meshcentral_name" variable is set, the it will try to execute the "daemon" command as the meshcentral user, instead of having daemon run the command as the meshcentral user. I see now...

Code:
${name}_user
                 User  to  run  command  as,  using     chroot(8)  if
                 ${name}_chroot  is     set,  otherwise  uses    su(1).
                 Only supported after /usr is mounted.
 
More study reveals that there might be an underlying issue with the meshcentral process needing npm rights.

If I run su -m meshcentral then it always fails with an error that it can’t access NPM or doesn’t have the rights to use it.

But when I do daemon -u meshcentral then things just work.

I can still su meshcentral and switch to the meshcentral user itself, then run the commands needed and that works. So I’m not sure what exactly is going on…
 
Did you find any solution to run meshcentral via daemon or even in the background at all?


I've been trying even the ugliest workarounds for hours now, but it seems this toy language always requires an open terminal/stdout to run - no matter what I try to run it in the background or as a service, it simply won't start. If it starts with some variant, it is still attached to the terminal and it also won't start automatically at boot (because then there is no terminal attached to it), so one always has to start the service manually and then that terminal needs to stay open or node will crash.

If I use daemon without -f, it will start when invocated manually, but the terminal in which I issue a 'service meshcentral start' becomes completely unusable - i.e. it interferes with typing (lots of missed characters) and occassionally there are (partial) messages popping up from the child (node) which is supposed to run in the background and shut up.
Of course it also won't start automatically at boot despite it being enabled in rc.conf - very likely because it doesn't have an actual user-facing terminal to annoy a human...

In the meshcentral installation documentation for OpenBSD, they expect you to run it from crontab (@reboot doas -u _meshcentral /usr/local/bin/node /usr/local/meshcentral/node_modules/meshcentral/meshcentral.js --launch), which - what a surprise - also does not work.


From various search results it seems node is "broken by design" in this regard, and one needs yet another node gadget called 'forever' to run a node script as a service. But 'forever' is ridden with security vulnerabilities and bugs and most importantly won't drop privileges (the '--uid' option is for some namespace-crap, not for specifying an actuall uid it will run the script as), so everything runs as root, which is completely unacceptable (and breaks stuff with meshcentral).
Trying to daemon-ize forever to run it as another user of course also fails because of the initial reason why one should use it...


I'd really like to evaluate meshcentral as an alternative to anydesk, but if this thing can't even run as a proper service that's simply a hard fail...

So is there any sane way to run node scripts as a service or should one just follow common sense and simply don't use javascript on a server?
 
Back
Top