Showing posts with label Sysadmin. Show all posts
Showing posts with label Sysadmin. Show all posts

Sunday, May 25, 2025

How to Configure an Nginx Reverse Proxy with WebSockets for Kodi Chorus2

This tutorial details how to configure Nginx as a secure reverse proxy for Kodi's Chorus2 web interface, enabling full remote media playback control over HTTPS under a subpath (e.g., https://domain.com/kodi/).

Before configuring Nginx, enable the Kodi Web Server in Settings → Services → Control and set a secure username and password, as documented in the Kodi Web Interface Wiki.

The Nginx URI Normalization Challenge

Kodi Chorus2 requires two distinct routing configurations:

  1. WebSocket JSON-RPC (port 9090): Real-time playback status and control events route through /jsonrpc without path prefixing.
  2. Web Assets & Album Art (port 10080 / 8080): Chorus2 fetches album artwork and movie posters using dynamic queries. Under Nginx's proxy_pass specification, naive subpath proxying will corrupt the image query string unless the normalized request URI is explicitly matched and forwarded.

Nginx Configuration (/etc/nginx/sites-available/kodi.conf)

Add the following location blocks to your Nginx HTTPS server block:

## Kodi Reverse Proxy Configuration

# 1) WebSocket channel for JSON-RPC
location ^~ /jsonrpc {
    proxy_http_version 1.1;
    proxy_set_header   Upgrade    $http_upgrade;
    proxy_set_header   Connection "Upgrade";
    proxy_set_header   Host       $host;
    proxy_set_header   X-Real-IP  $remote_addr;
    proxy_read_timeout 360s;
    proxy_pass         http://10.10.1.5:9090;
}

# 2) Redirect bare /kodi to canonical /kodi/
location = /kodi {
    return 301 /kodi/;
}

# 3) Proxy Chorus2 web interface and strip /kodi prefix
location /kodi/ {
    if ($request_uri ~ "^/kodi(?/[^?]*)") {
        set $new_path $after;
    }

    proxy_cache        off;
    proxy_set_header   Host      $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_read_timeout 300s;

    proxy_pass         http://10.10.1.5:10080$new_path$is_args$args;
}

Test your configuration and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

In Chorus2 settings (in your browser), enable reverse proxy mode and set the port to 443. Album art, audio streaming, and WebSocket playback controls will now operate flawlessly.

Friday, March 1, 2024

How to Disable Automatic Sleep and Suspend on Debian 12 Production Servers

When running Debian 12 (Bookworm) on home servers, lab nodes, or production workstations with desktop environments installed, power-saving defaults can cause the system to automatically suspend or sleep after periods of user inactivity (no keyboard or mouse movement). This disconnects SSH sessions and halts background services.

Method 1: Configure GDM3 Greeter Power Settings (Desktop / GDM3)

For systems running the GNOME Display Manager (GDM3), edit the greeter defaults configuration:

sudo nano /etc/gdm3/greeter.dconf-defaults

Uncomment or add the following directives under [org/gnome/settings-daemon/plugins/power] to set inactive timeout actions to blank instead of suspend:

[org/gnome/settings-daemon/plugins/power]
sleep-inactive-ac-type='blank'
sleep-inactive-battery-type='blank'

Method 2: Mask Systemd Sleep Targets (Recommended for Headless / Servers)

To completely prohibit the Linux kernel and systemd from entering sleep, suspend, or hibernation at any time, mask the respective systemd targets:

sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
Verification: Check system sleep state with systemctl status sleep.target. If masked, the target points to /dev/null, ensuring 24/7 server uptime without unexpected idle shutdowns.

Wednesday, February 21, 2024

How to Set Up a Tunneled Wi-Fi Hotspot on Raspberry Pi OS Bookworm with WireGuard and NetworkManager

This guide updates our earlier tutorial for Debian 12 Bookworm on Raspberry Pi. In this architecture, the Raspberry Pi connects to upstream internet via Ethernet (eth0), establishes an encrypted WireGuard VPN tunnel (wg0), and broadcasts a secure Wi-Fi access point on wlan0. All client traffic connected to the hotspot is policy-routed strictly through the WireGuard tunnel.

Modern Bookworm Architecture: NetworkManager replaces dhcpcd and leverages the built-in dnsmasq-base plugin for DHCP and DNS caching, eliminating the need for standalone services like isc-dhcp-server.

