Author: fjgraf

  • Simple contact form with html and php


    This code is a PHP-based contact form processor that sends emails using the msmtp command. It validates and sanitizes user input, composes an email with the user’s input, and sends it to a hardcoded recipient email address. The code prioritizes security and includes error handling and debugging mechanisms. To use this code, you’ll need to have your own email account that can work with an msmtp configuration, as it relies on this setup to send emails. Overall, the code provides a solid foundation for a contact form processor, and with some customizations, it can become even more robust and feature-rich. Expansion opportunities include adding support for multiple recipient email addresses, implementing CAPTCHA or anti-spam measures, integrating with popular email services, and allowing file attachments.

    HTML

    <style>
        /* Set a max width for the form */<br />
        form {<br />
            width: 100%;<br />
            max-width: 600px;  /* Adjust the max-width as needed */<br />
            margin: 0 auto;  /* Center the form */<br />
            padding: 20px;<br />
            background-color: #f9f9f9;<br />
            border-radius: 8px;<br />
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);<br />
        }</p>
    <p>    /* Style the labels */<br />
        label {<br />
            display: block;<br />
            margin-bottom: 8px;<br />
            font-weight: bold;<br />
        }</p>
    <p>    /* Style the input fields */<br />
        input[type="text"],<br />
        input[type="email"] {<br />
            width: 100%;  /* Make input fields full width */<br />
            padding: 10px;<br />
            margin-bottom: 15px;<br />
            border: 1px solid #ccc;<br />
            border-radius: 4px;<br />
            box-sizing: border-box;  /* Include padding in the width calculation */<br />
        }</p>
    <p>    /* Style the textarea */<br />
        textarea {<br />
            width: 100%;  /* Make the textarea full width */<br />
            height: 150px;  /* Increase the height of the message box */<br />
            padding: 10px;<br />
            margin-bottom: 15px;<br />
            border: 1px solid #ccc;<br />
            border-radius: 4px;<br />
            box-sizing: border-box;  /* Include padding in the width calculation */<br />
        }</p>
    <p>    /* Style the submit button */<br />
        button {<br />
            padding: 12px 20px;<br />
            background-color: #4CAF50;  /* Green background */<br />
            color: white;<br />
            border: none;<br />
            border-radius: 4px;<br />
            cursor: pointer;<br />
            font-size: 16px;<br />
        }</p>
    <p>    button:hover {<br />
            background-color: #45a049;  /* Slightly darker green on hover */<br />
        }</p>
    <p>    /* Add small text for the message character limit */<br />
        .char-limit {<br />
            font-size: 14px;<br />
            color: #888;<br />
            margin-bottom: 10px;<br />
        }<br />
    </style>
    <form action="/contact-process-form.php" method="POST">
        <input type="hidden" name="nonce" value="<?php echo $nonce; ?>"></p>
    <p>    <label for="name">Name:</label><br />
        <input type="text" id="name" name="name" required maxlength="100"></p>
    <p>    <label for="email">Email:</label><br />
        <input type="email" id="email" name="email" required maxlength="100"></p>
    <p>    <label for="subject">Subject:</label><br />
        <input type="text" id="subject" name="subject" required maxlength="100"></p>
    <p>    <label for="message">Message:</label><br />
        <textarea id="message" name="message" required maxlength="6000"></textarea></p>
    <p>    <!-- Add a character limit notice --><br />
        <small class="char-limit">Maximum characters allowed in message: 6000</small><br /> <!-- Added line break --></p>
    <p>    <button type="submit">Send</button><br />
    </form>

    php contact-process-form.php in root folder of website.

    <?php
    // Load WordPress functions (adjust path if necessary)
    require_once('/var/www/bashing.life/wp-load.php');
    
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
    
    // Log errors to a secure file instead of displaying
    ini_set('log_errors', 1);
    ini_set('error_log', '/var/log/php_errors.log');
    
    // Define the path to msmtp (adjust according to where msmtp is installed)
    $msmtp_path = '/usr/bin/msmtp';  // Replace with your msmtp path if it's different
    
    // Define the path to the msmtp configuration file
    $msmtp_config_file = '/etc/msmtprc';  // Replace with the correct path to the msmtp configuration file
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and retrieve the form data
        $name = sanitize_text_field($_POST['name']);
        $email = sanitize_email($_POST['email']);
        $subject = sanitize_text_field($_POST['subject']);
        $message = wp_kses_post($_POST['message']);  // Sanitizing message further
    
        // Validate the email address
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            echo "Invalid email format.";
            exit;
        }
    
    // Escape each variable to prevent command injection
        $safe_name = escapeshellarg($name);
        $safe_email = escapeshellarg($email);
        $safe_subject = escapeshellarg($subject);
        $safe_message = escapeshellarg($message);
    
        $hardcoded_subject = "New Contact Form Submission";
    
        $email_content = "You have received a new contact form submission:\n\n";
        $email_content .= "Name: $safe_name\n";
        $email_content .= "Email: $safe_email\n";
        $email_content .= "Subject (from form): $safe_subject\n\n";
        $email_content .= "Message:\n$safe_message\n";
    
     // Escape the full email content (to ensure no issues with newlines, quotes, etc.)
        $escaped_email_content = escapeshellarg($email_content);
    
        // Send the email using msmtp
        $recipient = 'example@example.com';  // Your recipient email address
    
        // Properly escape the command to avoid injection
    
        $command = "echo \"Subject:$hardcoded_subject\nContent-Type: text/plain; charset=UTF-8\n\n$email_content\" | $msmtp_path --file=$msmtp_config_file -a default example@example.com";
    
    
        // Execute the command and capture the output
        $output = shell_exec($command . ' 2>&1');  // Capture both stdout and stderr
    
        // Debugging: Check if output is captured and display it
        if ($output === null) {
            echo "Failed to send the message. No output received from msmtp.";
        } else {
            //echo "Message sent successfully!<br>"; //for future debugging
            //echo "<strong>Debugging Output from msmtp:</strong><br>"; //for future debugging
            //echo "<pre>$output</pre>";  // Debugging output from msmtp
            // Redirect to the thank-you page after success
            header("Location: thank-you");
            exit;
        }
    
    } else {
        echo "Please fill in all fields.";
    }
    ?>
    
    

    The msmtprc system-wide configuration file must be in /etc

  • Fixing Proxmox SSL Certificates Behind HAProxy: Step-by-Step Tutorial

    This tutorial chronicles my troubleshooting and resolution process for SSL certificate issues with Proxmox when running behind an OpenWRT router with HAProxy. It includes all intermediate steps, challenges, and reasoning, as well as interactions with my assistant, which helped guide the solution.


    1. Network Context and Initial Problem

    My setup was as follows:

    ISP Router -> OpenWRT (DMZ) with HAProxy -> Proxmox
    • Proxmox listens on its default HTTPS port 8006.
    • Other internal web servers are served through HAProxy, which handles TLS for domains like aurispetreus.net.
    • My goal was to have valid, trusted TLS certificates for Proxmox while maintaining other web services on the same HAProxy instance.

    Problem Observed

    When attempting to access Proxmox through its domain (for example, using the Proxmox Android app), I encountered SSL protocol errors. Initially, I wasn’t sure whether:

    1. Proxmox was failing to pick up the manually uploaded certificates.
    2. HAProxy configuration was interfering with TLS termination.
    3. File permissions or certificate formats were incorrect.

    2. Generating and Copying Certificates

    Proxmox could not directly request Let’s Encrypt certificates because it wasn’t publicly accessible from the internet. Therefore, I generated certificates on a separate Debian server (debian) that could reach Let’s Encrypt:

    certbot certonly -d da3.aurispetreus.net

    This created:

    /etc/letsencrypt/archive/da3.aurispetreus.net/fullchain1.pem
    /etc/letsencrypt/archive/da3.aurispetreus.net/privkey1.pem

    I then manually copied these files to Proxmox (proxmox A) and renamed them to match Proxmox’s expected filenames:

    /etc/pve/local/pve-ssl.pem       # fullchain
    /etc/pve/local/pve-ssl.key       # private key

    I also set proper permissions for the private key:

    chmod 600 /etc/pve/local/pve-ssl.key

    At this point, I suspected that the certificates might not be correctly paired, so I decided to verify them.


    3. Verifying Certificate and Key Match

    To ensure the certificate and private key matched, I used OpenSSL to check the modulus:

    openssl x509 -noout -modulus -in fullchain1.pem | openssl md5
    openssl rsa -noout -modulus -in privkey1.pem | openssl md5

    Initially, I received:

    Not an RSA key

    This indicated a misuse of commands or possibly a non-RSA key (like EC). After adjusting the method (taking into account the correct type of key generated by Certbot), I confirmed that the modulus of the certificate and the private key matched, verifying they belonged together.


    4. HAProxy Configuration for Proxmox

    Since Proxmox sits behind HAProxy, it was important that TLS traffic be forwarded correctly. I started with the following principles:

    1. Use TCP mode on HAProxy for port 443 to allow end-to-end TLS (Proxmox manages its own certificates).
    2. Route traffic using SNI to direct specific domains to their respective backend servers.
    3. Keep the standard HTTPS port (443) public, without binding Proxmox’s internal port 8006 on HAProxy.

    Here’s the relevant HAProxy frontend for HTTPS:

    frontend https_in
        bind *:443
        mode tcp
        option tcplog
    
        # Inspect TLS handshake for SNI
        tcp-request inspect-delay 5s
        tcp-request content accept if { req_ssl_hello_type 1 }
    
        # Use backend based on requested SNI
        use_backend %[req.ssl_sni,lower]_tls if { req.ssl_sni -m found }

    And the Proxmox backend:

    backend da3.aurispetreus.net_tls
        mode tcp
        option tcp-check
        server da3.aurispetreus.net 192.168.3.144:8006 check
    # Note: No need to bind HAProxy to port 8006 externally

    Important detail: The assistant reminded me explicitly:
    “No, you do not bind port 8006 on HAProxy, because HAProxy is meant to expose a public listener on the standard HTTPS port (443).”
    This avoids exposing internal Proxmox ports directly and keeps the network cleaner.


    5. Initial Testing

    I tested the TLS handshake locally:

    curl -vk https://192.168.3.144:8006/

    Output confirmed that TLSv1.3 was being used, and the correct certificate was presented.

    Externally, trying to access 188.21.68.172:8006 failed because the ISP router blocked the direct connection, which was expected.


    6. Debugging “Wrong Version Number” Error

    When testing public access via HAProxy:

    curl -vk https://da3.aurispetreus.net:443

    I got:

    error:0A00010B:SSL routines::wrong version number

    Analysis:

    • The HAProxy frontend for port 443 was in HTTP mode.
    • TLS traffic to Proxmox requires TCP passthrough, not HTTP mode.

    Solution: Change the frontend to TCP mode. After doing so, the handshake worked correctly, and the Proxmox Android app could connect.

  • Cockpit via Apache Reverse Proxy

    I know, this is very unsafe if your login credentials are stolen but it serves as a proof of concept!!!

    1. The Goal

    To provide secure, external access to the Cockpit Web Console via https://example.site/cockpit/ without opening extra ports (like 9090) on the router and without managing separate SSL certificates for the dashboard.

    2. Architecture Flow

    1. User requests https://example.site/cockpit/.
    2. OpenWrt (HAProxy) receives traffic on port 443 and passes it to the Debian LXC (192.168.1.16:443).
    3. Apache (inside LXC) terminates the SSL using Let’s Encrypt certificates.
    4. Apache proxies the request internally to 127.0.0.1:9090.
    5. Cockpit processes the request and responds through the tunnel.

    3. Key Configurations

    A. Apache VirtualHost (/etc/apache2/sites-available/...)

    We used mod_proxy and mod_rewrite to handle both standard web traffic and the persistent WebSocket connections required for the Cockpit terminal.

    # WebSocket Upgrade (Fixes "Login then Blank Page" issue)
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /cockpit/(.*) ws://127.0.0.1:9090/cockpit/$1 [P,L]
    
    # Subfolder Proxy
    <Location /cockpit/>
        ProxyPass http://127.0.0.1:9090/cockpit/
        ProxyPassReverse http://127.0.0.1:9090/cockpit/
    </Location>

    B. Cockpit Config (/etc/cockpit/cockpit.conf)

    Crucial for preventing CSRF (Cross-Site Request Forgery) security blocks and allowing the unencrypted internal “handshake.”

    [WebService]
    Origins = https://hissite.org
    ProtocolHeader = X-Forwarded-Proto
    AllowUnencrypted = true
    UrlRoot = /cockpit

    4. Troubleshoot Log & Fixes

    • Issue:sscg: command not found.
      • Fix: Installed sscg package to satisfy Cockpit dependencies.
    • Issue:gnutls_handshake failed: A TLS fatal alert.
      • Reason: Cockpit was expecting HTTPS but Apache was sending HTTP.
      • Fix: Added AllowUnencrypted = true and restarted cockpit.socket.
    • Issue: Blank page after login.
      • Reason: WebSockets (the “live” part of the site) were failing to tunnel through Apache.
      • Fix: Added specific RewriteRule for ws:// protocol.

    5. Security Hardening Applied

    • Consolidated SSL: All traffic uses the main site’s hardened TLS 1.2/1.3 settings.
    • Internal Communication: Apache talks to Cockpit over 127.0.0.1 (local loopback), meaning no unencrypted traffic ever touches your LAN or the WAN.

    6. Maintenance Commands

    If Cockpit ever stops responding, run these in order:

    1. sudo systemctl restart cockpit.socket (Restarts the listener)
    2. sudo systemctl restart apache2 (Restarts the proxy)
    3. sudo journalctl -u cockpit -f (To watch live logs if a crash occurs)
  • GnuDIP

    GnuDIP2 can be used to update your ip address. The following configuration is going to be tailored to manage the free ddns service provided in ddns.freedombox.org or compatible ddns services.

    Before starting you need to already have a gnudip account and install the curl package (sudo apt install curl).

    Download the latest version of GnuDIP from the official site:
    https://gnudip2.sourceforge.net/gnudip-www/latest/gnudip/html/clients.html

    Direct link:
    https://gnudip2.sourceforge.net/gnudip-www/latest/gnudip/html/client/UNIX/gnudip-latest-gdipc.tar.gz

    Change to your root account: This is so that the gdipc script (necessary to update the ip address of your service) can be run at a regular basis without the need to log in with your personal user account. Just let the root user handle it and forget it…

    Decompress and untar the file to /usr/local/

    Now you need to add a new directory path to your $PATH so you can run the script at the location where the gdipc folder was placed. Recomended location /usr/local/

    Edit the .bashrc file of your root account and add the following line at the end:

    #DDNS GnuDIP update service
    export PATH="$PATH:/usr/local/gdipc/bin"

    Source the file to update your $PATH with:

    source ~/.bashrc

    Running gdipc.pl script to add a new entry. This entry will contain the necessary information so that GnuDIP2 logs in to your account and verify if it needs to update your ip address.

    When you run gdipc.pl with the -c option, it allows you to configure the script through an interactive setup. This can help avoid manual editing of the script and ensure all necessary settings are entered correctly. Additionally, the information you enter will be saved in .GnuDIP2 in the same root home directory.

    1. Run the Script with -c Option:To begin the configuration process, run the script with the -c flag: gdipc.pl -c
    2. Follow the Prompts:The script will prompt you for the required configuration details. You will need to input the following:
      • Username: Your user account created in ddns.freedombox.org
      • Domain: Depending on the subdomain chosen at the time of registration like fbx.one or freedombox.rocks.
      • Connect by direct TCP (d) or web server (w) [d]:
      • GnuDIP Server – host[:port]: ddns.freedombox.org
      • Password: Your password provided at registration.
      • Cache File [/root/.GnuDIP2.cache..]: Location of the cache file.
      • Minimum Seconds Between Updates [0]: Leave as default
      • Maximum Seconds Between Updates [2073600]: Leave as default
    3. Complete the Configuration:After entering all the necessary information, the script will configure itself with the values you’ve provided.
    4. Verify the Configuration:Once you’ve configured the script, you can run it without the -c option to check if the DDNS update process works correctly:
      gdipc.pl The script should now update the DDNS service with your current IP address and domain.
    5. Automate the Process :To ensure your IP is updated regularly, you can automate the execution of gdipc.pl using a cron job.
      • Here’s an example cron job that runs the script every 10 minutes:
      • crontab -e Add the following line to run the script every 10 minutes:
        • */10 * * * * /usr/local/gdipc/bin/gdipc.pl -q "curl -s ifconfig.me" >> /home/root/.GnuDIP2.log 2>&1
        • Note that “curl -s ifconfig.me” will retrieve you public ip address.
    6. Executing and Logging: As you can see in the cron job configured, the script needs to be executed with the -q option. This is because if its run without it, it will use the local ip address of your network and not your public ip address to perform the update. Additionally, is configured standard and error output to a log file to keep track of the script work.
    • With -q Option: You can specify a command to retrieve the IP address, and the script will execute that command.
    • Without -q Option: The script tries to obtain the local machine’s IP address via getsockname() on a socket connection.
    • With -g Option: If you’re behind a gateway, the script registers the external IP address that the GnuDIP server sees.

  • wireguard config openwrt

    FINAL REVISED & HARDENED WIREGUARD FULL-TUNNEL SETUP ON OPENWRT (LUCI-ONLY)

    This configuration:

    • provides full-tunnel internet through home
    • gives VPN clients secure access to LAN devices
    • uses DNS-over-HTTPS for leak-proof DNS
    • follows OpenWrt firewall best practices
    • corrects all issues found in your shared configuration
    • requires no terminal commands

    ⭐ STEP 0 — Remove unsafe default “vpn” zone

    You already created a “vpn” zone. That setup is incorrect for full-tunnel.

    LUCI:

    Network → Firewall → Zones → delete the “vpn” zone

    Click Save & Apply.

    Now you should have only:

    • lan
    • wan

    Perfect.


    ⭐ STEP 1 — Add wg0 to LAN firewall zone

    This is the correct & secure model for road-warrior VPN in OpenWrt.

    LUCI:
    Network → Firewall → Zones → Edit “lan”

    Under Covered networks:

    lan
    wg0CHECK THIS

    Default policies (recommended):

    • Input: ACCEPT
    • Output: ACCEPT
    • Forward: ACCEPT
    • Masquerading: DISABLED
      (WAN zone handles NAT — as it should)

    Under “Allow forward to destination zones”:

    wan
    (no others)

    Under “Allow forward from source zones”:

    ✔ none required
    (but you may see unspecified, that’s okay)

    Click Save & Apply.


    ⭐ STEP 2 — Verify WAN zone has Masquerading enabled

    This is required for full-tunnel routing.

    LUCI:
    Network → Firewall → Zones → Edit “wan”

    Ensure these are correct:

    • Input: REJECT
    • Output: ACCEPT
    • Forward: REJECT
    • Masquerading: ENABLED
    • MSS clamping: OPTIONAL but recommended

    Save & Apply.


    ⭐ STEP 3 — WireGuard interface settings

    LUCI: Network → Interfaces → wg0

    General Settings:

    • Private Key → exists ✔
    • Listen Port → 51820
    • IP address:
    • 10.0.0.1/24
    • “Bring up on boot” → ✔

    Firewall Settings tab:

    • Assign wg0 to zone: lan

    Save & Apply.


    ⭐ STEP 4 — WireGuard peer (your phone/app)

    LUCI → Interfaces → wg0 → Peers → Add peer

    Fill in:

    Required fields:

    • Description: phone
    • Public Key: (phone app → generated key)
    • Allowed IPs:
    • 10.0.0.2/32

    Leave endpoint empty (phone connects to router; router does not initiate).

    Click Save.


    ⭐ STEP 5 — Traffic rule (WireGuard port)

    You already have this correct — just verify.

    LUCI:
    Network → Firewall → Traffic Rules

    Find rule named wireguard:

    Checklist:

    • Protocol: UDP
    • Source zone: wan
    • Source port: any
    • Destination zone: Device (input)
    • Destination port: 51820
    • Action: ACCEPT

    If all correct → leave it.


    ⭐ STEP 6 — Configure the phone (full tunnel & LAN access)

    Open the WireGuard app → edit tunnel.

    Replace values:

    
    
    
    
    
    [Interface]
    PrivateKey = <phone private key>
    Address = 10.0.0.2/32
    DNS = 10.0.0.1
    
    [Peer]
    PublicKey = <router public key>
    Endpoint = <your.ddns.or.public.ip>:51820
    AllowedIPs = 0.0.0.0/0
    PersistentKeepalive = 25 or leave blank for auto
    

    This ensures:

    ✔ All traffic goes through home
    ✔ DNS sent to router → goes through encrypted DoH
    ✔ No leaks
    ✔ VPN can reach LAN devices (192.168.1.0/24)


    ⭐ STEP 7 — Enable DNS-over-HTTPS on OpenWrt (LUCI-only, secure)

    This step prevents any DNS leaks and improves privacy.


    🔹 Install DoH resolver (via LUCI)

    LUCI:
    System → Software

    Search for:

    • https-dns-proxy
    • luci-app-https-dns-proxy

    Install both.


    🔹 Configure DoH (Cloudflare recommended)

    LUCI:
    Services → HTTPS DNS Proxy

    Enable an instance:

    • Provider: Cloudflare
    • Listen address: 127.0.0.1
    • Listen port: 5053

    Save & Apply.

    This sets the router DNS → DoH resolver.


    🔹 Point OpenWrt DNS to DoH

    LUCI:
    Network → DHCP and DNS → General Settings

    Under DNS Forwardings:

    
    
    
    
    
    127.0.0.1#5053

    Apply.

    Now all DNS from:

    • LAN devices
    • VPN clients (10.0.0.2)
    • The router itself

    is encrypted.


    ⭐ STEP 8 — Force VPN clients to use router DNS

    To prevent DNS bypass:

    LUCI:
    Network → Firewall → Traffic Rules → Add

    Create rule:

    • Name: Force-DNS-LAN-VPN
    • Source zone: lan
    • Destination port: 53
    • Action: REJECT

    Save & Apply.

    Now the phone cannot bypass router DNS.
    All DNS → VPN → Router → DoH.

    No leaks.


    ⭐ STEP 9 — Testing (VERY IMPORTANT)

    With VPN enabled on phone:

    Test external IP:

    https://ifconfig.me


    → should show your home public IP.

    Test DNS leak:

    https://browserleaks.com/dns


    → should show Cloudflare only (not mobile carrier, not Google, not ISP DNS).

    If anything leaks → tell me and I will fix it.


    🎉 YOUR CONFIGURATION IS NOW FULLY SECURE

    You now have:

    ✔ Fully operational WireGuard full-tunnel
    ✔ VPN access to LAN for remote management
    ✔ Encrypted DNS-over-HTTPS (no DNS leaks)
    ✔ Hardened firewall
    ✔ Correct OpenWrt zone model
    ✔ Privacy-safe mobile connection

  • AdGuard Home (AGH) Port Conflict Resolution

    AdGuard Home (AGH) Port Conflict Resolution

    AdGuard Home requires ports 53 (DNS) and 80 (Web Interface), but OpenWrt’s core services (Dnsmasq and LuCI) already use them. Use the following steps via SSH to fix the conflicts.


    1. Resolve Port 53 Conflict (DNS)

    We move OpenWrt’s Dnsmasq server from port 53 to port 5353, allowing AGH to take the standard port 53.

    1. Stop AGH: /etc/init.d/adguardhome stop
    2. Move Dnsmasq to Port 5353 (Execute these three lines): uci set dnsmasq.@dnsmasq[0].port=’5353′ uci commit dnsmasq /etc/init.d/dnsmasq reload
    3. Configure AGH DNS Port: During the AGH welcome screen setup, set its DNS server port to 53.

    2. Resolve Port 80 Conflict (Web Interface)

    Since port 80 is used by LuCI and your reverse proxy, we change the AGH dashboard port.

    1. Configure AGH Web Port: During the AGH welcome screen setup, change the Web interface port from 80 to an available port like 8080 or 81.
      • Access: You will access the AGH dashboard via http://[OpenWrt_IP]:8080 (or the port you chose).

    3. Finalize Traffic Redirection

    Once AGH is set up and listening on port 53, you must redirect all DNS traffic hitting the router (which goes to Dnsmasq on port 5353) back to AGH on port 53.

    1. Add a Forward Rule and Restart Dnsmasq (Execute these three lines): uci set dnsmasq.@dnsmasq[0].server=’127.0.0.1#53′ uci commit dnsmasq /etc/init.d/dnsmasq restart

    4. Verification

    • Check the AGH dashboard at your chosen port (e.g., http://[OpenWrt_IP]:8080).
    • Ensure devices are successfully being filtered.
  • Guide: Installing Realtek RTL8125 Driver on Debian/Proxmox

    This guide resolves issues encountered when installing the TP-Link TX21/Realtek RTL8125 driver on a Debian-based system (like Proxmox) that already has an older Realtek NIC using the built-in r8169 driver.

    Prerequisites

    • Console Access: Since network connectivity will be interrupted, you must have physical access (keyboard/monitor) or IPMI/iDRAC/vPro access.
    • Latest Driver: Ensure you download the latest Linux driver tarball for the RTL8125 chip directly from the Realtek website to avoid compilation errors with newer kernels.
    • Kernel Headers & DKMS: Install the necessary packages for compiling the driver:Bash
    apt update
    apt install build-essential dkms pve-headers

    1. Resolve Driver Installation Failure (The Hang)

    The installer (autorun.sh) will hang because the kernel’s default r8169 driver is actively in use by another NIC.

    A. Identify and Disable the Conflicting Interface

    1. Find the Physical Interface and Bridge: Use ip a to identify the active interface using the r8169 driver (e.g., enp6s0) and the corresponding Proxmox bridge (e.g., vmbr1).
    2. Bring Down the Network: This will stop the driver’s process, allowing the installer to unload it.
    ifdown vmbr1               # Bring down the bridge (crucial for Proxmox)
    ip link set enp6s0 down    # Bring down the physical interface
    • Manually Unload the Old Driver:
    rmmod r8169

    B. Run the Installation

    1. Navigate to the new driver directory (e.g., cd r8125-9.011.00).
    2. Execute the installer:
    ./autorun.sh

    If successful, the script will compile the new r8125 module using DKMS and install it.

    Reboot:

    reboot

    2. Resolve NIC Conflict (Missing Interfaces)

    After installation, the new r8125 driver often aggressively claims both the new NIC and the older onboard NIC, leaving the older one unusable.

    The solution is to bind the custom r8125 driver only to the new card, leaving the old card for the kernel’s r8169 driver.

    A. Identify the New Card’s PCI Address

    1. List PCI devices and find the new Realtek card: Look for the device actively using the r8125 driver and note its PCI address (e.g., 04:00.0).
    lspci -nnk | grep -i realtek -A3

    B. Create a Driver Binding Rule

    1. Create the configuration file: This uses the install directive to tell the system to load r8125 but only bind it to the specified PCI address.
    # REPLACE [NEW_CARD_PCI_ADDRESS] with your actual address (e.g., 04:00.0)
    echo 'install r8125 /sbin/modprobe --ignore-install r8125; /usr/bin/echo "[NEW_CARD_PCI_ADDRESS]" > /sys/bus/pci/drivers/r8125/bind' > /etc/modprobe.d/r8125-bind.conf
    • Update Initramfs: This applies the new binding rule before the kernel loads drivers.
    update-initramfs -u -k all

    and reboot now.

    3. Final Verification

    After the final reboot, both network interfaces should be present and active:

    • Check all interfaces:Bash
    ip a
    • Verify drivers:
      • The new TX21 card should show driver: r8125.
      • The old onboard NIC (e.g., enp6s0) should show driver: r8169.
  • OpenWrt MT7610U AP Install and config AP

    1. ⚙️ Hardware & Driver Installation

    The core task was installing the correct drivers and firmware for your MediaTek MT7610U chipset (Vendor ID 0b05:17d1).

    • Driver: Installed the kernel module responsible for the MT76x0 series USB chips:
      • opkg install kmod-mt76x0u
    • Firmware: Installed the required binary data for the chip to function (named for a similar chip in the family):
      • opkg install mt7601u-firmware
    • AP Management: Installed the daemon necessary to run a Wi-Fi Access Point and handle modern encryption:
      • opkg install hostapd-wolfssl (Chosen for full WPA3 support with a lightweight security library.)

    2. 🔒 Wireless Security (Encryption)

    You selected the strongest security suitable for a simple, password-based AP.

    • Protocol Choice: WPA3-SAE (Simultaneous Authentication of Equals).
    • Reasoning:
      • Simplicity: Uses a passphrase, eliminating the need for a complex RADIUS server (which would be required by WPA3-EAP/Enterprise).
      • Security: Provides modern protection against offline dictionary attacks, which WPA2-PSK is vulnerable to.

    3. 📶 Wireless Mode & Compatibility

    You successfully configured the AP to run on the 2.4 GHz band while maintaining compatibility for legacy devices.

    • Band: 2.4 GHz (Chosen for better range and penetration for remote management).
    • Mode: N (802.11n).
    • Compatibility: Selecting N mode allows all modern 802.11n devices to connect, while simultaneously enabling 802.11g mode, ensuring your older 2.4 GHz-only client can connect successfully.
    • Channel Width: (Implicitly or explicitly set to) 20 MHz (HT20) for maximum stability and compatibility in the congested 2.4 GHz band.
  • Easy Files Encryption

    Don’t trust password managers? Well you can encrypt that txt file full of complicated passwords and give it a master password that hopefully only you will know about.

    Encrypting a File with Explicit Cipher:

    gpg --symmetric --cipher-algo AES256 file.txt

    In this example, AES256 is used as the cipher algorithm, providing strong encryption.

    To further enhance security, you can also add the --s2k-cipher-algo, --s2k-digest-algo, and --s2k-mode options for passphrase hashing. For example:

    Enhanced Security Example:

    gpg --symmetric --cipher-algo AES256 --s2k-cipher-algo AES256 --s2k-digest-algo SHA512 --s2k-mode 3 file.txt

    Here’s a breakdown of the options used:

    • --cipher-algo AES256: Specifies the symmetric encryption algorithm (AES256 in this case).
    • --s2k-cipher-algo AES256: Specifies the cipher algorithm for the passphrase-to-key conversion.
    • --s2k-digest-algo SHA512: Specifies the hash algorithm used for passphrase-to-key conversion.
    • --s2k-mode 3: Iterated and salted passphrase-to-key conversion.

    Remember, the goal is to balance security with usability. Stronger encryption and hashing algorithms may increase security but could also impact performance.

    When decrypting, GPG will automatically use the appropriate algorithms based on the information stored in the encrypted file.

    Feel free to adjust the options based on your security requirements, and always ensure that the recipients of the encrypted file can decrypt it with the chosen settings.

    2. CCRYPT COMMAND

    Another super easy method is to use ccrypt. It’s simple and fast and if you forget the password there is no way to decrypt or crack ope the file AFAIK.

    To encrypt:

    ccrypt -e my_file

    A file named my_files.cpt will be created

    To decrypt:

    ccrypt -d my_files.cpt

    And you get the original file back.

  • Connection metric management

    Here is how with some simple steps I changed the metric of an internet connection in order to give priority to a usb dongle so its set as the default interface for internet traffic in my personal laptop. The laptop’s integrated wifi interface does not support 5 Ghz connections so every time I boot up the system I had to manually disconnect the integrated interface and reconnect it so its metric changes to a higher value:

    First one needs to see the internet connections managed by the NetworkManager service in order to get the name of the internet connection we need to modify:

    nmcli connection show

    The list shows the 2 wifi connections I currently use. One is for General internet traffic and the other one to manage an openwrt device:

    NAME                    UUID                                  TYPE      DEVICE
    Connection_1            0711f8ae-049e-4e4f-8800-3cffc70b458f  wifi      wlp3s0
    Connection_2            b2c7835e-69ac-4520-b401-f7120a456d65  wifi      wlx3xvre3db545  

    To verify the current metric for both interfaces we use ip route:

    default via 192.168.1.1 dev wlp3s0 proto dhcp src 192.168.1.111 metric 600
    default via 192.168.5.1 dev wlx3xvre3db545 proto dhcp src 192.168.5.198 metric 601  

    As we can see the internet traffic has a default route through the slower wifi interface. We can change this by changing the metric:

    nmcli connection modify "Connection_2" ipv4.route-metric 100

    We restart the service:

    sudo systemctl restart NetworkManager

    Once the service is back up we verify the metric again:

    default via 192.168.5.1 dev wlx3xvre3db545 proto dhcp src 192.168.3.198 metric 100  
    default via 192.168.1.1 dev wlp3s0 proto dhcp src 192.168.1.111 metric 602

    This change will be persistent after a reboot.