Home lab improvements
I redone my homelab setup.
Well I got fiber internet. The subscription is with a Fritzbox router. That has actually the features to allow a homelab. (The router at my parents dont even allow a local dns).
So I moved my main linux server directly from the internet (the ziggo modem was in bridge mode directly give a internet connection to my server)
But what i did i could not get ipv6 working on the debian machine. It was getting full of memory and a full disk. I have backups so i made a fresh reinstall.
Local (partual) Setup
I now have a new setup
Linux server: Nginx server for local websites and reverse proxies. Pi-hole: Main dns for my home lab. haos: home assistant on a pi
I have a dynamic dns setup at Dynu Dynamic DNS Its free and you can register a global sub dns.
This means you can create a website for any-name.your-subdomain.dynu-registered-domain.com on you local webserver.
You can also fully control the sub domain registry.
I added a ipv6 AAAA record for my home assistant setup. So even if my main nginx server is down i still can reach my home assistant instance over ipv6.
Nginx reverse proxy for home assistant with letsencrypt.
I could not find a working nginx config for home assistant. Tried some but they dont work. So i made one together with openAI.
1st make a skeleton port 80 setup. in /etc/nginx/sites-available/your.hostname
server {
server_name your.hostname;
listen 80;
listen [::]:80;
}
then make a symlink in /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/your.hostname /etc/nginx/sites-enabled/
run nginx -t and if no problems reload the service.
now run letsencrypt to enable ssl.
the file in /etc/nginx/sites-available/your.hostname is now ssl enabled and port 80 redirects to https. Now edit the file to make a reverse proxy to home assistant.
add the following in the server ssl (port 443) section replace 192.168.1.1 with the ip of your home assistant.
location / {
proxy_pass http://192.168.1.1:8123;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
location /api/websocket {
proxy_pass http://192.168.1.1:8123/api/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
now reload nginx again and the recursive proxy is ready. dont forget to edit home assistant config to allow the proxy. where 192.168.1.2 is the nginx server.
http:
use_x_forwarded_for: true
trusted_proxies:
- 192.168.1.2
nginx ssl addon for home assistant
We now have a ipv4 ipv6 (the config is ipv4 but nginx listens to the ipv6 address and just proxies the ipv4 content) but we could directly access the home assistant server with ipv6
this can be done installing the NGINX Home Assistant SSL proxy.
The documentation is sufficent for the addon so i dont mention it. What i will not is that the main server is polling the ssl certificates the next script will detect the right files of letsencrypt and copies then to haos and restarts the addon if ssl certs are changed.
# Variables
NGINX_CONFIG="/etc/nginx/sites-available/your.domain" #one of the sites available
SSL_DEST_DIR="/mnt/hass/ssl" #the mount of the ssl share of the samba addon
WEBHOOK_ID="-1234567" #webhook to restart the nginx addon
HASS_URL="http://192.168.1.1:8123" #home assistant url
WEBHOOK_URL="$HASS_URL/api/webhook/$WEBHOOK_ID"
# Get SSL path from config (only the fullchain.pem) and REMOVE the trailing semicolon
SSL_PATH_FROM_CONFIG=$(grep ssl_certificate "$NGINX_CONFIG" | awk '{print $2}' | head -n 1 | tr -d ';')
echo "SSL_PATH_FROM_CONFIG: $SSL_PATH_FROM_CONFIG"
SSL_SOURCE_DIR=$(dirname "$SSL_PATH_FROM_CONFIG")
echo "SSL_SOURCE_DIR: $SSL_SOURCE_DIR"
# Check if Nginx config file exists
if [ ! -f "$NGINX_CONFIG" ]; then
echo "Error: Nginx config file '$NGINX_CONFIG' not found."
exit 1
fi
# Check if SSL source directory exists
if [ ! -d "$SSL_SOURCE_DIR" ]; then
echo "Error: SSL source directory '$SSL_SOURCE_DIR' not found."
exit 1
fi
# Check if SSL destination directory exists and create if it doesn't
if [ ! -d "$SSL_DEST_DIR" ]; then
echo "Creating SSL destination directory '$SSL_DEST_DIR'..."
mkdir -p "$SSL_DEST_DIR"
if [ ! -d "$SSL_DEST_DIR" ]; then
echo "Error: Failed to create SSL destination directory."
exit 1
fi
fi
# Extract the filename (fullchain.pem)
SSL_FILENAME=$(basename "$SSL_PATH_FROM_CONFIG")
# Construct the paths to the fullchain.pem files in source and destination
SSL_SOURCE_FILE="$SSL_SOURCE_DIR/$SSL_FILENAME"
SSL_DEST_FILE="$SSL_DEST_DIR/$SSL_FILENAME"
# Compare the fullchain.pem files directly (check if dest file exists first)
if [ ! -f "$SSL_DEST_FILE" ] || ! cmp -s "$SSL_SOURCE_FILE" "$SSL_DEST_FILE"; then
echo "SSL certificates have changed or destination file doesn't exist. Copying and restarting Home Assistant add-on..."
# Copy SSL certificates (copy the whole directory)
cp -rL "$SSL_SOURCE_DIR"/* "$SSL_DEST_DIR"
if [ $? -eq 0 ]; then
echo "SSL certificates copied successfully."
else
echo "Error: Failed to copy SSL certificates."
exit 1
fi
# Restart Home Assistant Nginx add-on
echo "Restarting Home Assistant Nginx add-on..."
curl -X POST "$WEBHOOK_URL"
else
echo "SSL certificates have not changed. Skipping restart."
fi
exit 0
home assistant automation
An home assistant automation is responible for restarting the addon and is called if the ssl certs have changed.
dont forget to edit the webhook
alias: ssl addon restart
description: "restarts the ssl ngnix proxy addon"
triggers:
- trigger: webhook
allowed_methods:
- POST
- PUT
local_only: true
webhook_id: "-1234567"
conditions: []
actions:
- action: hassio.addon_restart
metadata: {}
data:
addon: core_nginx_proxy
mode: single
Now you only need to add an alias AAAA record in your ddns and you can reach your home assistant instance directly using ipv6.
Pi hole addons
Beacause i moved my homelab around my network is still working if my main server is down. so i moved pi-hole from the main server to a raspberry pi.
the installation is easy (I just use curl -sSL https://install.pi-hole.net | bash
)
ipv6 pihole Conditional forwarding
pi-hole is only allowing ipv4 or ipv6 Conditional forwarding.
So if you want both you need to create a file for one of them
in /etc/dnsmasq.d/90-reverse-ipv6.conf
server=/0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa/192.168.1.254
where 192.168.1.254 is your dhcp server.
pihole dynamic dns
For home assistant i use whisper for speech recognition and that takes some what a beefy system for a good user experience. The best system i have is my laptop but that is not a 24/7 system.
I could use a ddns service online but that does not work when your offline. (what is the point of a offline system with online requirements)
so I made a script that pings a range of ip addresses and uses the 1st one online to register a hostname. using a other script.
Just install the services provided on all systems with same port and the best one is picked by the ddns hostname.
in this example 192.168.5.8 is the ip of my laptop 10.109.212.9 if connected to vpn 192.168.5.6 is a slower 24/7 machine.
#!/bin/bash
# List of IP addresses to ping
IP_STRING="192.168.5.80 10.109.212.9 192.168.5.6"
hostname="whisper.mydomain"
# Function to check if IP is reachable
check_ip_reachable() {
ip="$1"
ping -c 1 -W 1 "$ip" >/dev/null 2>&1
}
# Main script
for ip in $IP_STRING; do
if check_ip_reachable "$ip"; then
echo "Found reachable IP: $ip"
/usr/local/bin/dyndnsmasq.sh "$ip" "$hostname"
exit 0
fi
done
echo "No reachable IP found in the list."
/usr/local/bin/dyndnsmasq.sh
#!/bin/bash
# Script to add or update a hostname's IP address in /etc/hosts
# Check for required arguments
if [ $# -ne 2 ]; then
echo "Usage: $0 <ip_address> <hostname>"
exit 1
fi
ip_address="$1"
hostname="$2"
# Check if IP address is valid (basic check)
if [[ ! "$ip_address" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
echo "Invalid IP address: $ip_address"
exit 1
fi
# Check if hostname is valid (basic check - can be more strict)
if [[ ! "$hostname" =~ ^[a-zA-Z0-9.-]+$ ]]; then
echo "Invalid hostname: $hostname"
exit 1
fi
# Create a temporary file to store the modified /etc/hosts content
temp_file=$(mktemp)
# Check if the hostname already exists in /etc/hosts and update or add
if grep -q "$hostname" /etc/hosts; then
# Hostname exists, update the IP address. Capture the changes.
if sed "s/^\([0-9.]*\)\s\+${hostname}\$/${ip_address} ${hostname}/" /etc/hosts > "$temp_file"; then
echo "Updated IP address for $hostname to $ip_address"
else
echo "Error updating IP address for $hostname"
rm "$temp_file"
exit 1
fi
else
# Hostname does not exist, add a new entry
echo "$ip_address $hostname" >> "$temp_file"
echo "Added $hostname with IP address $ip_address"
# Copy the original content of /etc/hosts to the temp file, then append the new line.
cat /etc/hosts >> "$temp_file"
fi
# Compare the original /etc/hosts with the new content in the temp file
if ! cmp -s /etc/hosts "$temp_file"; then # -s for silent comparison
# Files are different, overwrite /etc/hosts and restart dnsmasq
mv "$temp_file" /etc/hosts
echo "Changes made to /etc/hosts. Restarting pihole-FTL."
pihole restartdns
else
echo "No changes needed to /etc/hosts."
rm "$temp_file" # Clean up the temporary file
fi
exit 0
Thats all folks.
That is all i can share right now. I hope you found it usable.