1. Create the Wi-Fi Hotspot Profile in NetworkManager

Create a hotspot connection in the Raspberry Pi desktop Network GUI or via nmcli. Set the hotspot subnet to 10.0.1.1/24, enable auto-connect, and set MTU to 1420.

To enforce robust WPA2-only (RSN/AES) authentication and disable legacy WPA1:

nmcli con modify "Wi-Fi Hot" 802-11-wireless-security.proto rsn

2. Configure Policy Routing Table

Create a dedicated routing table for hotspot clients (subnet 10.0.1.0/24):

echo "200 INET2" | sudo tee -a /etc/iproute2/rt_tables

3. WireGuard Configuration (/etc/wireguard/wg0.conf)

Configure WireGuard with policy rules and MSS clamping to ensure seamless MTU handling through the tunnel:

[Interface]
PrivateKey = YOUR_PRIVATE_KEY
Address = 10.10.0.6/24
PostUp = iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE; ip rule add from 10.0.1.0/24 table INET2 priority 100; ip route add default dev wg0 table INET2; ip route add 8.8.8.8/32 dev wg0; ip route add 8.8.4.4/32 dev wg0; iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; iptables -t mangle -A FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; ip route flush cache
PreDown = iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE; ip rule del from 10.0.1.0/24 table INET2 priority 100; ip route del default dev wg0 table INET2; ip route del 8.8.8.8/32 dev wg0; ip route del 8.8.4.4/32 dev wg0; iptables -t mangle -D FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; iptables -t mangle -D FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu; ip route flush cache
Table = off
MTU = 1280

[Peer]
PublicKey = SERVER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0
Endpoint = YOUR_VPN_SERVER_IP:PORT
PersistentKeepalive = 25

4. Enable Kernel IPv4 Forwarding

Enable packet forwarding in /etc/sysctl.conf:

sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf

5. DNS Configuration for DHCP Clients

Configure NetworkManager's shared dnsmasq instance to supply public DNS servers to hotspot clients:

sudo mkdir -p /etc/NetworkManager/dnsmasq-shared.d/
echo "dhcp-option=option:dns-server,8.8.8.8,8.8.4.4" | sudo tee /etc/NetworkManager/dnsmasq-shared.d/dns.conf

6. Monitoring and Verification

Check active DHCP leases granted to Wi-Fi clients:

cat /var/lib/NetworkManager/dnsmasq-wlan0.leases

Verify dnsmasq runtime process parameters:

ps aux | grep dnsmasq

Saturday, February 10, 2024

How to Capture Screenshots over SSH on Debian 12 Wayland Desktops

On legacy Debian 11 (Bullseye) and older X11 desktops, taking a screenshot of an active desktop session remotely over SSH was straightforward using scrot:

DISPLAY=:0.0 scrot -o screenshot.jpg

In Python:

import os
os.environ["DISPLAY"] = ":0.0"
os.system("scrot -o screenshot.jpg")

Wayland on Debian 12 (Bookworm)

On Debian 12 (and Raspberry Pi OS Bookworm with Wayfire or labwc), Wayland is the default compositor. Because Wayland enforces strict security isolation between graphical clients and display sockets, scrot will fail with the error:

failed to create display

To take screenshots under Wayland, use the native grim utility (pre-installed on Raspberry Pi OS). When calling grim over SSH from a non-interactive TTY, you must explicitly export both WAYLAND_DISPLAY and XDG_RUNTIME_DIR:

WAYLAND_DISPLAY=wayland-1 XDG_RUNTIME_DIR=/run/user/1000 grim screenshot.png

Python Automation Script

To capture screenshots programmatically in Python over SSH:

import os

pngfile = "/tmp/screenshot.png"
os.environ["WAYLAND_DISPLAY"] = "wayland-1"
os.environ["XDG_RUNTIME_DIR"] = "/run/user/1000"

os.system(f"grim {pngfile}")
Tip: If you are unsure of your socket names, run echo $WAYLAND_DISPLAY and echo $XDG_RUNTIME_DIR from a terminal inside the active desktop session, or check the socket files in /run/user/$(id -u)/.

Thursday, February 8, 2024

How to Set Default Route and Network Metrics on Debian 12 (Bookworm) Using NetworkManager

On Debian 12 (Bookworm) and Raspberry Pi OS Bookworm, dhcpcd has been deprecated and replaced by NetworkManager as the default network management stack. Consequently, /etc/dhcpcd.conf is no longer present.

When multiple network interfaces (such as Ethernet eth0 and Wi-Fi wlan0) are connected simultaneously, the Linux kernel determines the default gateway based on routing metrics. Lower metric values take precedence over higher values.

Rule: Lower route metric = higher routing priority. To prioritize an interface for default internet access, assign it a lower metric than competing interfaces.

1. Inspect Current Routing Metrics

Check the existing routing table and metric values:

ip route show
# or:
route -n

2. List NetworkManager Connection Profiles

Identify the exact connection name you wish to adjust:

nmcli connection show

3. Adjust the Route Metric

You can set the route metric directly using a single nmcli command:

# Set metric to 100 for higher priority (e.g. Ethernet)
nmcli connection modify "Wired connection 1" ipv4.route-metric 100

# Reactivate the connection to apply changes
nmcli connection up "Wired connection 1"

Alternatively, you can edit the connection interactively:

nmcli connection edit "Wired connection 1"
nmcli> set ipv4.route-metric 100
nmcli> save
nmcli> quit

Run ip route show again to verify that your preferred connection now holds the lowest metric on the default route.

Wednesday, July 5, 2023

How to Configure Eturnal TURN Server with TLS 1.3 and Static Credentials on Debian 12

Eturnal is a modern, lightweight STUN/TURN server written in Erlang that serves as an efficient alternative to Coturn with built-in TLS 1.3 support. While Eturnal natively uses time-limited ephemeral credentials (REST API authentication), many WebRTC clients require static usernames and passwords. Here is how to configure Eturnal on Debian 12 and generate static credentials using an HMAC-SHA1 Python helper.

Stack: Eturnal 1.12+ • Debian 12 Bookworm • TLS 1.3 • HMAC-SHA1 Password Generator

1. Installing Eturnal on Debian 12

# Add Eturnal package repository and install
curl -fsSL https://eturnal.net/gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/eturnal.gpg
echo "deb https://eturnal.net/debian bookworm main" | sudo tee /etc/apt/sources.list.d/eturnal.list
sudo apt-get update && sudo apt-get install eturnal -y

2. Generating Static TURN Credentials via Python

To produce valid credentials matching your configured shared secret (secret: "YOUR_SHARED_SECRET" in /etc/eturnal.yml):

import time
import hmac
import hashlib
import base64

SHARED_SECRET = "YOUR_SHARED_SECRET"
# Set expiration timestamp (e.g. 1 year in the future)
expiry = int(time.time()) + (365 * 24 * 3600)
username = f"{expiry}:user1"

# Compute HMAC-SHA1 hash
key = SHARED_SECRET.encode('utf-8')
msg = username.encode('utf-8')
password = base64.b64encode(hmac.new(key, msg, hashlib.sha1).digest()).decode('utf-8')

print(f"TURN Username: {username}")
print(f"TURN Password: {password}")

Monday, July 3, 2023

How to Compile and Install Coturn 4.6.2 with TLS 1.3 Support on Debian 12 (Bookworm)

Coturn is the standard open-source STUN/TURN server enabling WebRTC audio/video connections across symmetric NATs and firewalls. Full support for modern TLS 1.3 encrypted TURN connections (TURNS) was added in Coturn 4.6.2. Because Debian 12 (Bookworm) originally packaged Coturn 4.6.1, compiling version 4.6.2 from source with OpenSSL 3.x is necessary for enterprise TLS 1.3 compliance.

Features: TURNS over TLS 1.3 • WebRTC relay performance • Debian 12 Bookworm

Compilation & Installation Commands

# 1. Install build tools and OpenSSL 3 development libraries
sudo apt-get update
sudo apt-get install -y pkg-config build-essential libssl-dev libevent-dev git

# 2. Download Coturn 4.6.2 release
cd /usr/src
git clone https://github.com/coturn/coturn.git
cd coturn
git checkout 4.6.2

# 3. Configure and compile with OpenSSL
./configure --prefix=/usr/local
make -j$(nproc)
sudo make install

# Verify binary and TLS support
turnserver -v

Thursday, February 10, 2022

How to Install Asterisk 18 and FreePBX 16 on Raspberry Pi OS Bullseye (64-bit & 32-bit)

Deploying Asterisk 18 LTS alongside the modern FreePBX 16 administrative interface on Raspberry Pi OS (Debian 11 Bullseye) enables a carrier-grade VoIP telephony platform on energy-efficient ARM hardware. This guide provides the complete setup for both 64-bit (aarch64) and 32-bit (armhf) architectures.

OS: Raspberry Pi OS Bullseye • Components: Asterisk 18.x, FreePBX 16, Node.js 14, MariaDB 10.5, Apache 2.4

1. Installing System Packages & PHP 7.4

sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install -y build-essential libssl-dev libncurses5-dev libnewt-dev   libxml2-dev libsqlite3-dev uuid-dev mariadb-server mariadb-client   libjansson-dev libedit-dev sox libsox-fmt-all git curl subversion

# Install PHP 7.4 modules required by FreePBX 16
sudo apt-get install -y apache2 php php-cli php-mysql php-pear php-gd php-mbstring   php-intl php-xml php-curl php-zip

2. Building Asterisk 18 LTS

cd /usr/src
sudo wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz
sudo tar -zxf asterisk-18-current.tar.gz
cd asterisk-18.*

sudo contrib/scripts/get_mp3_source.sh
sudo contrib/scripts/install_prereq install

sudo ./configure --with-pjproject-bundled --with-jansson-bundled
sudo make menuselect.makeopts
sudo menuselect/menuselect --enable format_mp3 menuselect.makeopts
sudo make -j$(nproc)
sudo make install
sudo make config
sudo ldconfig

3. Installing FreePBX 16

cd /usr/src
sudo wget http://mirror.freepbx.org/modules/packages/freepbx/freepbx-16.0-latest.tgz
sudo tar -zxf freepbx-16.0-latest.tgz
cd freepbx
sudo ./install -n

Friday, June 4, 2021

How to Perform Path MTU Discovery on Linux and macOS (Ping and Tracepath)

Mismatched Maximum Transmission Unit (MTU) sizes across VPNs, tunnels (WireGuard, IPsec, PPPoE), and intermediate network links frequently cause silent TCP connection hangs and packet fragmentation issues. Testing your path's effective MTU using the "Don't Fragment" (DF) bit pinpoints the exact link threshold.

Formula: Total MTU = ICMP Payload Size + 28 bytes (20 bytes IP header + 8 bytes ICMP header).

1. Path MTU Discovery on Linux

