- Choice of OS
- Installation - Operationg sytems
- SSH
- Static IP Adresses
- Raspberry Pi (Raspberry Pi OS)
- Notebook (Debian)
- HTTPS
- Firewall
The Rasberry Pi as Rasberry Pi OS installed because it's the offical operating system for this board and has a wide range of community support. On the notebook is installed Debian but headless. If installed as I do (headless basicly) some other tools are also not preinstalled like sudo
.
Install using the installation image Netinst and an external drive to boot from. After booting from the external drive uncheck every graphical environment that is choosen so that non of them will be installed.
Now install SSH
and SUDO
software. After installing SUDO
the choosen user has to be added to the SUDO
group to have access to SUDO
.
#!/bin/bash
# update system
apt update && sudo apt full-upgrade
# install software
apt install ssh sudo
usermod -aG sudo USERNAME # add USERNAME to group
reboot
Now you can change to the user that is assigned to the SUDO
group to check up if the wished group is assigned to the user.
#!/bin/bash
su USERNAME # change user
id
Install via Raspberry Pi Imager
or other flashing software to install Raspberry Pi OS Lite (64-bit)
on the storage of your choice. Also keep in mind to enable SSH and maybe setup the PUB-Key for the authentication process already. After the installation update the system.
sudo apt update && sudo apt full-upgrade
sudo reboot
Here is explained how I setup SSH
for both operating systems. So some steps here are unnecessary for one of them of course. The installation of the package ssh
is either explained in the steps before or preinstalled like by Raspberry Pi OS
.
Enable and start the service and check the status of the service. If everything runs smoothly the SSH access is now ready to use.
#!/bin/bash
sudo systemctl enable --now ssh.service
sudo systemctl status ssh.service
If you want to generate the files for the PUB-Key authentication. Here a command for that. I would recommend to checkout ubuntuusers for a better understanding how SSH and ssh-keygen
works.
#!/bin/bash
ssh-keygen -t rsa -b 4096
The keys will be saved in the folger ~/.ssh
. You need to put the content of the *.pub
in the authorized_keys
. Also you can put that public key manually there. For that copie in the /home/PIUSER/.ssh/authorized_keys
. Maybe you need to create the .ssh
folder beforewards.
After the PUB-Key authentification is working (tested) change some lines in the configuration file (/etc/ssh/sshd_config
) for SSH
to disable the password based login and the login into root
via SSH
.
But before make sure to have a copie of the working configuration file to rollback if problems with the service are happening.
#!/bin/bash
sudo su
cd /etc/ssh
cp -a sshd_config sshd_config.backup
nano sshd_config
Now edit the lines #PermitRootLogin ...
to PermitRootLogin No
so no logins via password is valid anymore. After that restart the service to get the changed configuration working.
#!/bin/bash
sudo systemctl restart ssh.service
sudo systemctl status ssh.service
For that I don't use dhcpcd
or NetworkManager
. You could use dhcpcd
if you don't want to use your Raspberry Router for LAN connections but only as AccessPoint. For that you need to install dhcpcd5
. Basicly I had trouble to setup virtual interfaces with dhcpcd5
but maybe there is some work around for that.
But I use for configure a static IP-Adresses the service called networking
. For that install ifupdown
than you are good to go with the installation part.
#!/bin/bash
sudo apt-get install ifupdown
sudo rfkill unblock wifi # remove soft lock of wlan interface
For the configuration of this service you can add a onfiguration file to /etc/network/interfaces.d/YOUR-CONF
but I'd like to use the basic config file /etc/network/interfaces
. Here a template for the Rasberry Pi Router. Fot the Debian installed on the notebook you can modify this here. To get your informations about interfaces on your device use ifconfig
or ip
. And for more information about interfaces I like to refer to ubuntuusers.
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
# your normal network; gateway of your other networks/interfaces
auto eth0
iface eth0 inet static
address 192.168.0.40/24
gateway 192.168.0.1
network 192.168.0.0
broadcast 192.168.0.255
# dns-nameservers 127.0.0.1 # own DNS; for later
# gateway of manually configured clients; virtual ethernet interface
auto eth0:1
iface eth0:1 inet static
address 10.140.25.1/24
network 10.140.25.0
broadcast 10.140.25.255
# dns-nameservers 127.0.0.1 ::1
# accesspoint interface
auto wlan0
iface wlan0 inet static
address 10.140.20.1/24
network 10.140.20.0
broatcast 10.140.20.255
# dns-nameservers 127.0.0.1 ::1
Now the config is complete you should enable the service and disable the other ones that want to configure the interfaces.
#!/bin/bash
sudo systemctl disable NetworkManager systemd-networkd
sudo systemctl enable --now networking
sudo systemctl status networking
If you checked the networking
service and it says something like that the interfaces are already configured that is caused by NetworkManager
and systemd-networkd
. So you need to restart to let networking
configure the interfaces for you needs.
#!/bin/bash
sudo reboot
So to check if everything runs fine you can check that with followed commands.
#!/bin/bash
ifconfig # or 'ip -br a'
sudo systemctl status networking
I would also recommend to use PiHole or alternatives like AdGuard Home. A huge part of this guide is possibly also usable for AdGuard Home but I refer to PiHole.
To install PiHole you can use this command or go to this https://pi-hole.net/ to get more informations.
#!/bin/bash
curl -sSL https://install.pi-hole.net | bash
After you followed throught the guide you should have a running website to handle PiHole.
I recommend a very famous blocklist source here. I tested these here.
Afterwards you added your blocklists of your choice you have to get to Tools -> Update Gravity
section within the web ui and click on update
. You can do that over the terimal as alternative if you prefer that.
PiHole has a guide for Unbound as a recursive DNS. It's well documented and works correctly if you want to setup that. Also lookup here for checkups for your configurations.
I like to have followed features if I make a request to a DNS.
- DNSSEC - validate response of DNS server
- DNS-Over-TLS (DOT) - encrypted requests to the DNS server
The problem is PiHole supported only DNSSEC so I build my own DNS request forwarder with the help of Unbound. Unbound is basicly a service that makes the same thing as every DNS server does. It makes requests to the root nameserver. The problem with that is that DNS servers and Unbound not encrypt the requests that they make.
But you can also use Unbound to use Unbound normally to make DNS requests but also encrypted (DOT).
#!/bin/bash
sudo apt-get install unbound
Now that Unbound installed you need to configure it.
#!/bin/bash
sudo nano /etc/unbound/unbound.conf.d/NAMECONFIG.conf
Here an example how I make this configuration for Unbound.
server:
# logfile: "/var/log/unbound/unbound.log"
verbosity: 0
interface: 127.0.0.1
port: 5335
do-ip4: yes
do-udp: yes
do-tcp: yes
do-ip6: yes
prefer-ip6: no
harden-glue: yes
harden-dnssec-stripped: yes
use-caps-for-id: no
edns-buffer-size: 1232
prefetch: yes
num-threads: 1
so-rcvbuf: 1m
tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
private-address: 192.168.0.0/24
private-address: 10.140.20.0/24
private-address: 10.140.25.0/24
forward-zone:
name: .
forward-first: no # disables fallback to recursive dns behavior
forward-tls-upstream: yes
# uses Quad9; can be replaced with other configs
forward-addr: 9.9.9.9@853#dns.quad9.net
forward-addr: 149.112.112.112@853#dns.quad9.net
forward-addr: 2620:fe::fe@853#dns.quad9.net
forward-addr: 2620:fe::9@853#dns.quad9.net
The port is changed from the default port 53 to 5335 as the PiHole documentation says to do because of the port conflict that would be the cause if you don't do that. Because PiHole runs already under port 53.
#!/bin/bash
sudo systemctl enable --now unbound # if not done already
sudo systemctl restart unbound
# checks connection with DNS
dig pi-hole.net @127.0.0.1 -p 5335 # expected status: NOERROR
dig fail01.dnssec.works @127.0.0.1 -p 5335 # expected status: SERVFAIL
dig dnssec.works @127.0.0.1 -p 5335 # expected status: NOERROR
And now we are finished with the configuration of the Unbound DNS request forwarder. So you can change the DNS reference within PiHole to 127.0.0.1#5335
within the section Settings -> DNS
.
Now the Unbound setup and the reference to it within PiHole is made you should change the config of networking
so that your Rasberry calls only to the locally DNS setup (PiHole) and not to your standard router.
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
# your normal network; gateway of your other networks/interfaces
auto eth0
iface eth0 inet static
...
dns-nameservers 127.0.0.1 # own DNS configuration
# gateway of manually configured clients; virtual ethernet interface
auto eth0:1
iface eth0:1 inet static
...
dns-nameservers 127.0.0.1 ::1
# accesspoint interface
auto wlan0
iface wlan0 inet static
...
dns-nameservers 127.0.0.1 ::1
After that you should restart your server to load up every setting and newly made configuration correcly.
First you have to enable that IPv4 packages have the right to be forwarded across another interface. Add/Uncomment for that a line within /etc/sysctl.conf
.
#!/bin/bash
sudo nano "/etc/sysctl.conf"
The line I told about. You can add or uncomment the containing one.
net.ipv4.ip_forward=1
Now add the following forwarding configurations with iptables.
#!/bin/bash
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.140.20.0/24 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.140.25.0/24 -j MASQUERADE
This configuration is only temporary so you can put your configuration into the /etc/iptables.ipv4.nat
files. Or you install a package that makes exactly that for you. Make the temporary config persistent.
For that you can install following packages.
#!/bin/bash
sudo apt-get install iptables-persistent netfilter-persistent
sudo systemctl enable --now netfilter-persistent.service # only to be sure that it runs correctly
sudo netfilter-persistent save # makes it persistent
To make a AccessPoint via wlan0 interface you can use the DHCP configuration within the PiHole web ui. PiHole will be reployed and installed with dnsmasq so you don't have to setup the DHCP for your wlan0 interface manually.
You have to install Hostapd for that.
#!/bin/bash
sudo apt-get install hostapd
# creating future hostapd config
sudo touch /etc/hostapd/hostapd.conf
sudo nano /etc/default/hostapd # needs to refer to config path
Now that you have the file /etc/default/hostapd
open you should change/add this line to the configurations.
DAEMON_CONF="/etc/hostapd/hostapd.conf"
Let us configure the AccessPoint (hostapd). For that open the file /etc/hostapd/hostapd.conf
with the editor your choice. Here an example for a 5GHz AccessPoint.
interface=wlan0
driver=nl80211
ssid=NAME_NETWORK
country_code=DE
hw_mode=a
channel=36
ieee80211d=1
ieee80211n=1
ieee80211ac=1
wmm_enabled=1
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
auth_algs=1
wpa_passphrase=PASSWORD
And now we have to enable and start the service. Then check if the service is running correctly.
#!/bin/bash
sudo systemctl unmask hostapd
sudo systemctl enable --now hostapd
sudo systemctl status hostapd
But if the current service is already running you should just restart it and checkout the status of this service using systemctl.
Afterwards you can add your DHCP IP-Adress section that you want to be automaticly assigned to the clients. For that use the IP-Adress section that is within the subnet of wlan0. Then you should restart your RaspberryPi and checkout if you can connect with your clients and get access to the internet.
If not maybe checkout if the forwarding (common problem) is the problem. You can test that if you make this temporary and reconnect to your AccessPoint.
#!/bin/bash
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.140.20.0/24 -j MASQUERADE
If that's the problem you could write down a daemon (/etc/systemd/system/YOURDAEMON.service
) that makes this every time you restart your server. But that would be not the greatest solution for that kind of problem. Here an example for that.
Here an example for a service like that.
[Unit]
Description=assignes interfaces to forward
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/bash PATH.sh
RemainAfterExit=true
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Naturally you have to write the PATH.sh
. Here also an example for that.
#!/bin/bash
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.140.20.0/24 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.140.25.0/24 -j MASQUERADE
Now you can enable your own service.
#!/bin/bash
sudo systemctl enable --now YOURDAEMON.service
sudo systemctl status YOURDAEMON.service
And that's it. Now it should work out fine even without the convenience of the tools that does that.
So a final restart and checkout and we are finished with the AccessPoint, static adresses and a DNS blocklist (with encryption via Unbound).
I used PIVPN with WireGuard to make access from outside my private network possible. So I want to mention that here.
Oneshot line to install PIVPN. I recommend to enable automatic security updates and refer to PiHole as DNS. The rest of it is pretty much easy going.
#!/bin/bash
curl -L https://install.pivpn.io | bash
You only have to go through everything that PIVPN mentioned. After that the VPN is ready to use. But don't forget to make a rule on your default router that the port that you've choosen is open and uses udp.
If you want to get access from outside you have probably a dynamic ip adress that you get from you ISP. So you have to get a DDNS that refers to your ip. Basicly your server (RaspberryPi) makes a call intervallwise to the DDNS host so that the domain gets updated and refers to your current ip adress.
Here I show how it's done with the service ddclient
and no-ip.com since no-ip.com is free to use. ddclient
can use every host of DDNS adresses.
#!/bin/bashYou should see the configured
Here the configuration for **no-ip.com** with `ddclient`.
```bash
# ddclient.conf für No-IP (dyndns2)
protocol=dyndns2
use=web, web=checkip.dyndns.com/, web-skip='IP Address'
server=dynupdate.no-ip.com
login=USERNAME
password=PASSWORD
DOMAINNAME.SUFFIX
#!/bin/bash
sudo systemctl enable --now ddclient
sudo systemctl status ddclient
If ddclient
has a error within it's status restart the service and try it again.
You could use Jellyfin on your Raspberry Pi (I did that) but for me it's response time is too long so I swapped to my notebook for that. Here the oneshot line to install Jellyfin. Works for Raspberry Pi OS and Debian.
#!/bin/bash
curl -s https://repo.jellyfin.org/install-debuntu.sh | sudo bash
For the storage I use a hard drive that is mounted through the configuration that I made within /etc/fstab
. Output every UUID and storage information of connected devices.
#!/bin/bash
sudo blkid
And now you can use that UUID of your choosen device to mount that device where you want to using /etc/fstab
. I would recommend to have the device with the ext4 data systems because it's the same as evey linux systems uses. So it will probably not have any issues because of the format.
Add this line with your mounting directory and the UUID of your device to the file /etc/fstab
.
...
# jellyfin
UUID=YOUR_UUID /MOUNTINGDIR ext4 defaults,users,exec 0 0
After a reboot the device should be mounted. You can check that using df
. Now we have to give access to the jellyfin
user so that Jellyfin has access to the files on this device.
#!/bin/bash
sudo chown -R jellyfin: /MOUNTINGDIR
sudo chmod -R 755 /MOUNTINGDIR
To setup hardware acceleration for transcoding or other processes with an Intel GPU. Also I want to refer to the (guide)[https://jellyfin.org/docs/general/post-install/transcoding/hardware-acceleration/intel] by the Jellyfin team.
Installation of resources (drivers) for Jellyfin.
#!/bin/bash
sudo apt install jellyfin-ffmpeg7 intel-opencl-icd
Now assign the render
group to jellyfin
and restart the notebook the be sure that everything (like drivers) are loaded correctly. For checkout if the drivers are loaded correctly you can use the commands used in the offical tutorial
#!/bin/bash
sudo usermod -aG render jellyfin
sudo reboot
To get access to Jellyfin you can use the web browser using http://HOSTNAME:8096
or a client software. There you can setup your folders that are located on your external storage. Also to get Hardware Acceleration working you have to go to Dashboard -> Playback -> Transcoding
and choose in Hardware acceleration
Video Acceleration API (VAAPI)
.
Here will be explained how to install Samba to get access to the choosen folders remotely. This part is fully compatible with Rasberry Pi OS
.
#!/bin/bash
sudo apt install samba samba-common
cd /etc/samba; sudo cp -a smb.conf smb.conf.backup
Now edit the Samba configuration (/etc/samba/smb.conf
) to get remote access to the choosen folder via a certain user. You can add an additional user for that using sudo adduser USERNAME
. Here an example.
... # leave unchanged
[global]
workgroup = WORKGROUP
security = user
encrypt passwords = yes
client min protocol = SMB2
client max protocol = SMB3
... # leave unchanged
# add lines for remote access to the end
[USERNAME]
path = /mnt/REMOTEACCESS
valid users = USERNAME
writeable = yes
browseable = yes
public = no
Now that everything is setup check the service and enable it if everything runs fine.
#!/bin/bash
# reload service
sudo systemctl restart smbd.service nmbd.service
# enable service
sudo systemctl enable smbd.service nmbd.service
It is important to know that every client software that I know can't handle self signed SSL certificates. Other users have the same problem here. As example the Jellyfin and Suwayomi client software has no possibility to connect via HTTPS if the SSL certificat is self signed. So I would say if you want to use HTTPS you have no choice but to make a certified SSL certificate. For that you can use certbot
. But a downside by using certbot
is that the SSL certs expire pretty fast and have to be newly generated because if not we have the same problem as with the self signed ones. The client software doesn't connect via HTTPS. But if the wished service (like Suwayomi) is only used via the web browser that problem is no more. For that I use openssl
to generate a self signed SSL cert.
I you want to setup HTTPS for a working HTTP website you can either add the generated SSL certificate or if not possible through a reverse proxy.
Generate a self signed SSL certificate using openssl
that expire after one year. The duration until the certificate will expire can be changed.
#!/bin/bash
sudo apt install openssl
# generate ssl cert
openssl req -x509 -newkey rsa:4096 -keyout ssl-selfsigned.key -out ssl-selfsigned.crt -days 365 -nodes
The -x509
stands for a self signed cert. rsa:4096
sets the encryption method to RSA 4096 Bit. Change -days DURATION
to a wished duration how long the cert should be valid. -nodes
declares that no password based encryption should be used for the private key. Pretty useful so you don't have to enter the password for starting Apache2 as a service.
The scenario is that you have a web service that doesn't support HTTPS directly. Here you use a self signed SSL certificate and Nginx or Apache2. Now setup one of them to pass the HTTPS requests locally to the HTTP service and that's it. Basicly we tunnel locally the original HTTP web service to another web service that uses HTTPS. Additionally you can forbit the HTTP port to be used by external clients directly so the only way is through the HTTPS web service that tunnels the request to the original one. For that you can use ufw
or maybe something like that is already possible by the HTTP service itself.
Here how to setup Apache2 to setup as reverse proxy.
#!/bin/bash
# setup basic apache
sudo apt install apache2
sudo systemctl enable apache2
# enable needed modules
sudo a2enmod ssl rewrite proxy proxy_http
Now we add up a site under Apache2 and enable that site. After that it's needed to reload/restart Apache2 to load the enabled modules and it's site.
#!/bin/bash
cd /etc/apache2/sites-available
sudo nano reverseProxy.conf
Here an example how the configuration file can look like and works out for me. The adress http://127.0.0.1:8149
using the port 8149 is the original web page and the tunneled web page through HTTPS is located under the port 8150.
<VirtualHost *:8150>
SSLEngine on
SSLCertificateFile /PATH/ssl-selfsigned.crt
SSLCertificateKeyFile /PATH/ssl-selfsigned.key
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8149/
ProxyPassReverse / http://127.0.0.1:8149/
</VirtualHost>
The declared port 4590 for Apache2 has to be mapped within the /etc/apache2/ports.conf
. Here an example like I did that.
#!/bin/bash
cd /etc/apache2
sudo cp ports.conf ports.conf.backup
sudo nano ports.conf
And here the /etc/apache2/ports.conf
.
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf
Listen 80
<IfModule ssl_module>
Listen 443
Listen 8150 # reverse proxy
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
Listen 8150 # reverse proxy
</IfModule>
Now enable the site and restart/reload the Apache2 service. And maybe checkout the status of Apache2 if something doesn't work like it should.
#!/bin/bash
sudo a2ensite reverseProxy
sudo systemctl restart apache2
sudo systemctl status apache2
The website should be reachable via the url https://IP-ADRESS:8150
.
For a firewall setup I use ufw
. ufw
will replace netfilter-persistent
so I would recommend to use ufw
only for the servers that doesn't use NAT (Network Adress Translation). This package is a firewall (filters packages) that wraps around iptables
so basicly you can use NAT but you have to put the configuration for iptables
that should load up by netfilter-persistent
into the configuration file of ufw
.
Put the parts that you want to load up (iptables config /etc/iptables/rules.v4
) into the file /etc/ufw/before.rules
. So the configuration will load up as before.
Here a basic setup for ufw
so every request from outside that is not allowed spezifically will be blocked.
#!/bin/bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
Now allow SSH before load up the firewall. If loaded before SSH is allowed the connection will break and you will lose potentially your server access.
#!/bin/bash
sudo ufw allow 22/tcp # or simply *allow ssh* if port is default
sudo ufw enable
Last but not least adding every service (port) that should be reachable from outside.
#!/bin/bash
# own dns setup
sudo ufw allow 53
sudo ufw allow 5335
# dhcp, hostapd, samba & jellyfin
sudo ufw allow 67/udp
sudo ufw allow 68/udp
sudo ufw allow Samba
sudo ufw allow 8096/tcp
sudo ufw allow 8920/tcp
# reverse proxy & web services
sudo ufw allow 80/tcp
sudo ufw allow 445/tcp
sudo ufw allow 8150/tcp
And reload ufw
to get the changes working and checkout the status of ufw
.
#!/bin/bash
sudo ufw reload
sudo ufw status