FreeBSD 12.1 Guide with rc.d script to start OctoPrint Automatically and as a Service

Hi,
I haven't seen much mention of using OctoPrint with FreeBSD so I just wanted to let people know that OctoPrint works perfectly on the FreeBSD 12.1 operating system! It is pretty straight forward to install using a virtual python environment but what people may not know is how to write a script in FreeBSD to have OctoPrint start automatically at startup and also to allow it to be controlled like a normal FreeBSD system service with "service octoprint {start,status,reset,stop,start}". So here is an rc.d startup script that I made that uses a non-privileged user instead of root with "iknowhatiamdoing" flag because it's not good to run OctoPrint as root for many reasons but especially security. Notes I wrote for myself are included at the top of the script may be helpful. Remember to add the user to the "dialer" group so it can access the USB serial port that connects to the 3D Printer. Enjoy!

#!/bin/sh

# PROVIDE: octoprint
# REQUIRE: NETWORKING
# KEYWORD: shutdown

# *******DESCRIPTION: FreeBSD 12.1 - rc.d script for the 3D Printer Software OctoPrint. This script takes advantage of FreeBSD's rc.subr framework to start OctoPrint automatically at startup and to allow it to be controlled as a FreeBSD service (eg. service octoprint start).  This script assumes you are running OctoPrint as a virtual python environment (py27-virtualenv), but it can easily be changed if you want.
# *******HELP:
# 1. To increase security we want to avoid running it as root so create a user named "octoprint" (or any name you want but then change the script to reflect the change) and add the user to the "dialer" group so it can access the USB serial port that connects to the 3D Printer.
# 2. Add the line "octoprint_enable=yes" to the end of "etc/rc.conf" this will enable and start OctoPrint at boot time.
# 3. Place this rc.d script file in "usr/local/etc/rc.d/"  (make sure this file is executable, if not run: "chmod +x /usr/local/etc/rc.d/octoprint")
# 4. Make sure the variables below such as, "command", "octoprint_basedir", "command_interpreter", etc..., reflect the correct paths to your octoprint executable, base directory, and virtual python executable (if you are using a virtual python environment like this script does). 
# 5. After startup the service can be controlled like any other service "service octoprint {start,status,reset,stop,start}"

. /etc/rc.subr

name=octoprint
rcvar="octoprint_enable"

: ${octoprint_enable:=no}

octoprint_user=octoprint
octoprint_group=${octoprint_user}
octoprint_user_path="/usr/home/${octoprint_user}"
octoprint_basedir="${octoprint_user_path}/.octoprint"

command_interpreter="${octoprint_user_path}/OctoPrint/venv/bin/python2.7"
command="${octoprint_user_path}/OctoPrint/venv/bin/${name}"
command_args="serve --basedir ${octoprint_basedir} > /dev/null 2>&1 &"

load_rc_config $name
run_rc_command "$1"
4 Likes

Thanks rob! I wish to be an FreeBSD expert like you one day.
I follow your guide and everything worked perfectly.

However in my case octoprint was a litttle slower and not respondig as fast as it should.
Looking at the .log I found:

2020-11-07 11:05:54,989 - octoprint.util.pip - INFO - pip installs to /usr/home/octoprint/OctoPrint/venv/lib/python3.7/site-packages (writable -> no), --user flag needed -> no, virtual env -> yes
2020-11-07 11:05:54,989 - octoprint.util.pip - INFO - ==> pip ok -> NO!

so to fix this I hat to su and then
chmod 775 /usr/home/octoprint/OctoPrint/venv/lib/python3.7/site-packages

after that I tested if everything was ok, as user octoprint I did
test -w /usr/home/octoprint/OctoPrint/venv/lib/python3.7/site-packages && echo "YES" || echo "NO"

after that Octoprint was happy and the UI was normal and not sticky as before...

BTW,

it could be sensible to add the user octoprint to the operator group so Octoprint can poweroff the FreeBSD box and mount a USB drive in case of a firmware update...

1 Like

to make all the updates possible, even octoprint to a newest version you need to

chmod -R 775 /usr/home/octoprint/OctoPrint/venv/lib/python3.7/site-packages
chmod -R 775 /usr/home/octoprint/OctoPrint/venv/bin

Reading all the above, I still had zero clue how to install octoprint.
And wondered why nobody ever made a port.
So as I didn't find anything, I was starting to do so myself, but then stumbled upon already present values for octroprint in /usr/ports/UIDs and /usr/ports/GIDs

A bit of searching brought brought me to
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=213327
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=213842

