Discover, Review, Enjoy — Byte by Byte

Tag: linux

Emby – Convert SSL Certificate for Use in Emby (OpenSSL Guide)

This guide explains how to convert a certificate from a provider (such as OVH or Namecheap) into a .pfx file for use in Emby, and how to verify that your private key, CSR, and certificate all match correctly.

This is useful when:

  • You purchased an SSL certificate from a provider
  • You generated your own CSR
  • Emby requires a .pfx certificate file
  • You want to verify everything matches before importing

1. Convert Certificate to PFX Format

Emby requires a .pfx (PKCS#12) certificate file.

Run the following command:

openssl pkcs12 -export -out mgn.pfx \
-inkey mgn_ovh.key \
-in mgn_ovh.crt \
-certfile mgn_ovh.ca-bundle

File Explanation

  • mgn_ovh.key → Your private key
  • mgn_ovh.crt → Certificate issued by provider
  • mgn_ovh.ca-bundle → Intermediate certificate bundle
  • mgn.pfx → Output file used in Emby

You will be prompted to create a password.
This password will be required when importing into Emby.


2. Troubleshooting: Verify the Key, CSR, and Certificate Match

If Emby refuses the certificate, or conversion fails, ensure that:

  • The private key matches the CSR
  • The certificate was issued for the correct key
  • The CA bundle matches the certificate

All modulus hashes must match.


Confirm the Private Key

openssl rsa -noout -modulus -in mgn_ovh.key | openssl md5

Example output:

MD5(stdin)= xxxxxxxxxxxxxxxxx

Check the Original CSR

openssl req -noout -modulus -in request.csr | openssl md5

The MD5 hash must match the private key output above.


Check the Provider Certificate

openssl x509 -noout -modulus -in mgn_ovh.crt | openssl md5

This must also match the previous two outputs.

If all three hashes match → your key, CSR, and certificate are correctly paired.


3. Verify the Certificate Chain

Ensure the certificate is properly signed by the CA:

openssl verify -CAfile mgn_ovh.ca-bundle mgn_ovh.crt

Expected output:

mgn_ovh.crt: OK

If it returns OK, the certificate chain is valid.


4. Import Into Emby

In Emby:

Dashboard → Network → HTTPS → Certificate Path

Upload the .pfx file and enter the password created during export.

Restart Emby after importing.


Common Issues

  • Key does not match certificate → wrong private key used
  • CSR regenerated after certificate purchase
  • Incorrect CA bundle file
  • Missing intermediate certificates

Always confirm modulus values match before attempting conversion.


Tested On

  • Debian-based systems
  • OpenSSL 1.1 / 3.x
  • Emby Server (Linux)
  • Certificates from OVH / Namecheap

Linux – Cloudflare Dynamic DNS Update Script (Bash)

This guide shows how to create a simple Bash script that automatically updates a Cloudflare DNS A record when your public IP address changes.

This is ideal for:

  • Home lab environments
  • Self-hosted services
  • Proxmox / VPN endpoints
  • ISP connections with dynamic IP addresses

Instead of using a third-party Dynamic DNS provider, this script updates Cloudflare directly via its API.


How It Works

The script:

  1. Fetches your current public IP address
  2. Queries Cloudflare for the existing DNS record
  3. Compares the two
  4. Updates the DNS record only if the IP has changed
  5. Logs all activity with timestamps

This prevents unnecessary API calls and keeps logs clean.


Requirements

Install required tools:

apt install -y curl jq

You will also need:

  • A Cloudflare account
  • Your Zone ID
  • Your DNS Record ID
  • An API key or token

The Script

Create the file:

nano /root/cloudflare-ddns.sh

Paste the following:

#!/bin/bash# Variables
ZONE_ID="YOUR_ZONE_ID"
RECORD_ID="YOUR_RECORD_ID"
AUTH_EMAIL="your@email.com"
AUTH_KEY="YOUR_GLOBAL_API_KEY"
DOMAIN="yourdomain.com"
LOG_FILE="/root/ddns.log"# Fetch the current public IP
CURRENT_IP=$(curl -s https://api.ipify.org)# Get the existing IP from Cloudflare
EXISTING_IP=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
-H "Content-Type: application/json" \
-H "X-Auth-Email: $AUTH_EMAIL" \
-H "X-Auth-Key: $AUTH_KEY" | jq -r '.result.content')# Timestamp
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")# Compare and update if needed
if [ "$CURRENT_IP" != "$EXISTING_IP" ]; then
echo "$TIMESTAMP - IP changed from $EXISTING_IP to $CURRENT_IP. Updating record..." | tee -a "$LOG_FILE" RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
-H "Content-Type: application/json" \
-H "X-Auth-Email: $AUTH_EMAIL" \
-H "X-Auth-Key: $AUTH_KEY" \
--data '{"type":"A","name":"'"$DOMAIN"'","content":"'"$CURRENT_IP"'","ttl":1,"proxied":false}') if echo "$RESPONSE" | grep -q '"success":true'; then
echo "$TIMESTAMP - DNS record updated successfully." | tee -a "$LOG_FILE"
else
echo "$TIMESTAMP - Update failed. Response: $RESPONSE" | tee -a "$LOG_FILE"
fi
else
echo "$TIMESTAMP - IP unchanged ($CURRENT_IP). No update required." | tee -a "$LOG_FILE"
fi

Save and make executable:

chmod +x /root/cloudflare-ddns.sh

Finding Your Cloudflare IDs

Zone ID

Cloudflare Dashboard → Domain → Overview → Right Sidebar → Zone ID

Record ID

Run:

curl -X GET "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/dns_records" \
-H "X-Auth-Email: your@email.com" \
-H "X-Auth-Key: YOUR_GLOBAL_API_KEY" \
-H "Content-Type: application/json"

Find the record for your domain and copy the "id" value.


Run the Script Manually

/root/cloudflare-ddns.sh

Check the log:

cat /root/ddns.log

Automate with Cron

Edit root crontab:

crontab -e

Run every 5 minutes:

*/5 * * * * /root/cloudflare-ddns.sh

Security Recommendation (Important)

Instead of using your Global API Key, it is strongly recommended to create a Cloudflare API Token with limited permissions:

Permissions required:

  • Zone → DNS → Edit
  • Zone → Zone → Read

This reduces risk if the script is ever exposed.


Optional Improvements

You could enhance this script by:

  • Sending a Pushover notification on IP change
  • Logging to syslog instead of a flat file
  • Supporting IPv6 (AAAA record)
  • Adding error handling if Cloudflare API is unreachable

Use Cases

This script is useful for:

  • Hosting services behind dynamic residential IP
  • WireGuard endpoints
  • Self-hosted dashboards
  • Proxmox remote access
  • Home VPN servers

Tested On

  • Debian 12
  • Proxmox VE 8
  • Cloudflare DNS (A records)

Linux – Internet Checker Script V1.0

# Linux - Internet Checker Script V1.0
# Function to check network interface
check_interface()
    local INTERFACE=$(ip route | grep default | awk '{print $5}')
    if [[ -n "$INTERFACE" ]]; then
        echo -e "\e[32mNetwork interface ($INTERFACE) is up.\e[0m"
    else
        echo -e "\e[31mNo network interface found or it is down!\e[0m"
        return 1
    fi
}

# Function to check default gateway
check_gateway() {
    local GATEWAY=$(ip route | grep default | awk '{print $3}')
    if ping -c 2 "$GATEWAY" &> /dev/null; then
        echo -e "\e[32mSuccessfully connected to gateway ($GATEWAY).\e[0m"
    else
        echo -e "\e[31mFailed to connect to the gateway ($GATEWAY).\e[0m"
        return 1
    fi
}

# Function to check DNS resolution
check_dns() {
    if nslookup google.com &> /dev/null; then
        echo -e "\e[32mDNS resolution is working.\e[0m"
    else
        echo -e "\e[31mDNS resolution failed!\e[0m"
        return 1
    fi
}

# Function to check connectivity to external servers via ping
check_ping() {
    local SERVERS=("8.8.8.8" "1.1.1.1" "google.com")
    for server in "${SERVERS[@]}"; do
        if ping -c 2 "$server" &> /dev/null; then
            echo -e "\e[32mSuccessfully pinged $server.\e[0m"
        else
            echo -e "\e[31mFailed to ping $server.\e[0m"
            return 1
        fi
    done
}

# Function to check if specific ports are open
check_ports() {
    local PORTS=(80 443)
    for port in "${PORTS[@]}"; do
        if nc -zv google.com $port &> /dev/null; then
            echo -e "\e[32mPort $port is accessible.\e[0m"
        else
            echo -e "\e[31mPort $port is not accessible!\e[0m"
            return 1
        fi
    done
}

# Function to check traceroute to Google DNS
check_traceroute() {
    if command -v traceroute &> /dev/null; then
        echo -e "\e[32mTraceroute to Google DNS (8.8.8.8) is possible:\e[0m"
        traceroute -m 5 8.8.8.8
    else
        echo -e "\e[31mTraceroute command not available on this system.\e[0m"
    fi
}

