I have a python script that I would like to run in a Freenas jail. It works without the service daemon, but I would like to start it as a service. I have created the following service script /etc/rc.d/attendance


# PROVIDE: attendance
# KEYWORD: shutdown

. /etc/rc.subr


load_rc_config $name

: ${attendance_enable="NO"}

run_rc_command "$1"

I have also added attendance_enable="YES" under /etc/rc.conf

When I run, service attendance start I recieve

Starting attendance
limits: /root/Zkteco/app.py: No such file or directory
/etc/rc.d/attendance: WARNING: failed to start attendance

Event though the directory exists, I tried moving it from /etc/rc.d/attendance to /usr/local/etc/rc.d/attendance and it seems to work, but it never goes as a background process either and I have to CTRL+C to stop it.

Any recommendation? The script is a webapp using fastapi and uvicorn, doest it have anything to do with it? How can I see the logs of the service error trying to start.

Thing I've tried

I created a binary with pyinstaller --onefile from the script. And changed

run_rc_command "$1

This change made the service start but again, it never goes to background.

1 Answer 1


The files in /etc/rc.d is considered part of the operating system and managed by that. You should only be working with /usr/local/etc/rc.d. Notice that this is the location rc scripts for all packages are placed as well.

rc.d is a service management framework. But it does nothing to create a "service" or more accurately "to daemonize a process". It is in place to give a uniform way to handle the "services".

You noticed that as your app did not drop to the background as you expected and you needed to CTRL-C out. Your expectations are not in line with what should happen. It is the responsibility of your script/program/app to daemonize itself (go to the background etc.). The rc script is only a wrapper around your application.

I do not know your app nor uvicorn very well. But from the documentation uvicorn does not seem to support daemonizing itself. This will typically happen when specifying a command line parameter. Your basic test for this is: Are you able to run your app from the command line and have it detach from the console by itself?

If you want a pure Python way to do that then have a look at PEP 3143 – Standard daemon process library.

The easy FreeBSD approach would be to utilize daemon(8). A very simple example would be:



. /etc/rc.subr

command_args="-c -f -P ${pidfile} -u ${attendance_user} -r /usr/local/bin/app"

load_rc_config $name
run_rc_command "$1"

(See Is there an easy way to create a FreeBSD rc script? and FreeBSD rc.d script doesn't start as a daemon)

I notice that you placed your app in /root. It smells like you are running things as root. It is a good practice to run things as an unprivileged user.

This should work for your simple case. If this is a proper production rollout you need to do more but that is due to uvicorn and not FreeBSD. If you read up on https://www.uvicorn.org/deployment/ you will notice that in production you would often use gunicorn and maybe nginx as well.

The above is the "proper" FreeBSD way of doing things. If you like to use FreeBSD this is good to learn and work with.

But if you are more of a Python/web programmer and find it daunting to setup gunicorn etc. Then you might find it easier to install supervisord. It is easily installed as a package sysutils/py-supervisor/. This can been seen as an alternative to rc/daemon and you will find a lot more examples online specifically for use with Python web projects.

  • thank you a lot for the clear explanation. I thought it was like in linux where the daemon takes care of the service for everything. I ended up using supervisor for the program. I was using /root because I was inside a jail. It works now and it is pretty clear
    – Ukhu
    May 9, 2023 at 17:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .