-
-
Save HackingGate/1508e7a1d7eeb1145b2a32c15606f774 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| set -e | |
| set -o pipefail | |
| # --- System and Time Configuration --- | |
| # Set system timezone to Tokyo, Japan | |
| sudo timedatectl set-timezone Asia/Tokyo | |
| # Configure hardware clock to use UTC (recommended for Linux) | |
| sudo timedatectl set-local-rtc 0 | |
| # Display current time and date settings | |
| timedatectl | |
| # Reference for dual-booting with Windows 11 (requires Windows to use UTC) | |
| # https://gist.github.com/HackingGate/180aafbc6342ad4b1cb31309fa83c91a | |
| # --- Core Package Installation --- | |
| # Update package lists and upgrade the system | |
| sudo apt update | |
| sudo apt upgrade -y | |
| # Install essential development tools, utilities, and Nvidia dependencies | |
| sudo apt install emacs-nox vim-nox neovim curl wget gh git build-essential zsh efibootmgr jq fastfetch htop dkms linux-headers-$(uname -r) firmware-misc-nonfree -y | |
| # --- Nvidia Driver Installation (Debian 13 "Trixie" Method) --- | |
| # Support for GeForce 700 series and newer GPUs (Version 550.163.01) | |
| # For older devices, consider Version 535.216.03 or nouveau | |
| # Configure APT sources to include contrib, non-free, and non-free-firmware for drivers | |
| echo "Adding contrib, non-free, and non-free-firmware components to sources..." | |
| sudo tee /etc/apt/sources.list.d/debian.sources > /dev/null <<'EOF' | |
| Types: deb deb-src | |
| URIs: http://deb.debian.org/debian | |
| Suites: trixie | |
| Components: main contrib non-free non-free-firmware | |
| Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg | |
| Types: deb deb-src | |
| URIs: http://security.debian.org/debian-security | |
| Suites: trixie-security | |
| Components: main contrib non-free non-free-firmware | |
| Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg | |
| EOF | |
| # Check if system uses dracut and configure it for nvidia | |
| if command -v dracut &> /dev/null; then | |
| echo "System uses dracut - configuring for NVIDIA..." | |
| sudo mkdir -p /etc/dracut.conf.d | |
| sudo tee /etc/dracut.conf.d/10-nvidia.conf > /dev/null <<'EOF' | |
| install_items+=" /etc/modprobe.d/nvidia-blacklists-nouveau.conf /etc/modprobe.d/nvidia.conf /etc/modprobe.d/nvidia-options.conf " | |
| EOF | |
| echo "Dracut configuration for NVIDIA created." | |
| fi | |
| # Update package lists | |
| echo "Updating package lists..." | |
| sudo apt update | |
| # Install linux-headers for current kernel (required for DKMS) | |
| echo "Installing linux headers for kernel $(uname -r)..." | |
| sudo apt install linux-headers-$(uname -r) -y | |
| # Install Nvidia proprietary drivers and DKMS | |
| sudo apt install nvidia-kernel-dkms nvidia-driver firmware-misc-nonfree -y | |
| # Verify DKMS build status | |
| echo "Checking DKMS build status..." | |
| sudo dkms status | |
| # Configure NVIDIA options for Wayland support and suspend/hibernate (if applicable) | |
| echo "Configuring NVIDIA options for Wayland and power management..." | |
| # Enable kernel modesetting for NVIDIA Wayland support | |
| echo "Enabling NVIDIA kernel modesetting for Wayland..." | |
| NVIDIA_GRUB_CONFIG="/etc/default/grub.d/nvidia-modeset.cfg" | |
| NVIDIA_CMDLINE='GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX nvidia-drm.modeset=1 nvidia-drm.fbdev=1"' | |
| if [ ! -f "$NVIDIA_GRUB_CONFIG" ]; then | |
| sudo mkdir -p "$(dirname "$NVIDIA_GRUB_CONFIG")" | |
| echo "$NVIDIA_CMDLINE" | sudo tee "$NVIDIA_GRUB_CONFIG" > /dev/null | |
| echo "Created NVIDIA modeset configuration in GRUB" | |
| elif ! grep -q "nvidia-drm.modeset=1" "$NVIDIA_GRUB_CONFIG"; then | |
| echo "$NVIDIA_CMDLINE" | sudo tee "$NVIDIA_GRUB_CONFIG" > /dev/null | |
| echo "Updated NVIDIA modeset configuration in GRUB" | |
| else | |
| echo "NVIDIA modeset configuration already exists in GRUB" | |
| fi | |
| # Configure NVIDIA power management for suspend/hibernate support | |
| echo "Configuring NVIDIA power management..." | |
| NVIDIA_PM_CONFIG="/etc/modprobe.d/nvidia-power-management.conf" | |
| NVIDIA_PM_OPTION="options nvidia NVreg_PreserveVideoMemoryAllocations=1" | |
| if [ ! -f "$NVIDIA_PM_CONFIG" ]; then | |
| echo "$NVIDIA_PM_OPTION" | sudo tee "$NVIDIA_PM_CONFIG" > /dev/null | |
| echo "Created NVIDIA power management configuration" | |
| elif ! grep -q "NVreg_PreserveVideoMemoryAllocations=1" "$NVIDIA_PM_CONFIG"; then | |
| # Remove any existing conflicting line and add the correct one | |
| sudo sed -i '/NVreg_PreserveVideoMemoryAllocations=/d' "$NVIDIA_PM_CONFIG" | |
| echo "$NVIDIA_PM_OPTION" | sudo tee -a "$NVIDIA_PM_CONFIG" > /dev/null | |
| echo "Updated NVIDIA power management configuration" | |
| else | |
| echo "NVIDIA power management configuration already exists" | |
| fi | |
| # Install and enable NVIDIA suspend/hibernate services | |
| echo "Installing NVIDIA suspend/hibernate support..." | |
| sudo apt install nvidia-suspend-common -y | |
| # Enable NVIDIA power management services | |
| echo "Enabling NVIDIA power management services..." | |
| sudo systemctl enable nvidia-suspend.service 2>/dev/null || echo "nvidia-suspend.service already enabled or not available" | |
| sudo systemctl enable nvidia-hibernate.service 2>/dev/null || echo "nvidia-hibernate.service already enabled or not available" | |
| sudo systemctl enable nvidia-resume.service 2>/dev/null || echo "nvidia-resume.service already enabled or not available" | |
| # Update GRUB configuration to apply kernel modesetting changes | |
| sudo update-grub | |
| # Update the initial ramdisk to include the new drivers | |
| if command -v dracut &> /dev/null; then | |
| echo "Updating dracut initrd..." | |
| sudo dracut --regenerate-all --force | |
| else | |
| echo "Updating initramfs..." | |
| sudo update-initramfs -u | |
| fi | |
| # Clean up any old, uninstalled Nvidia packages | |
| if dpkg -l | grep -q '^rc.*nvidia'; then | |
| echo "Purging old Nvidia package configurations..." | |
| dpkg -l | awk '/^rc/ && /nvidia/ { print $2 }' | xargs sudo apt purge -y | |
| fi | |
| echo "NVIDIA driver installation complete." | |
| # --- Shell and Package Manager Setup --- | |
| # Install Oh My Zsh for a better terminal experience | |
| sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" | |
| # Install Homebrew package manager for Linux | |
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| echo >> ~/.zshrc | |
| echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> ~/.zshrc | |
| eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" | |
| brew install gcc | |
| # Configure Flatpak for application management | |
| sudo apt install flatpak gnome-software-plugin-flatpak -y | |
| sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo | |
| sudo flatpak update | |
| # --- Desktop Application Installation --- | |
| # Install GNOME Extensions utility and Extension Manager | |
| sudo flatpak install flathub org.gnome.Extensions -y | |
| sudo flatpak install flathub com.mattjakeman.ExtensionManager -y | |
| # Replace Firefox ESR with the latest Flatpak version | |
| # Note: Snap is not installed by default on Debian, so 'snap remove' may be unnecessary. | |
| if command -v snap &> /dev/null; then sudo snap remove firefox; fi | |
| sudo apt purge firefox-esr -y | |
| sudo flatpak install flathub org.mozilla.firefox | |
| # Install Brave browser | |
| sudo apt install curl -y | |
| sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg | |
| echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main"|sudo tee /etc/apt/sources.list.d/brave-browser-release.list | |
| sudo apt update | |
| sudo apt install brave-browser -y | |
| # Debloat Brave browser by disabling certain features via policy | |
| sudo mkdir -p /etc/brave/policies/managed/ && sudo chmod 755 /etc/brave/policies/managed/ | |
| sudo tee /etc/brave/policies/managed/00_debloat.json > /dev/null << 'EOF' | |
| { | |
| "TorDisabled": true, | |
| "BraveRewardsDisabled": true, | |
| "BraveWalletDisabled": true, | |
| "BraveVPNDisabled": true, | |
| "BraveAIChatEnabled": false | |
| } | |
| EOF | |
| # Install Thunderbird email client | |
| sudo flatpak install flathub org.mozilla.Thunderbird | |
| # Set Flatpak Firefox as the default web browser | |
| xdg-settings set default-web-browser org.mozilla.firefox.desktop | |
| # Refresh snap packages if snapd is installed | |
| if command -v snap &> /dev/null; then sudo snap refresh; fi | |
| # --- User Environment and Tool Configuration --- | |
| # Configure Emacs as the default text editor | |
| sudo update-alternatives --set editor /usr/bin/emacs | |
| echo ' | |
| # Set default editor to Emacs | |
| export EDITOR="/usr/bin/emacs" | |
| export VISUAL="/usr/bin/emacs" | |
| ' >> ~/.zshrc | |
| # Install 1Password password manager and CLI | |
| # https://support.1password.com/install-linux/#debian-or-ubuntu | |
| curl -sS https://downloads.1password.com/linux/keys/1password.asc | sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg | |
| echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/amd64 stable main' | sudo tee /etc/apt/sources.list.d/1password.list | |
| sudo mkdir -p /etc/debsig/policies/AC2D62742012EA22/ | |
| curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | sudo tee /etc/debsig/policies/AC2D62742012EA22/1password.pol | |
| sudo mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22 | |
| curl -sS https://downloads.1password.com/linux/keys/1password.asc | sudo gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg | |
| sudo apt update && sudo apt install 1password-cli 1password -y | |
| op --version | |
| # Setup SSH key from 1Password | |
| mkdir -p ~/.ssh | |
| # Sign in to 1Password CLI | |
| eval $(op signin) | |
| # Retrieve and install SSH key with specific fingerprint | |
| echo "Retrieving SSH key with fingerprint SHA256:dsPhhaQhifJccmUhI2ZZIoSnEOUIWYRbSe1TWZs2JuA" | |
| ITEM_ID="mijcwmynssrwh33ad3mknt77fy" | |
| op item get "$ITEM_ID" --format json | jq -r '.fields[] | select(.label == "private key") | .value' > ~/.ssh/id_ed25519 | |
| op item get "$ITEM_ID" --format json | jq -r '.fields[] | select(.label == "private key") | .ssh_formats.openssh.value' > ~/.ssh/id_ed25519 | |
| chmod 600 ~/.ssh/id_ed25519.pub | |
| # Set proper security permissions | |
| chmod 600 ~/.ssh/id_ed25519 | |
| echo "SSH private and public keys saved to ~/.ssh/" | |
| eval "$(ssh-agent -s)" | |
| ssh-add ~/.ssh/id_ed25519 | |
| # Setup git global configuration | |
| git config --global user.name "HackingGate" | |
| git config --global user.email "i@hackinggate.com" | |
| git config --global core.editor "emacs" | |
| git config --global init.defaultBranch main | |
| git config --global gpg.format ssh | |
| git config --global commit.gpgSign true | |
| git config --global user.signingkey ~/.ssh/id_ed25519.pub | |
| git config --global submodule.recurse true | |
| # Setup 1Password browser integration for Flatpak | |
| # https://gist.github.com/LinuxSBC/7c39374130d2d443871ddde64cba18a3 1password-flatpak-browser-integration.sh | |
| curl -L https://gist.githubusercontent.com/LinuxSBC/7c39374130d2d443871ddde64cba18a3/raw/1password-flatpak-browser-integration.sh -o 1password-flatpak-browser-integration.sh | |
| chmod +x 1password-flatpak-browser-integration.sh | |
| ./1password-flatpak-browser-integration.sh | |
| # Auto start 1Password for GNOME Shell | |
| mkdir -p ~/.config/autostart | |
| cat > ~/.config/autostart/1password.desktop << 'EOF' | |
| [Desktop Entry] | |
| Name=1Password | |
| Exec=/usr/bin/1password --silent %U | |
| Terminal=false | |
| Type=Application | |
| Icon=1password | |
| StartupWMClass=1Password | |
| Comment=Password manager and secure wallet | |
| MimeType=x-scheme-handler/onepassword; | |
| Categories=Office; | |
| EOF | |
| chmod +x ~/.config/autostart/1password.desktop | |
| echo "1Password autostart configured" | |
| # --- Networking and System Customization --- | |
| # Install Tailscale for secure networking | |
| curl -fsSL https://tailscale.com/install.sh | sh | |
| sudo tailscale up | |
| # Install and configure Starship prompt | |
| brew install starship | |
| echo 'eval "$(starship init zsh)"' >> ~/.zshrc | |
| # Install essential fonts including CJK support | |
| sudo apt install -y fonts-firacode fonts-noto fonts-noto-cjk-extra fonts-noto-extra fonts-noto-ui-core fonts-noto-ui-extra fonts-noto-unhinted | |
| # NOTE: The 'mainline' PPA for kernel management is specific to Ubuntu and has been removed. | |
| # For newer kernels on Debian, consider using the 'backports' repository or manual installation. | |
| # Update firmware | |
| sudo fwupdmgr refresh --force | |
| sudo fwupdmgr update -y | |
| # Install rEFInd boot manager | |
| sudo apt install refind -y | |
| # Configure rEFInd boot timeout | |
| echo "Configuring rEFInd timeout to 5 seconds..." | |
| if [ -f /boot/efi/EFI/refind/refind.conf ]; then | |
| CURRENT_TIMEOUT=$(grep -oP 'timeout \K[0-9]+' /boot/efi/EFI/refind/refind.conf || echo "not set") | |
| sudo sed -i 's/timeout [0-9]\+/timeout 5/' /boot/efi/EFI/refind/refind.conf | |
| echo "rEFInd timeout successfully changed from $CURRENT_TIMEOUT to 5 seconds" | |
| else | |
| echo "Warning: rEFInd configuration file not found at /boot/efi/EFI/refind/refind.conf" | |
| fi | |
| # Configure GRUB boot timeout | |
| echo "Configuring GRUB timeout to 5 seconds..." | |
| if [ -f /etc/default/grub ]; then | |
| sudo sed -i 's/GRUB_TIMEOUT=[0-9]*/GRUB_TIMEOUT=5/' /etc/default/grub | |
| sudo update-grub | |
| echo "GRUB timeout successfully set to 5 seconds" | |
| else | |
| echo "Warning: GRUB configuration file not found at /etc/default/grub" | |
| fi | |
| # --- GNOME Desktop Tweaks --- | |
| # Enable Emacs keybindings across GTK applications | |
| gsettings set org.gnome.desktop.interface gtk-key-theme "Emacs" | |
| # Enable Emacs daemon for better performance for the current user | |
| systemctl --user enable --now emacs | |
| # Configure Caps Lock as an additional Ctrl key | |
| echo "Setting Caps Lock to function as Ctrl..." | |
| current_options=$(gsettings get org.gnome.desktop.input-sources xkb-options) | |
| if [[ $current_options == "@as []" ]]; then | |
| gsettings set org.gnome.desktop.input-sources xkb-options "['ctrl:nocaps']" | |
| else | |
| # Avoid adding if already present | |
| if [[ $current_options != *"ctrl:nocaps"* ]]; then | |
| current_options=${current_options:5:-1} | |
| gsettings set org.gnome.desktop.input-sources xkb-options "[$current_options, 'ctrl:nocaps']" | |
| fi | |
| fi | |
| echo "--- Debian setup script finished ---" | |
| echo "Please reboot your system to apply all changes, especially for the new drivers and kernel modules." |
Router Setup with Dnsmasq and DNSCrypt-Proxy
Debian 13 Trixie router configuration using NetworkManager, dnsmasq for DHCP/DNS, dnscrypt-proxy for encrypted upstream DNS, and UFW for firewall management. Supports both IPv4 and IPv6 with full internet access.
Prerequisites
- Debian 13 Trixie
- NetworkManager installed
- Bridge interface
br-lan(devicebr0) configured at 172.16.0.1/24 - Internet connection via
end0(wan0)
1. Enable IP Forwarding
IP forwarding is required for routing traffic between interfaces for both IPv4 and IPv6.
# Check if already enabled
cat /etc/sysctl.d/99-custom-forward.conf
# If not present, create it:
sudo tee /etc/sysctl.d/99-custom-forward.conf > /dev/null << 'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
# Apply immediately
sudo sysctl -p /etc/sysctl.d/99-custom-forward.conf
# Verify
cat /proc/sys/net/ipv4/ip_forward # Should return 1
cat /proc/sys/net/ipv6/conf/all/forwarding # Should return 12. Install DNSCrypt-Proxy
DNSCrypt-proxy provides encrypted DNS queries (DNS-over-HTTPS or DNSCrypt).
# Install dnscrypt-proxy
sudo apt install dnscrypt-proxy -y
# Check which address dnscrypt-proxy is listening on
sudo ss -lnp | grep dnscrypt-proxyIn most cases, it listens on 127.0.2.1:53.
Verify the service is running:
sudo systemctl status dnscrypt-proxy3. Configure NetworkManager to Use Dnsmasq
NetworkManager can run dnsmasq as an integrated service.
# Configure NetworkManager to use dnsmasq
sudo tee /etc/NetworkManager/conf.d/00-use-dnsmasq.conf > /dev/null << 'EOF'
[main]
dns=dnsmasq
EOF
# Disable systemd-resolved if running
sudo tee /etc/NetworkManager/conf.d/no-systemd-resolved.conf > /dev/null << 'EOF'
[main]
systemd-resolved=false
EOF4. Install and Configure Dnsmasq
# Check for port conflicts
sudo ss -lnup | grep ':53'
# Install dnsmasq
sudo apt install dnsmasq -y
# Disable standalone dnsmasq service (NetworkManager will manage it)
sudo systemctl disable dnsmasq --now5. Configure Dnsmasq for DHCP and DNS
IMPORTANT: NetworkManager's integrated dnsmasq uses the /etc/NetworkManager/dnsmasq-shared.d/ directory for configuration files, NOT /etc/NetworkManager/dnsmasq.d/.
Create dnsmasq configuration to:
- Serve DHCP on br0 (172.16.0.100-200 for IPv4, fd00:172:16::100-200 for IPv6)
- Use dnscrypt-proxy as upstream DNS
- Provide DNS and gateway to clients
- Enable IPv6 Router Advertisements
sudo tee /etc/NetworkManager/dnsmasq-shared.d/router.conf > /dev/null << 'EOF'
# DHCP server for br0 (172.16.0.0/24)
interface=br0
dhcp-range=172.16.0.100,172.16.0.200,12h
# Use dnscrypt-proxy as upstream DNS
server=127.0.2.1
# Never forward plain names (without a dot or domain part)
domain-needed
# Never forward addresses in the non-routed address spaces
bogus-priv
# Don't read /etc/resolv.conf for upstream servers
no-resolv
# Cache size
cache-size=1000
# Listen for DNS queries on these addresses
listen-address=127.0.0.1,172.16.0.1
# DHCP options
dhcp-option=option:router,172.16.0.1
dhcp-option=option:dns-server,172.16.0.1
# IPv6 DHCP range using ULA (Unique Local Address)
dhcp-range=fd00:172:16::100,fd00:172:16::200,constructor:br0,ra-names,64,12h
# Enable IPv6 Router Advertisements
enable-ra
EOF
cat /etc/NetworkManager/dnsmasq-shared.d/router.conf6. Configure Router's Own DNS
The router itself should use its local dnsmasq instance for DNS resolution.
# Remove the symlink to systemd-resolved's resolv.conf
sudo rm /etc/resolv.conf
# Create a static resolv.conf pointing to local dnsmasq
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
# Make it immutable so NetworkManager doesn't overwrite it
sudo chattr +i /etc/resolv.conf
# Verify
cat /etc/resolv.conf7. Configure IPv6 on br0 Interface
Configure NetworkManager to assign an IPv6 ULA address to br0 for LAN clients:
# Add IPv6 address to br-lan connection
sudo nmcli connection modify br-lan ipv6.addresses "fd00:172:16::1/64"
sudo nmcli connection modify br-lan ipv6.method shared
# Reload the connection
sudo nmcli connection up br-lan
# Verify
ip -6 addr show br0
# Should show: inet6 fd00:172:16::1/648. Restart NetworkManager
# Stop systemd-resolved if it's running
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
sudo systemctl mask systemd-resolved
# Restart NetworkManager to apply changes
sudo systemctl restart NetworkManager
# Verify dnsmasq is running under NetworkManager
sudo ss -lnup | grep ':53'
ps aux | grep dnsmasqYou should see dnsmasq listening on both 127.0.0.1:53 and 172.16.0.1:53, and dnscrypt-proxy on 127.0.2.1:53.
9. Install and Configure UFW Firewall
UFW (Uncomplicated Firewall) provides an easy-to-use interface for managing iptables/ip6tables rules. It supports both IPv4 and IPv6 by default.
# Install UFW
sudo apt install ufw -y
# Enable IP forwarding in UFW configuration
sudo sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw
# Verify IPv6 is enabled in UFW (should be yes by default)
grep "^IPV6=" /etc/default/ufw10. Configure IPv4 NAT Rules in UFW
UFW needs NAT (masquerading) rules added to /etc/ufw/before.rules for IPv4 routing.
# Edit /etc/ufw/before.rules and add NAT table BEFORE the *filter table
# The NAT section should be added after the header comments and before the "Don't delete these required lines" section
sudo nano /etc/ufw/before.rulesAdd these lines after the header comments and BEFORE the # Don't delete these required lines line:
# NAT table rules for IPv4 masquerading
*nat
:POSTROUTING ACCEPT [0:0]
# Forward traffic from br0 to WAN interfaces with masquerading
-A POSTROUTING -s 172.16.0.0/24 -o end0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/24 -o wlp1s0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/24 -o wlan0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/24 -o cdc-wdm0 -j MASQUERADE
# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
The file should look like this:
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
#
# NAT table rules for IPv4 masquerading
*nat
:POSTROUTING ACCEPT [0:0]
# Forward traffic from br0 to WAN interfaces with masquerading
-A POSTROUTING -s 172.16.0.0/24 -o end0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/24 -o wlp1s0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/24 -o wlan0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/24 -o cdc-wdm0 -j MASQUERADE
# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-before-input - [0:0]
... (rest of file continues)
11. Configure IPv6 NAT66 Rules in UFW
For IPv6 internet access using ULA addresses, we need NAT66 (IPv6 masquerading).
# Edit /etc/ufw/before6.rules and add NAT table BEFORE the *filter table
sudo nano /etc/ufw/before6.rulesAdd these lines after the header comments and BEFORE the # Don't delete these required lines line:
# NAT66 table for IPv6 masquerading
*nat
:POSTROUTING ACCEPT [0:0]
# Masquerade IPv6 traffic from LAN (ULA) to WAN interfaces
-A POSTROUTING -s fd00:172:16::/64 -o end0 -j MASQUERADE
-A POSTROUTING -s fd00:172:16::/64 -o wlp1s0 -j MASQUERADE
-A POSTROUTING -s fd00:172:16::/64 -o wlan0 -j MASQUERADE
-A POSTROUTING -s fd00:172:16::/64 -o cdc-wdm0 -j MASQUERADE
# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
12. Configure UFW Rules
Configure UFW to allow LAN traffic and routing. These rules apply to both IPv4 and IPv6.
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default allow forward
# Allow all traffic coming in on br0 (LAN interface)
sudo ufw allow in on br0
# Allow SSH access
sudo ufw allow ssh
# Allow routing from br0 (LAN) to WAN interfaces (applies to both IPv4 and IPv6)
sudo ufw route allow in on br0 out on end0
sudo ufw route allow in on br0 out on wlp1s0
sudo ufw route allow in on br0 out on wlan0
sudo ufw route allow in on br0 out on cdc-wdm0
# Enable UFW
sudo ufw enable
# Check status
sudo ufw status verbose13. Verification
Test the setup for both IPv4 and IPv6:
# Check IP forwarding
cat /proc/sys/net/ipv4/ip_forward # Should return 1
cat /proc/sys/net/ipv6/conf/all/forwarding # Should return 1
# Check DNS resolution on the router (IPv4)
dig @127.0.0.1 google.com
dig @172.16.0.1 google.com
# Check that dnsmasq is using dnscrypt-proxy as upstream
dig @127.0.2.1 google.com
# Check dnsmasq is listening on correct addresses
sudo ss -lnup | grep ':53'
# Should show:
# - dnsmasq on 127.0.0.1:53 and 172.16.0.1:53
# - dnscrypt-proxy on 127.0.2.1:53
# Check IPv6 address on br0
ip -6 addr show br0
# Should show fd00:172:16::1/64
# Check UFW status (shows both IPv4 and IPv6 rules)
sudo ufw status numbered
# Check IPv4 NAT rules
sudo iptables -t nat -L POSTROUTING -n -v
# Check IPv6 NAT66 rules
sudo ip6tables -t nat -L POSTROUTING -n -v
# Test IPv4 connectivity
ping -c 3 8.8.8.8
# Test IPv6 connectivity
ping6 -c 3 google.com
# Check dnsmasq leases (after a client connects)
cat /var/lib/NetworkManager/dnsmasq-br0.leases
# Monitor dnsmasq logs
sudo journalctl -u NetworkManager -f | grep dnsmasqFrom a LAN client:
- Connect to the br0 network
- Verify you receive an IPv4 IP in the range 172.16.0.100-200
- Verify you receive an IPv6 IP in the range fd00:172:16::100-200
- Gateway should be 172.16.0.1
- DNS server should be 172.16.0.1
- Test internet connectivity (both IPv4 and IPv6)
- Visit
test-ipv6.comoripv6.google.comto verify IPv6 internet access
Summary
Your router is now configured with:
- DHCP Server: Assigns IPv4 IPs 172.16.0.100-200 and IPv6 IPs fd00:172:16::100-200 to LAN clients on br0
- DNS Server: Dnsmasq on 172.16.0.1, forwarding to dnscrypt-proxy (127.0.2.1)
- Encrypted DNS: DNSCrypt-proxy provides DNS-over-HTTPS/DNSCrypt
- Firewall: UFW managing iptables/ip6tables rules with support for both IPv4 and IPv6
- IPv4 NAT/Routing: Traffic from LAN (br0) is routed to WAN (end0, wlp1s0, wlan0, cdc-wdm0) with masquerading
- IPv6 ULA + NAT66: LAN clients use ULA addresses (fd00:172:16::/64) with NAT66 for internet access
- IPv6 Router Advertisements: Enabled for automatic IPv6 configuration on clients
- Gateway: LAN clients use 172.16.0.1 as their default gateway (both IPv4 and IPv6)
Configuration Files Reference
Key Files Created/Modified:
- IP Forwarding:
/etc/sysctl.d/99-custom-forward.conf - NetworkManager DNS Config:
/etc/NetworkManager/conf.d/00-use-dnsmasq.conf - NetworkManager systemd-resolved:
/etc/NetworkManager/conf.d/no-systemd-resolved.conf - Dnsmasq Config:
/etc/NetworkManager/dnsmasq-shared.d/router.conf(includes IPv6) - Router DNS:
/etc/resolv.conf(immutable, points to 127.0.0.1) - UFW Default Config:
/etc/default/ufw - UFW IPv4 NAT Rules:
/etc/ufw/before.rules - UFW IPv6 NAT Rules:
/etc/ufw/before6.rules(NAT66 for ULA)
Quick Verification Commands
# Check all services are running
sudo systemctl status NetworkManager dnscrypt-proxy ufw
# Check DNS chain is working (both IPv4 and IPv6)
dig @172.16.0.1 google.com +short
dig @172.16.0.1 AAAA google.com +short
# Check firewall rules count
sudo ufw status numbered | wc -l
# Check IPv4 NAT is active
sudo iptables -t nat -L POSTROUTING -n | grep MASQUERADE
# Check IPv6 NAT66 is active
sudo ip6tables -t nat -L POSTROUTING -n | grep MASQUERADE
# Check IPv6 forwarding
cat /proc/sys/net/ipv6/conf/all/forwarding
# Test connectivity (both protocols)
ping -c 2 8.8.8.8 && ping6 -c 2 google.comNotes
- IPv6 with NAT66: This router uses ULA (Unique Local Addresses) for IPv6 with NAT66 enabled for internet access. ULA addresses (fd00::/8) are similar to private IPv4 addresses.
- DNS: The router uses its own dnsmasq (127.0.0.1) which forwards to dnscrypt-proxy (127.0.2.1) for encrypted DNS.
- Immutable resolv.conf: The
chattr +imakes/etc/resolv.confimmutable to prevent NetworkManager from overwriting it. - UFW Configuration: UFW automatically creates both IPv4 and IPv6 rules when you add firewall rules.
- Alternative to NAT66: If your ISP provides IPv6 prefix delegation, you can configure it to get globally routable IPv6 addresses instead of using ULA+NAT66.
Router Settings
On Armbian edge, Photonicat 2
Enable IPv4 forwarding