# Function to check HTTP request and handle redirects
check_http_request() {
    if curl -s -o /dev/null -w "%{http_code}" https://google.com | grep -q "200\|301\|302"; then
        echo -e "\e[32mHTTP request successful or redirected.\e[0m"
    else
        echo -e "\e[31mHTTP request failed!\e[0m"
        return 1
    fi
}

# Run all checks
echo "Starting detailed internet connection check..."
check_interface
check_gateway
check_dns
check_ping
check_ports
check_traceroute
check_http_request

echo "Internet connection check complete."

Linux – Fail2Ban Auto Installation Script V1.0

run the following command

nano /fail2ban.sh

Copy and paste the script below.

#!/bin/bash

# Fail2Ban auto-install and setup script (no sudo)

# Step 1: Update package list and install Fail2Ban and rsyslog
apt update && apt install fail2ban rsyslog -y

# Step 2: Ensure rsyslog is running and enabled on boot
systemctl start rsyslog
systemctl enable rsyslog

# Step 3: Configure rsyslog to log auth messages
if ! grep -q "^auth,authpriv.*" /etc/rsyslog.conf; then
    echo "auth,authpriv.*   /var/log/auth.log" >> /etc/rsyslog.conf
    echo "Configured rsyslog to log authentication messages."
fi

# Restart rsyslog to apply changes
systemctl restart rsyslog

# Step 4: Copy the default jail.conf to jail.local to prevent overwriting in updates
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Step 5: Configure the SSH jail and other settings in jail.local
if ! grep -q "^\[DEFAULT\]" /etc/fail2ban/jail.local; then
    echo -e "\n[DEFAULT]\n" >> /etc/fail2ban/jail.local
fi

# Check and set bantime if it doesn't exist
if ! grep -q "^bantime" /etc/fail2ban/jail.local; then
    echo "bantime = 24h" >> /etc/fail2ban/jail.local
else
    sed -i 's/^bantime.*/bantime = 24h/' /etc/fail2ban/jail.local
fi

# Check and set findtime if it doesn't exist
if ! grep -q "^findtime" /etc/fail2ban/jail.local; then
    echo "findtime = 10m" >> /etc/fail2ban/jail.local
else
    sed -i 's/^findtime.*/findtime = 10m/' /etc/fail2ban/jail.local
fi

# Check and set maxretry if it doesn't exist
if ! grep -q "^maxretry" /etc/fail2ban/jail.local; then
    echo "maxretry = 5" >> /etc/fail2ban/jail.local
else
    sed -i 's/^maxretry.*/maxretry = 5/' /etc/fail2ban/jail.local
fi

# Configure the SSH jail
if ! grep -q "^\[sshd\]" /etc/fail2ban/jail.local; then
    echo -e "\n[sshd]\nenabled = true\nlogpath = /var/log/auth.log\n" >> /etc/fail2ban/jail.local
else
    sed -i 's/^enabled.*/enabled = true/' /etc/fail2ban/jail.local
    sed -i 's|^logpath.*|logpath = /var/log/auth.log|' /etc/fail2ban/jail.local
fi

# Step 6: Ensure SSH logging is enabled in /etc/ssh/sshd_config
# Handle LogLevel
if grep -q "^#LogLevel" /etc/ssh/sshd_config; then
    sed -i 's/^#LogLevel.*/LogLevel INFO/' /etc/ssh/sshd_config
elif grep -q "^LogLevel" /etc/ssh/sshd_config; then
    sed -i 's/^LogLevel.*/LogLevel INFO/' /etc/ssh/sshd_config
else
    echo "LogLevel INFO" >> /etc/ssh/sshd_config
fi

# Handle SyslogFacility
if grep -q "^#SyslogFacility" /etc/ssh/sshd_config; then
    sed -i 's/^#SyslogFacility.*/SyslogFacility AUTH/' /etc/ssh/sshd_config
elif grep -q "^SyslogFacility" /etc/ssh/sshd_config; then
    sed -i 's/^SyslogFacility.*/SyslogFacility AUTH/' /etc/ssh/sshd_config
else
    echo "SyslogFacility AUTH" >> /etc/ssh/sshd_config
fi

# Step 7: Restart SSH and Fail2Ban services to apply the changes
systemctl restart sshd
systemctl restart fail2ban

# Step 8: Enable Fail2Ban on boot
systemctl enable fail2ban

echo "Fail2Ban and rsyslog have been installed and configured successfully."

CTRL + O Then CTRL + X to Save and Close the file.

Now run the following command to sent the scripts permissions

chmod 755 /fail2ban.sh

Now we need to run the script to automatically install and setup fail2ban

./fail2ban.sh

© 2026 bytesmith17

Theme by Anders NorénUp ↑