Use ping with -M do (enforce Don't Fragment) or tracepath:

# Ping with 1472 bytes payload (1472 + 28 = 1500 MTU)
ping -M do -s 1472 8.8.8.8

# If it reports "Frag needed and DF set", step down until packets pass:
ping -M do -s 1392 8.8.8.8 # (1392 + 28 = 1420 MTU, standard for WireGuard)

# Automatic MTU trace across intermediate hops:
tracepath 8.8.8.8

2. Path MTU Discovery on macOS

# On macOS, use -D to set DF bit:
ping -D -s 1472 8.8.8.8

Tuesday, May 18, 2021

How to Proxy Secure WebSockets (WSS) in a Subfolder with Apache mod_proxy_wstunnel

Routing secure WebSocket connections (wss://) originating from a specific URL subfolder (such as /websocket1) to a local backend daemon (running on an internal TCP port like 2085) requires configuring Apache's mod_proxy_wstunnel.

Prerequisites: Enable Apache modules: proxy, proxy_http, proxy_wstunnel, and rewrite.

Apache VirtualHost Configuration

# Enable proxy tunneling for WebSockets
RewriteEngine On

# Detect WebSocket upgrade request headers for /websocket1
RewriteCond %{REQUEST_URI} ^/websocket1 [NC]
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/websocket1/(.*)$ ws://127.0.0.1:2085/$1 [P,L]

# Normal HTTP proxy fallback (if needed):
ProxyPass /websocket1 http://127.0.0.1:2085/
ProxyPassReverse /websocket1 http://127.0.0.1:2085/

Reload Apache to apply:

sudo systemctl reload apache2

Tuesday, March 2, 2021

How to Install Asterisk 18 and FreePBX 15 on Ubuntu (Raspberry Pi 4)

Running a full-featured IP-PBX telephony server on a Raspberry Pi 4 provides small offices and lab environments with an enterprise telephone system at negligible power consumption. This comprehensive guide covers compiling Asterisk 18 LTS with DAHDI/libpri and configuring the FreePBX 15 web administration portal on Ubuntu Server (ARM64).

Hardware: Raspberry Pi 4 (4GB / 8GB recommended) • OS: Ubuntu 20.04 LTS aarch64 • Stack: Asterisk 18 LTS, FreePBX 15, MariaDB, Node.js

1. Installing Build Prerequisites and MariaDB

sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install -y build-essential linux-headers-generic libssl-dev libncurses5-dev   libnewt-dev libxml2-dev linux-headers-$(uname -r) libsqlite3-dev uuid-dev   mariadb-server mariadb-client libjansson-dev libedit-dev sox libsox-fmt-all

# Configure database
sudo mysql_secure_installation

2. Compiling Asterisk 18 LTS

cd /usr/src
sudo wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz
sudo tar -zxf asterisk-18-current.tar.gz
cd asterisk-18.*

sudo contrib/scripts/get_mp3_source.sh
sudo contrib/scripts/install_prereq install

sudo ./configure --with-pjproject-bundled --with-jansson-bundled
sudo make menuselect.makeopts
sudo menuselect/menuselect --enable format_mp3 menuselect.makeopts
sudo make -j$(nproc)
sudo make install
sudo make samples
sudo make config
sudo ldconfig

3. Installing FreePBX 15

Install Node.js, Apache, PHP modules, and run the FreePBX install script pointing to Asterisk:

cd /usr/src
sudo wget http://mirror.freepbx.org/modules/packages/freepbx/freepbx-15.0-latest.tgz
sudo tar -zxf freepbx-15.0-latest.tgz
cd freepbx
sudo ./install -n

Tuesday, December 22, 2020

[Solved] Proxmox 6.3 DHCP Error on Huawei RH2288 V3 Servers: No Working Lease in Persistent Database

When booting the Proxmox VE 6.x installer on enterprise Huawei FusionServer RH2288 V3 rack servers, the graphical installation aborts and drops into a debug shell with the error: No working lease in persistent database.

Root Cause: Kernel framebuffer conflict with Huawei integrated server graphics (BMC) and IOMMU initialization.

Step-by-Step Resolution

  1. At the Proxmox GRUB boot menu, press e to edit the boot entry.
  2. Locate the linux kernel line and append the following kernel parameters:
    modprobe.blacklist=nouveau amd_iommu=on video=efifb:off
  3. Press Ctrl+X or F10 to boot.

Assigning Static IP in Debug Shell (If DHCP is Unavailable)

If your datacenter environment does not offer DHCP on the management network, configure network parameters directly in the debug prompt:

ip addr add 192.168.1.50/24 dev enp2s0f0
ip route add default via 192.168.1.1 dev enp2s0f0
echo "nameserver 1.1.1.1" > /etc/resolv.conf

How to Install Matching Linux Kernel Headers on Sangoma OS (FreePBX Distro)

When running the FreePBX Sangoma OS distro inside a VirtualBox virtual machine, installing VirtualBox Guest Additions fails with "Kernel headers not found for target kernel" even after installing kernel-devel and kernel-headers via yum.

Root Cause: In FreePBX Sangoma OS installations, the build directory symlink /lib/modules/$(uname -r)/build is missing from the active kernel directory.

The 1-Line Fix

Create the missing build symlink pointing to the kernel source directory:

# 1. Install development packages
yum install dkms gcc kernel-devel kernel-headers -y

# 2. Fix the missing module build symlink
ln -s /usr/src/kernels/$(uname -r) /lib/modules/$(uname -r)/build

# 3. Mount and build Guest Additions
mount /dev/cdrom /media/cdrom
cd /media/cdrom
./VBoxLinuxAdditions.run

The kernel module compilation will complete cleanly, enabling dynamic display resizing and shared folders.

Monday, November 23, 2020

How to Install and Configure Munin Monitoring with Nginx and CGI on CentOS 8

Setting up Munin on CentOS 8 via EPEL 8 provides turnkey server performance graphs. This guide walks through configuring systemd timer units, fastcgi spawners for dynamic graph generation, and integrating the dashboard into an Nginx virtual host.

Packages: munin • munin-node • munin-cgi • spawn-fcgi

1. Installing Packages from EPEL 8

dnf install epel-release -y
dnf install munin munin-cgi munin-node spawn-fcgi nginx -y

2. Enabling Node and Systemd Services

systemctl enable --now munin-node
systemctl enable --now munin-cgi-graph.socket
systemctl enable --now munin-cgi-html.socket

3. Nginx Server Block (/etc/nginx/conf.d/munin.conf)

server {
    listen 80;
    server_name munin.example.com;

    location / {
        root /var/www/html/munin;
        index index.html;
    }

    location ^~ /munin-cgi/munin-cgi-graph/ {
        fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*);
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_pass unix:/run/munin/fcgi-graph.sock;
        include fastcgi_params;
    }
}

Tuesday, September 22, 2020

How to Deploy BigBlueButton Web Conferencing on CentOS 8 with Docker

BigBlueButton (BBB) is the leading open-source virtual classroom and web conferencing system. While upstream BBB exclusively provides automated installer scripts for Ubuntu LTS, organizations standardized on Enterprise Linux (CentOS 8 / RHEL 8) can deploy BigBlueButton components cleanly using Docker containers.

Stack: CentOS 8 • Docker CE • BigBlueButton Docker Compose • Nginx TLS Reverse Proxy

1. Installing Docker CE on CentOS 8

dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install docker-ce docker-ce-cli containerd.io -y
systemctl enable --now docker

2. Deploying BigBlueButton via Docker Compose

git clone https://github.com/bigbluebutton/docker.git bbb-docker
cd bbb-docker
cp .env.example .env

# Configure your FQDN and Let's Encrypt email in .env
./scripts/generate-api-secrets.sh
docker-compose up -d

Thursday, July 9, 2020

How to Install and Configure Icecast 2 Streaming Audio Server on CentOS 8

Icecast is a high-performance, open-source streaming media audio server capable of broadcasting MP3, Ogg Vorbis, and Opus audio streams. Because prebuilt Icecast packages were initially omitted from CentOS 8 and EPEL 8 repositories, compiling from source with Vorbis and Theora audio support is required.

Environment: CentOS 8 / RHEL 8 • Icecast 2.4.x • Ogg / Vorbis / Theora Codecs

1. Install Build Tools and Codec Dependencies

yum groupinstall "Development Tools" -y
yum install curl-devel libtheora-devel libvorbis-devel libxslt-devel speex-devel libshout-devel -y

2. Download and Build Icecast

cd /usr/src
wget http://downloads.xiph.org/releases/icecast/icecast-2.4.4.tar.gz
tar -zxf icecast-2.4.4.tar.gz
cd icecast-2.4.4

./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
make && make install

3. Create Service User and Start Daemon

useradd -r -s /sbin/nologin icecast
chown -R icecast:icecast /var/log/icecast

# Launch Icecast as a background daemon
icecast -b -c /etc/icecast.xml

Wednesday, July 8, 2020

How to Rebuild Apache httpd to Change suexec AP_DOC_ROOT from /var/www to /home (CentOS & RHEL)

Standard RPM packages of Apache httpd in CentOS and RHEL compile suexec with a hardcoded document root of /var/www (--with-suexec-docroot=/var/www). However, web control panels like Virtualmin host customer accounts under /home. When suexec executes a user script under /home, it aborts with "command not in docroot". Here is how to rebuild the official upstream httpd SRPM with AP_DOC_ROOT set to /home.

Compilation Flag: --with-suexec-docroot=/home

Rebuilding the RPM

# 1. Install build tools and dependencies
yum install rpm-build redhat-rpm-config gcc make -y
yum-builddep httpd -y

# 2. Download and unpack httpd SRPM
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
cd ~/rpmbuild/SRPMS
yumdownloader --source httpd
rpm -ivh httpd-*.src.rpm

# 3. Edit SPECS/httpd.spec and modify suexec docroot
cd ~/rpmbuild/SPECS
sed -i 's|--with-suexec-docroot=/var/www|--with-suexec-docroot=/home|g' httpd.spec

# 4. Rebuild binary RPM
rpmbuild -bb httpd.spec

# 5. Install the custom suexec binary
rpm -Uvh --force ~/rpmbuild/RPMS/x86_64/httpd-*.rpm

Confirm the new docroot:

suexec -V | grep AP_DOC_ROOT

Monday, June 22, 2020

[Solved] Fixing Apache suexec and mod_fcgid: Error Reading Data from FastCGI Server

When running PHP applications under Apache using mod_fcgid combined with suexec privilege separation, web requests may suddenly abort with HTTP 500 Internal Server Errors and the following message in Apache error logs:

Error Message: End of script output before headers: php.fcgi • mod_fcgid: error reading data from FastCGI server

Root Cause

suexec enforces strict security checks on the FastCGI wrapper script and user directory:

  1. The wrapper script and parent directories must be owned exclusively by the virtual server user and group—not root or apache.
  2. File permissions cannot be group-writeable (chmod 755 is required, 775 or 777 causes instant suexec rejection).
  3. The target script must reside strictly inside the compiled suexec document root (e.g. /home/user/public_html).

Resolution Steps

Inspect /var/log/httpd/suexec.log to reveal the exact permission violation, and enforce correct ownership:

# Fix permissions and ownership
chown -R user:user /home/user/fcgi-bin /home/user/public_html
chmod 755 /home/user/fcgi-bin/php.fcgi
chmod 755 /home/user/public_html

Wednesday, June 3, 2020

How to Install Virtualmin with Multiple PHP and MySQL Versions on CentOS 8

Deploying a production web hosting stack on CentOS 8 with Virtualmin requires modern multi-PHP support (allowing legacy applications to run PHP 5.6 or 7.2 while modern apps run PHP 7.4 or 8.0) and reliable database server management via Remi repositories.

Stack: CentOS 8 • Virtualmin 6.x • Remi Software Collections (SCL) • MySQL 8.0 • Multi-PHP

1. Fix Perl UTF-8 Locale Warnings

cat << 'EOF' > /etc/environment
LANGUAGE=en_US.utf8
LC_ALL=en_US.utf-8
LANG=en_US.utf8
LC_TYPE=en_US.utf8
EOF

2. Enable EPEL and Remi Repositories

dnf install epel-release -y
dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm -y
dnf module reset php -y
dnf module enable php:remi-7.4 -y

3. Installing Parallel PHP Versions

dnf install php56-php-fpm php72-php-fpm php74-php-fpm php80-php-fpm -y

4. Install Virtualmin

wget http://software.virtualmin.com/gpl/scripts/install.sh
sh install.sh

Friday, May 29, 2020

How to Forward Public IP Traffic to a WireGuard Client Behind NAT While Preserving Client IPs

When exposing a local server located behind a residential CGNAT (Carrier-Grade NAT) to the public internet using a cloud VPS as a front-end gateway, standard DNAT/MASQUERADE setups rewrite incoming packets with the WireGuard gateway's internal IP. This destroys client IP visibility, making rate-limiting, geo-blocking, and security auditing impossible. Here is how to configure policy-based routing and iptables PREROUTING to preserve the original client IP all the way to your backend application.

Architecture: Public Client (IP: X) → Cloud VPS (Public IP: Y) → WireGuard Tunnel → Home Server Behind NAT (Sees Real Client IP: X)

1. Cloud VPS Gateway Configuration

On the cloud VPS, forward external ports directly through the WireGuard interface (wg0) without applying SNAT/MASQUERADE to the incoming packets:

# Enable IP forwarding
sysctl -w net.ipv4.ip_forward=1

# Forward HTTP port 80 to WireGuard client (10.200.200.2)
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.200.200.2:80
iptables -A FORWARD -p tcp -d 10.200.200.2 --dport 80 -j ACCEPT

2. Home Server Policy Routing (The Secret to Preserving IPs)

Because the incoming packet preserves the public client IP, the home server's reply would normally route through its default residential gateway rather than returning via the WireGuard tunnel (causing asymmetric routing drop). Resolve this using Linux policy routing:

# 1. Create a custom routing table
echo "200 custom_vpn" >> /etc/iproute2/rt_tables

# 2. Route responses to traffic arriving on wg0 back through wg0
ip rule add from 10.200.200.2 table custom_vpn
ip route add default via 10.200.200.1 dev wg0 table custom_vpn

Now your backend web application logs the true public client IP address for every visitor!

How Google Antigravity Solved the Mysterious NVIDIA Sleep Reboot on My Dell Inspiron 7567 (Ubuntu Linux)

If you run modern Ubuntu or Linux on a Dell Inspiron 15 Gaming (7567) or a similar 7th-gen Intel laptop paired with an NVIDIA GeForce GTX ...