Before taking on this tutorial, the author assumes that:
- The end-user can comfortably install and configure their Linux distribution of choice. (For the sake of clarity, I'll be using Ubuntu 18.04 for this tutorial. Other distros, YMMV)
- The end user can install, upgrade, downgrade and resolve both conflicts and dependency resolution of packages on his/her distribution's package manager.
- That the user is comfortable with the Linux terminal, and can navigate through it.
- Basic competence on the shell, such as reading man files, using a text editor of choice, manipulating file operations on the same, etc is assumed.
- Some advanced features require specific hardware (High-performance hardware encoding utilizes Intel's QuickSync, requires a relatively new Intel CPU with integrated graphics)
Many of the commands and groups of commands in this guide are using generic names and addresses that can be customized. I tried to use defaults that make sense, but if you want to make changes, feel free. Setup guides for nginx, ffmpeg, ffserver, etc, are readily available onliine and can be referenced to make this easier.
You can also add as many octoprint instances as your hardware is capable of handling. Simply add an additional iteration with a unique name and port.
Recommended setup option:
- When creating a user, there is a box to specify the name of the server. Choose something easy to remember, as you can use the system's name in an address like
server-name.local
- If you plan to just copy and paste the commands here, simply name your server '
octoprint
' - This local address scheme also requires a router/modem that is capable of utilizing mDNS / avahi / bonjour. This is also sometimes called uPNP
# Update package info
sudo apt update && \
# Upgrade any packages with available updates
sudo apt upgrade -y && \
# Update kernel modules with available updates
sudo apt dist-upgrade -y && \
sudo apt install -y \
# git protocol for pulling from github and other repos
git \
# octoprint and many other applicatios run on this interpreter
python3 \
# python's in-built package manager
python3-pip \
# SSH server, allows remote terminal control over network
openssh-server \
# Webserver, used in this case for reverse-proxy (octoprint.local/printer0 instead of 192.168.1.123:5000)
nginx \
# Video encoding application. Needed for webcam streams
ffmpeg \
# AKA Bonjour|mDNS, allows local networks to utilize the server's self-configured hostname in place of an IP address
avahi-daemon
sudo apt install -y \
# Allows remote desktop view of the server's GUI
x11vnc \
# My personal preferred terminal text editor
vim \
# Allows users to search for files by name or regex
locate \
# Allows users to view the thermal sensor and voltage readings from hardware
lm-sensors \
# For non-ubuntu debian-based installs, this is used primarily in MOTD login notifications
update-notifier-common \
# Package contains binaries like ifconfig, which were removed between Ubuntu 16 and 18
net-tools \
# Allows other systems to access NFS shares on this server
nfs-kernel-server \
# Allows this server to access NFS shares on other systems
nfs-common \
# Allows other systems to access Windows SMB protocol shared folders
samba \
# Allows this server to mount Windows SMB network shared folders
cifs-utils
sudo sensors-detect --auto # first-time setup for lm-sensors
sudo updatedb # Initial database creation for locate
# You will be prompted to make a password and supply user data. Only the password is required, all other fields can be left blank
sudo adduser octoprint0
sudo adduser octoprint1
su octoprint0 # You will be prompted to enter the password for this user
cd ~
pip install --upgrade --user pip # installs latest pip version to user's local environment
# DO NOT OMIT THE --user FLAG! This can cause serious issues with your system's default pip instance!
~/.local/bin/pip install --user https://get.octoprint.org/latest
exit
su octoprint1 # You will be prompted to enter the password for this user
cd ~
pip install --upgrade --user pip
~/.local/bin/pip install --user https://get.octoprint.org/latest
exit
echo -e \
"octoprint0 ALL = NOPASSWD: /bin/systemctl start octoprint.service
octoprint0 ALL = NOPASSWD: /bin/systemctl stop octoprint.service
octoprint0 ALL = NOPASSWD: /bin/systemctl restart octoprint.service
octoprint0 ALL = NOPASSWD: /bin/systemctl reboot
octoprint0 ALL = NOPASSWD: /bin/systemctl poweroff
octoprint0 ALL = NOPASSWD: /usr/sbin/service octoprint restart
octoprint0 ALL = NOPASSWD: /sbin/reboot
octoprint0 ALL = NOPASSWD: /sbin/shutdown -P 0
octoprint1 ALL = NOPASSWD: /bin/systemctl start octoprint.service
octoprint1 ALL = NOPASSWD: /bin/systemctl stop octoprint.service
octoprint1 ALL = NOPASSWD: /bin/systemctl restart octoprint.service
octoprint1 ALL = NOPASSWD: /bin/systemctl reboot
octoprint1 ALL = NOPASSWD: /bin/systemctl poweroff
octoprint1 ALL = NOPASSWD: /usr/sbin/service octoprint restart
octoprint1 ALL = NOPASSWD: /sbin/reboot
octoprint1 ALL = NOPASSWD: /sbin/shutdown -P 0" > /etc/sudoers.d/octoprint
sudo mv /etc/ffserver.conf /etc/ffserver.original # Backup original configuration file
# Writes a new config file using contents below
sudo echo -e \
"#################################################################
# Global Server Config
HTTPPort 8090
HTTPBindAddress 0.0.0.0
MaxHTTPConnections 2000
MaxClients 1000
MaxBandwidth 100000
CustomLog /var/log/ffserver.log
##################################################################
# Definition of the live feeds. Each live feed contains one video
<Feed printer0.ffm>
File /tmp/printer0.ffm
FileMaxSize 1G
ACL allow 127.0.0.1
</Feed>
#################################################################
<Feed printer1.ffm>
File /tmp/printer1.ffm
FileMaxSize 1G
ACL allow 127.0.0.1
</Feed>
##################################################################
# Stream definitions
<Stream printer0.mjpeg>
Feed printer0.ffm
Format mjpeg
VideoBitRate 6140
VideoBufferSize 8192
VideoFrameRate 15
VideoSize hd1080
VideoGopSize 12
VideoCodec mjpeg
NoAudio
VideoQMin 3
VideoQMax 31
</Stream>
<Stream printer0_snap.jpg>
Feed printer0.ffm
Format jpeg
VideoFrameRate 2
VideoIntraOnly
VideoSize hd1080
NoAudio
Strict -1
</Stream>
##################################################################
<Stream printer1.mjpeg>
Feed printer1.ffm
Format mjpeg
VideoBitRate 6140
VideoBufferSize 8192
VideoFrameRate 15
VideoSize hd1080
VideoGopSize 12
VideoCodec mjpeg
NoAudio
VideoQMin 3
VideoQMax 31
</Stream>
<Stream printer1_snap.jpg>
Feed printer1.ffm
Format jpeg
VideoFrameRate 2
VideoIntraOnly
VideoSize hd1080
NoAudio
Strict -1
</Stream>" > /etc/ffserver.conf # Edit this file if any changes are needed
We need separate Octoprint instances for each printer (Each one uses it's own port)
# Writes a new webserver config file to nginx for each octoprint instance
sudo echo -e \
"[Unit]
Description=Octoprint - Open Source Printing Interface for 3D printers
Documentation=https://docs.octoprint.org
After=network.target
[Service]
User=octoprint0
Environment=HOME=/home/octoprint0
WorkingDirectory=/home/octoprint0
ExecStart=/usr/bin/python2 /home/octoprint/.local/bin/octoprint --port=5000 serve
Restart=always
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/octoprint0.service
sudo echo -e "[Unit]
Description=Octoprint - Open Source Printing Interface for 3D printers
Documentation=https://docs.octoprint.org
After=network.target
[Service]
User=octoprint1
Environment=HOME=/home/octoprint1
WorkingDirectory=/home/octoprint1
ExecStart=/usr/bin/python2 /home/octoprint/.local/bin/octoprint --port=5001 serve
Restart=always
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/octoprint1.service
# Now we enable the new services
sudo systemctl enable octoprint0.service octoprint1.service
# And finally start the octoprint servers using systemd
sudo service octoprint0 start
sudo service octoprint1 start
sudo echo -e \
"[Unit]
Description=FFMPEG streaming server service
After=network.target
[Service]
ExecStart=/usr/bin/ffserver
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/ffserver.service
sudo echo -e \
"[Unit]
Description=ffmpeg Recast for RTSP After=ffserver.service
[Service]
Type=simple WorkingDirectory=/usr/bin/
ExecStart=/usr/bin/ffmpeg -i \"rtsp://<username>:<password>@<rtsp_stream_address>\" http://localhost:8090/printer0.ffm
Restart=always
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/printer0-ffmpeg.service
sudo echo -e \
"[Unit]
Description=FFMPEG streaming server service
After=network.target
[Service]
ExecStart=/usr/bin/ffserver
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/ffserver.service
sudo echo -e \
"[Unit]
Description=ffmpeg Recast for RTSP After=ffserver.service
[Service]
Type=simple WorkingDirectory=/usr/bin/
ExecStart=/usr/bin/ffmpeg -i \"rtsp://<username>:<password>@<rtsp_stream_address>\" http://localhost:8090/printer1.ffm
Restart=always
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/printer1-ffmpeg.service
echo -e "Please be sure to edit the systemd unit files with the correct rtsp information before starting the services."
Before continuing, be sure to edit the new systemd unit files before enabling and starting them
# If using nano as your text editor:
sudo nano /etc/systemd/system/printer0-ffmpeg.service
sudo nano /etc/systemd/system/printer1-ffmpeg.service
# If using vim as your text editor:
sudo vim /etc/systemd/system/printer0-ffmpeg.service
sudo vim /etc/systemd/system/printer1-ffmpeg.service
# And make sure to reload the systemd daemon
sudo systemctl daemon-reload
Then enable and start the services in order
sudo systemctl enable ffserver.service printer0-ffmpeg.service printer1-ffmpeg.service
sudo service ffserver start
sudo service printer0-ffmpeg.service start
sudo service printer1-ffmpeg.service start
nginx config (change the name of the location to your own taste)
sudo echo -e \
"server {
listen 80;
server_name octoprint.lan octoprint-nuc.local localhost;
location /printer0/ {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /printer0;
proxy_http_version 1.1;
client_max_body_size 0;
}
location /printer0_stream/ {
proxy_pass http://127.0.0.1:8090/printer0.mjpeg;
}
location /printer0_snap/ {
proxy_pass http://127.0.0.1:8090/printer0_snap.jpg;
}
location /printer1/ {
proxy_pass http://127.0.0.1:5001/;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /printer1;
proxy_http_version 1.1;
client_max_body_size 0;
}
location /printer1_stream/ {
proxy_pass http://127.0.0.1:8090/printer1.mjpeg;
}
location /printer1_snap/ {
proxy_pass http://127.0.0.1:8090/printer1_snap.jpg;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}" > /etc/nginx/sites-available/octoprint.conf
sudo ln -s /etc/nginx/sites-available/octoprint.conf /etc/nginx/sites-enabled/octoprint.conf
sudo service nginx reload
sudo service nginx restart
You should now have two separate octoprint instances running, along with two RTSP ip cameras streams.
Most network adapters get assigned some weird and hard to remember designations these days. To make them more "friendly" you can edit the startup config:
Edit your /etc/default/grub
changing the line from
GRUB_CMDLINE_LINUX=""
to
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
and, finally:
sudo update-grub
and reboot your system:
sudo reboot
If you installed the Optional Packages
earlier, you can skip this:
sudo apt install -y samba
There are a number of lines in the samba configuration file that need to be edited:
sudo vim /etc/samba/smb.conf
# Change this to the network name you want to use
netbios name = octoprint
#------------------------------------------------------------------#
# Allow users who've been granted usershare privileges to create
# public shares, not just authenticated ones
usershare allow guests = yes
#------------------------------------------------------------------#
[Printer 0 FileStore]
path = /home/octoprint0/.octoprint/uploads
writeable = yes
browseable = yes
guest ok = yes
[Printer 0 Watched]
path = /home/octoprint0/.octoprint/watched
writeable = yes
browseable = yes
guest ok = yes
[Printer 1 FileStore]
path = /home/octoprint1/.octoprint/uploads
writeable = yes
browseable = yes
guest ok = yes
[Printer 1 Watched]
path = /home/octoprint1/.octoprint/watched
writeable = yes
browseable = yes
guest ok = yes
Lastly, we need to make sure the folders are writable by everyone:
sudo chmod -R 777 /home/octoprint0/.octoprint/uploads
sudo chmod -R 777 /home/octoprint0/.octoprint/watched
sudo chmod -R 777 /home/octoprint1/.octoprint/uploads
sudo chmod -R 777 /home/octoprint1/.octoprint/watched
On a Windows system, you would be able to access these shares by opening a file exporer window, and typing into the address bar \\octoprint.local
If you installed the Optional Packages
earlier, you can skip this:
sudo apt install -y cifs-utils
First we need to create an empty folder that will "contain" the files hosted on the windows share
sudo mkdir -p /home/octoprint0/.octoprint/uploads/shared
sudo chown -R octoprint0:octoprint0 /home/octoprint0/.octoprint/uploads/shared
Next, we must create a new auto-mount under the filesystem table
sudo vim /etc/fstab
Example (last line is the only one we've added):
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda2 during installation
UUID=[redacted] / ext4 errors=remount-ro 0 1
## /boot/efi was on /dev/sda1 during installation
UUID=[redacted] /boot/efi vfat umask=0077 0 1
# swap was on /dev/sda3 during installation
UUID=[redacted] none swap sw 0 0
//windows-share.local/STL_Files /home/octoprint0/.octoprint/uploads/shared cifs uid=octoprint0,gid=octoprint0,password=,dir_mode=0777,file_mode=0666,iocharset=utf8,_netdev 0 0
Now lets test the mount
sudo mount -a
If everything works, the cursor should advance to the next line without any output
If you installed the Optional Packages
earlier, you can skip this:
sudo apt install -y nfs-kernel-server
First we need to define the shared folder:
sudo vim /etc/export
An example NFS exports config file:
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/home/octoprint0/.octoprint 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check,no_acl)
Now we need to start the NFS share
sudo exportfs -a
sudo service nfs-kernel-server restart
This share can be accessed on other Linux/Unix systems by following the NFS Client instructions below
If you installed the Optional Packages
earlier, you can skip this:
sudo apt install -y nfs-common
First we need to create an empty folder to mount the share
sudo mkdir -p /home/octoprint0/.octoprint/uploads/shared
sudo chown -R octoprint0:octoprint0 /home/octoprint0/.octoprint/uploads/shared
Now we add the NFS share to the filesystem table
sudo vim /etc/fstab
Example (last line is the only one we've added):
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda2 during installation
UUID=[redacted] / ext4 errors=remount-ro 0 1
# /boot/efi was on /dev/sda1 during installation
UUID=[redacted] /boot/efi vfat umask=0077 0 1
# swap was on /dev/sda3 during installation
UUID=[redacted] none swap sw 0 0
nfs-share.local:/path/to/shared/folder /home/octoprint0/.octoprint/uploads/shared nfs auto,nofail,noatime,nolock,intr,tcp,actimeo=1800 0 0
Now let's test the mount:
sudo mount -a
This portion of the guide involves building an application from source, which may be difficult for less experienced linux users. I personally don't have a ton of experience with the backend of ffmpeg, so there won't be a lot of help here if something goes wrong
I initially started building this portion of the guide while combining features from this tutorial and this tutorial for building ffmpeg to be able to use Intel's hardware transcoding to offload most of the heavy processing involved with getting a video feed from an RTSP source, however many of the configuration options applied here are either depreciated, out of date, or were completely uneccessary, so it took quite a while to get the sources built in a way that would work for this application.
Also this is still a work in progress. I've got one method mostly working, but there are a number of other ways to do this that I'm still exploring.
One important thing to know is that H264 and other such video streams cannot be transcoded directly to mjpeg using Intel's hardware transcoder. Instead they must be served as a web-enabled stream format like HLS/m3u8 or DASH/webm. This requires extra steps to get it working with Octoprint, namely using a modified plugin that I'm currently developing
sudo apt update && \ # Update package info
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt upgrade -y && \ # Upgrade any packages with available updates
sudo apt dist-upgrade -y \ # Update kernel modules with available updates
sudo apt install -y \
build-essential gcc libgd-dev \
libgd3 \
python-pip \
openssh-server \
nginx \
ffmpeg \
avahi-daemon
Work in Progress
Work in Progress
Work in Progress