Here I explain how I setup my own server for my private usage at home. I use the RaspberryPi 4B with 8GB memory and a external hard driver as a storage. As an operating system I use raspian because it's used to be the stablest ones. To be exact here I use Raspberry Pi OS Lite (64-bit)
.
The reason for that kind of project is to have a own seperated router where everything can be hosted and you have 100% control about anything like content filtering, hosting a own VPN, configuring a additional firewall or basicly anything that doesn't require a ton of processor power. But basicly everything here can be used on similar Debian based x86 systems if needed. But I like to refer to my setup. Also I like to keep my
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 install already the PUB-Key for the authentication process.
If you want to generate the keys 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 installation of Raspian with SSH access the first step would be to update the system and reboot afterwards.
#!/bin/bash
# full-upgrade is newer than dist-upgrade but does the same
sudo apt update && sudo apt full-upgrade
sudo reboot
For that we don't use dhcpcd
or NetworkManager
. You could use dhcpcd
if you don't want to use your RaspberryRouter 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 that. And for more information 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'
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/bash
sudo apt-get install ddclient
sudo nano /etc/ddclient.conf
Here the configuration for no-ip.com with ddclient
.
# 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.
Also i like to run a Jellyfin server. And if you use the raspberry only for transfering the data it's no big deal because the encoding process will happen on the client devices.
Here the oneshot line to install Jellyfin.
#!/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
. If everything is fine you can refer within jellyfin to the directories of the device and storage your data on this device.
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. 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
.
Or you make a reverse proxy. The scenario is that Jellyfin uses a self signed SSL certificate and your desktop binds that connection locally over HTTP using Apache2 or something like that.
But that would only workout for devices that can bind the HTTPS connection locally on a local HTTP side. So mobile devices would have trouble with that.