But no trace of when and why the port is gone.
Based on what I found I recreated something current - but I'm not allowed to upload .shar files nor even .txt files.
Let me try to copy/paste that in a separate reply.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#       www/py-octoprint
#       www/py-octoprint/files
#       www/py-octoprint/files/octoprint.in
#       www/py-octoprint/pkg-descr
#       www/py-octoprint/pkg-plist
#       www/py-octoprint/distinfo
#       www/py-octoprint/Makefile
#
echo c - www/py-octoprint
mkdir -p www/py-octoprint > /dev/null 2>&1
echo c - www/py-octoprint/files
mkdir -p www/py-octoprint/files > /dev/null 2>&1
echo x - www/py-octoprint/files/octoprint.in
sed 's/^X//' >www/py-octoprint/files/octoprint.in << '57fdb464397893c4c80c50d91280245e'
X#!/bin/sh
X
X# $FreeBSD$
X#
X# PROVIDE: octoprint
X# REQUIRE: LOGIN
X# KEYWORD: shutdown
X#
X
X. /etc/rc.subr
X
Xname=octoprint
Xrcvar=octoprint_enable
Xdesc="OctoPrint 3D printer control daemon"
X
Xload_rc_config $name
X
Xcommand=%%PREFIX%%/bin/$name
Xpidfile=/var/run/$name/$name.pid
Xcommand_interpreter=%%PYTHON%%
X
Xeval ": \${${name}_enable:=NO}
Xeval ": \${${name}_host=0.0.0.0}
Xeval ": \${${name}_port=5000}
Xeval ": \${${name}_flags:="--basedir %%HOME%% --host $octoprint_host --port $octoprint_port --pid $pidfile"}
Xeval ": \${${name}_user:=\"%%USERS%%\"}"
Xeval ": \${${name}_group:=\"%%GROUPS%%\"}"
X
X# octoprint_flags="daemon $octoprint_flags start"
X# octoprint_env=PYTHON_EGG_CACHE=%%HOME%%
X#command_args="daemon $octoprint_flags --pid $pidfile start"
X
X
Xocto_prestart()
X{
X
X#      # octoprint_flags gets appended when we don't want it to.
X#      rc_flags=""
X
X       if [ ! -d /var/run/${name} ]; then
X#              install -d -o ${user} -g ${group} -m 755 /var/run/${name}
X               install -d -o ${user} -g ${group} /var/run/${name}
X       fi
X       if [ ! -d /var/db/${name} ]; then
X               install -d -o ${user} -g ${group} /var/db/${name}
X       fi
X}
X
Xrun_rc_command "$1"
57fdb464397893c4c80c50d91280245e
echo x - www/py-octoprint/pkg-descr
sed 's/^X//' >www/py-octoprint/pkg-descr << '6a721191ce2946e940f72622b64dc4e1'
XSnappy web interface for your 3D printer. OctoPrint allows full remote
Xcontrol and monitoring, it's compatible and extendable, and it's 100%
Xopen source.
6a721191ce2946e940f72622b64dc4e1
echo x - www/py-octoprint/pkg-plist
sed 's/^X//' >www/py-octoprint/pkg-plist << 'cc3de245a7f31f290cd36b478871011d'
X@dir(octoprint,octoprint,755) /var/run/octoprint
X%%PYTHON_SITELIBDIR%%/octoprint/templates/_data/AUTHORS.md
X%%PYTHON_SITELIBDIR%%/octoprint/templates/_data/SUPPORTERS.md
X%%PYTHON_SITELIBDIR%%/octoprint/templates/_data/THIRDPARTYLICENSES.md
X
cc3de245a7f31f290cd36b478871011d
echo x - www/py-octoprint/distinfo
sed 's/^X//' >www/py-octoprint/distinfo << '1e6b800daa3d0545eea4f06f2e7af676'
XTIMESTAMP = 1668596308
XSHA256 (OctoPrint-OctoPrint-1.8.6-7d336bd_GH0.tar.gz) = 71bb91356770ff43c82bd24ab44f7df80c0fd30504d6c931a2a093e8039c6d6a
XSIZE (OctoPrint-OctoPrint-1.8.6-7d336bd_GH0.tar.gz) = 6221633
1e6b800daa3d0545eea4f06f2e7af676
echo x - www/py-octoprint/Makefile
sed 's/^X//' >www/py-octoprint/Makefile << '577f38d00e1a2e89d424842c4d74cc06'
XPORTNAME=      octoprint
XPORTVERSION=   1.8.6
XCATEGORIES=    www python
XPKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
X
XMAINTAINER=    bsdports@kyle-evans.net
XCOMMENT=       Web interface for controlling a 3D printer
XWWW=           http://octoprint.org/
X
XLICENSE=       AGPLv3
XLICENSE_FILE=  ${WRKSRC}/LICENSE.txt
X
X# find the current list of deps in work-py38/OctoPrint-*/setup.py
XRUN_DEPENDS=   ${PYTHON_PKGNAMEPREFIX}argon2-cffi>=21.3.0:security/py-argon2-cffi@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}cachelib>0:www/py-cachelib@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}click>=8.0.3:devel/py-click@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}colorlog>=6:devel/py-colorlog@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}emoji>=1.4.2:misc/py-emoji@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}feedparser>=6.0.8:textproc/py-feedparser@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}filetype>=1.0.7:devel/py-filetype@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}Flask>=2.1:www/py-flask@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}Flask-Assets>=2.0:www/py-flask-assets@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}flask-babel>0:devel/py-flask-babel@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}Flask-Login>0.6:www/py-flask-login@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}Flask-Principal>=0.4:www/py-flask-principal@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}frozendict>=2.0:devel/py-frozendict@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}future>=0.18.2,<1:devel/py-future@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}markdown>=3.2.2:textproc/py-markdown@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}netaddr>=0.8,<0.9:net/py-netaddr@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}netifaces>=0.11:net/py-netifaces@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}pkginfo>=1.7.1:sysutils/py-pkginfo@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}psutil>=5.8:sysutils/py-psutil@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}pylru>=1.2:devel/py-pylru@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}pyserial>=3.4:comms/py-pyserial@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}yaml>=5.4.1:devel/py-yaml@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}requests>=2.26.0:www/py-requests@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}sarge>=0.1.6:devel/py-sarge@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}semantic-version>=2.8.5:devel/py-semantic-version@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}sentry-sdk>=1.5.7:devel/py-sentry-sdk@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}tornado>=6.0.4:www/py-tornado@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}watchdog>=1:devel/py-watchdog@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}websocket-client>0:www/py-websocket-client@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}werkzeug>0:www/py-werkzeug@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}wrapt>=1.13.3:devel/py-wrapt@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}zeroconf>0.36:net/py-zeroconf@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}blinker>=1.4:devel/py-blinker@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}regex>0:textproc/py-regex@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}unidecode>0:converters/py-unidecode@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}awesome-slugify>=1.6.5:textproc/py-awesome-slugify@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}chainmap>=1.0.2:devel/py-chainmap@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}future>=0.15.2:devel/py-future@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}passlib>=1.7.4:security/py-passlib@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}rsa>=3.5:security/py-rsa@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}scandir>=1.3:sysutils/py-scandir@${PY_FLAVOR} \
X               ${PYTHON_PKGNAMEPREFIX}sockjs-tornado>=1.0.2:www/py-sockjs-tornado@${PY_FLAVOR}
X# Last 7 are probably absolete
X# Still desired or required:
X#    "Flask-Limiter>2.6",
X#    "pathvalidate>2.4.1",
X#    "zipstream-ng>1.3.4",
X
X#    "develop": [
X#        "ddt>0",
X#        "mock>=4",
X#        "pytest-doctest-custom>=1",
X#        "pytest>=6.2.5",
X#        "pre-commit>0",
X#        "pyinstrument>0",
X
X#    "plugins": ["cookiecutter>=1.7.2"],
X
XUSES=          python
X
XUSE_GITHUB=    yes
X#GH_ACCOUNT=   kevans91
XGH_ACCOUNT=    OctoPrint
XGH_PROJECT=    OctoPrint
XGH_TAGNAME=    7d336bd
X
XUSE_PYTHON=    autoplist distutils
XUSE_RC_SUBR=   octoprint
XSUB_LIST+=     PYTHON=${PYTHON_CMD} \
X               HOME=${PREFIX}/octoprint
X
XUSERS=         octoprint
XGROUPS=                octoprint
X
XOPTIONS_DEFINE=        DOCS
X
XDOCS_BUILD_DEPENDS=    ${PYTHON_PKGNAMEPREFIX}sphinx>=3:textproc/py-sphinx@${PY_FLAVOR} \
X                       ${PYTHON_PKGNAMEPREFIX}sphinx_rtd_theme>0:textproc/py-sphinx_rtd_theme@${PY_FLAVOR} \
X                       ${PYTHON_PKGNAMEPREFIX}sphinxcontrib-httpdomain>0:textproc/py-sphinxcontrib-httpdomain@${PY_FLAVOR}
X# Still desired or required:
X#                      ${PYTHON_PKGNAMEPREFIX}sphinxcontrib-mermaid
X#                      ${PYTHON_PKGNAMEPREFIX}readthedocs-sphinx-ext
X
Xpost-extract:
X       @${MKDIR} ${STAGEDIR}/var/run/octoprint
X#.if ${PORT_OPTIONS:MDOCS}
X#      @${MV} ${STAGEDIR}${DATADIR}/docs ${STAGEDIR}${DOCSDIR}
X#.else
X#      @${RM} -r ${STAGEDIR}${DATADIR}/docs
X#.endif
X
Xpost-patch:
X       ${RM} -rf ${WRKSRC}/src/octoprint/plugins/softwareupdate
X
X
X.include <bsd.port.mk>
577f38d00e1a2e89d424842c4d74cc06
exit

It was tested all perfect using the tools portlint, portclippy, portfmt and poudriere on 13.1 AMD
But I haven't used it yet.