<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>soban</title>
	<atom:link href="https://soban.pl/feed/" rel="self" type="application/rss+xml" />
	<link>https://soban.pl/</link>
	<description>IT, Linux, Servers, Security</description>
	<lastBuildDate>Mon, 02 Mar 2026 14:04:06 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>CrowdSec – Intelligent Linux Server Protection Against Botnets, Brute-Force Attacks and Internet Scanning</title>
		<link>https://soban.pl/crowdsec-linux-server-protection/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Fri, 27 Feb 2026 10:46:55 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=793</guid>

					<description><![CDATA[<p>If you run a Linux server with Nginx, SSH, or WordPress, you probably already know Fail2Ban. It is a solid tool, but it works locally — it blocks only the IP addresses that attacked your server. CrowdSec works in a completely different way. It is a protection system based on shared IP reputation. If thousands [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/crowdsec-linux-server-protection/">CrowdSec – Intelligent Linux Server Protection Against Botnets, Brute-Force Attacks and Internet Scanning</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><img fetchpriority="high" decoding="async" width="1024" height="685" src="https://soban.pl/wp-content/uploads/2026/02/image-4-1024x685.png" alt="" class="wp-image-789" style="aspect-ratio:1.4949112952561037;width:580px;height:auto" srcset="https://soban.pl/wp-content/uploads/2026/02/image-4-1024x685.png 1024w, https://soban.pl/wp-content/uploads/2026/02/image-4-300x201.png 300w, https://soban.pl/wp-content/uploads/2026/02/image-4-768x514.png 768w, https://soban.pl/wp-content/uploads/2026/02/image-4.png 1174w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>If you run a Linux server with Nginx, SSH, or WordPress, you probably already know <strong>Fail2Ban</strong>. It is a solid tool, but it works locally — it blocks only the IP addresses that attacked <em>your</em> server.</p>



<p><strong>CrowdSec</strong> works in a completely different way. It is a protection system based on shared IP reputation. If thousands of servers worldwide detect a malicious IP address, your server can block it <strong>before an attack even happens</strong>.</p>



<h2 class="wp-block-heading">How Does CrowdSec Work?</h2>



<ul class="wp-block-list">
<li>analyzes system logs (nginx, ssh, wordpress)</li>



<li>detects suspicious behavior</li>



<li>shares attacker IP intelligence with other servers</li>



<li>blocks traffic at the firewall level</li>
</ul>



<p>The result? Most bots and internet scanners never even reach your Nginx server.</p>



<h2 class="wp-block-heading">Installing CrowdSec on Debian / Ubuntu</h2>



<p>CrowdSec installation is very simple and available directly from Debian repositories.</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">apt update
apt install crowdsec</pre></div>



<p>During installation, CrowdSec automatically:</p>



<ul class="wp-block-list">
<li>creates a local API (LAPI)</li>



<li>registers the server in CrowdSec Central API</li>



<li>downloads default security scenarios</li>
</ul>



<h2 class="wp-block-heading">Installing Firewall Bouncer</h2>



<p>CrowdSec detects threats, but it requires an enforcement component — called a <strong>bouncer</strong> — which blocks traffic at the firewall level.</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">apt install crowdsec-firewall-bouncer</pre></div>



<p>By default, the bouncer uses <strong>nftables</strong> and automatically adds blocking rules for malicious IP addresses.</p>



<h2 class="wp-block-heading">Installing Security Collections</h2>



<p>Collections include log parsers and attack detection scenarios.</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cscli collections install crowdsecurity/nginx
cscli collections install crowdsecurity/wordpress
cscli collections install crowdsecurity/base-http-scenarios
cscli collections install crowdsecurity/sshd</pre></div>



<p>Reload configuration after installation:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">systemctl reload crowdsec</pre></div>



<h2 class="wp-block-heading">Configuring Nginx Logs</h2>



<p>To allow CrowdSec to analyze HTTP traffic, you must specify Nginx log files.</p>



<p>Edit the file:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">nano /etc/crowdsec/acquis.yaml</pre></div>



<p>Add the following configuration:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">filenames:
  - /var/log/nginx/access*.log
  - /var/log/nginx/error*.log
labels:
  type: nginx</pre></div>



<p>Then restart the service:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">systemctl restart crowdsec</pre></div>



<h2 class="wp-block-heading">Verifying CrowdSec Operation</h2>



<p>Service status:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">systemctl status crowdsec</pre></div>



<p>Active bans list:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cscli decisions list</pre></div>



<p>Operational metrics:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cscli metrics</pre></div>



<h2 class="wp-block-heading">Final Result</h2>



<p>After proper CrowdSec installation:</p>



<ul class="wp-block-list">
<li>the server automatically blocks known botnets</li>



<li>WordPress attacks and SSH brute-force attempts are stopped at the firewall</li>



<li>Nginx handles significantly less malicious traffic</li>



<li>server CPU and IO usage are noticeably reduced</li>
</ul>



<p>CrowdSec can be considered an <strong>evolution of Fail2Ban</strong> — a system that not only reacts locally but also benefits from global threat intelligence.</p>
<p>Artykuł <a href="https://soban.pl/crowdsec-linux-server-protection/">CrowdSec – Intelligent Linux Server Protection Against Botnets, Brute-Force Attacks and Internet Scanning</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Fail2Ban: How to Detect Repeat Offenders and Ban Them for a Week (Recidive)</title>
		<link>https://soban.pl/fail2ban-recidive-nginx-wordpress-setup/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Thu, 26 Feb 2026 12:09:28 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=752</guid>

					<description><![CDATA[<p>If you use Fail2Ban with Nginx and WordPress, sooner or later you’ll notice one thing: the same IP addresses keep coming back. They get banned for a few minutes or an hour, disappear… and shortly after try again /.env, /wp-login.php, /phpmyadmin, or other common attack paths. The solution is not to aggressively tighten the filters. [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/fail2ban-recidive-nginx-wordpress-setup/">Fail2Ban: How to Detect Repeat Offenders and Ban Them for a Week (Recidive)</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><img decoding="async" width="1024" height="688" src="https://soban.pl/wp-content/uploads/2026/02/image-3-1024x688.png" alt="" class="wp-image-749" style="width:566px;height:auto" srcset="https://soban.pl/wp-content/uploads/2026/02/image-3-1024x688.png 1024w, https://soban.pl/wp-content/uploads/2026/02/image-3-300x201.png 300w, https://soban.pl/wp-content/uploads/2026/02/image-3-768x516.png 768w, https://soban.pl/wp-content/uploads/2026/02/image-3.png 1157w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p><br>If you use Fail2Ban with Nginx and WordPress, sooner or later you’ll notice one thing: the same IP addresses keep coming back. They get banned for a few minutes or an hour, disappear… and shortly after try again <code>/.env</code>, <code>/wp-login.php</code>, <code>/phpmyadmin</code>, or other common attack paths.</p>



<p>The solution is not to aggressively tighten the filters. The solution is <strong>recidive</strong> — a second layer of protection in Fail2Ban that analyzes the ban history and blocks repeat offenders long-term.</p>



<h2 class="wp-block-heading">Reference to the previous configuration</h2>



<p>If you don’t yet have a basic Fail2Ban configuration for Nginx and WordPress, I described it here:</p>



<p><a href="https://soban.pl/fail2ban-nginx-wordpress-setup-2/" target="_blank" rel="noopener">Fail2Ban + Nginx + WordPress – basic configuration</a></p>



<p>In that article, we configure jails such as <code>nginx-exploit</code>, <code>nginx-secure</code>, and <code>sshd</code>. Recidive does not replace that configuration — it strengthens it.</p>



<h2 class="wp-block-heading">How to find repeat offenders in the logs</h2>



<p>First, it’s worth checking whether the issue actually exists. We extract from the Fail2Ban logs the list of IP addresses that were banned most frequently:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">grep "Ban " /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -nr | head</pre></div>



<p>Example output (addresses partially anonymized):</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">13 204.76.203.18
9 41.142.XXX.XXX
8 64.89.XXX.XXX
8 50.82.XXX.XXX
8 35.243.XXX.XXX
8 34.24.XXX.XXX
7 45.166.XXX.XXX
7 34.83.XXX.XXX
7 176.42.XXX.XXX
6 49.36.XXX.XXX</pre></div>



<p>If you see numbers like 8, 9, or 13 — it means those IPs are coming back after the ban expires. A short <code>bantime</code> is just a technical pause for them.</p>



<h2 class="wp-block-heading">Why recidive is better than increasing bantime</h2>



<ul class="wp-block-list">

<li>You don’t have to ban everyone for 24 hours because of a single typo in a URL.</li>



<li>You don’t increase the risk of blocking legitimate users.</li>



<li>The penalty is progressive and applies only to returning addresses.</li>

</ul>



<p>Recidive analyzes <code>/var/log/fail2ban.log</code> and counts how many times a given IP has been banned by other jails. This way, you only “finish off” those that have already been blocked multiple times before.</p>



<h2 class="wp-block-heading">Recidive configuration (5 bans in 24h = 7 days ban)</h2>



<p>Add the following block to <code>/etc/fail2ban/jail.local</code>:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">nano /etc/fail2ban/jail.local</pre></div>



<p>At the end of the file, paste:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">[recidive]
enabled  = true
logpath  = /var/log/fail2ban.log
bantime  = 7d
findtime = 1d
maxretry = 5</pre></div>



<p>Save the file and restart Fail2Ban:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">systemctl restart fail2ban</pre></div>



<p>Check the jail status:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">fail2ban-client status recidive</pre></div>



<h2 class="wp-block-heading">How to check who is close to the recidive threshold</h2>



<p>If you want to see IPs that already have several bans and are approaching the recidive threshold:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">grep "Ban " /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | awk '$1 &gt;= 3 {print}' | sort -nr</pre></div>



<h2 class="wp-block-heading">Summary</h2>



<p>Recidive is one of the simplest and most effective ways to limit recurring scanners and bots. Instead of aggressively banning everyone — you block only those who repeatedly come back.</p>



<p>In an environment with multiple domains, Nginx reverse proxy, and WordPress, it’s practically a must-have configuration element: less noise in logs, fewer repeated attacks, and less manual analysis.</p>
<p>Artykuł <a href="https://soban.pl/fail2ban-recidive-nginx-wordpress-setup/">Fail2Ban: How to Detect Repeat Offenders and Ban Them for a Week (Recidive)</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Debian 13 (Trixie) → Proxmox VE 9 – Simplified Installation on Pure Debian</title>
		<link>https://soban.pl/install-proxmox-ve-9-on-debian-13-trixie/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Mon, 23 Feb 2026 16:18:39 +0000</pubDate>
				<category><![CDATA[Proxmox]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=726</guid>

					<description><![CDATA[<p>Proxmox VE 9 is based on Debian 13 (Trixie) and introduces a newer kernel, updated LXC, QEMU and improved virtualization stack. This guide presents a simplified and automated method to install Proxmox VE 9 on a clean Debian 13 system using two installation scripts. The method follows the same approach as my previous Proxmox 8 [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/install-proxmox-ve-9-on-debian-13-trixie/">Debian 13 (Trixie) → Proxmox VE 9 – Simplified Installation on Pure Debian</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><img decoding="async" width="1024" height="680" src="https://soban.pl/wp-content/uploads/2026/02/image-2-1024x680.png" alt="" class="wp-image-727" style="width:593px;height:auto" srcset="https://soban.pl/wp-content/uploads/2026/02/image-2-1024x680.png 1024w, https://soban.pl/wp-content/uploads/2026/02/image-2-300x199.png 300w, https://soban.pl/wp-content/uploads/2026/02/image-2-768x510.png 768w, https://soban.pl/wp-content/uploads/2026/02/image-2.png 1118w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Proxmox VE 9 is based on Debian 13 (Trixie) and introduces a newer kernel, updated LXC, QEMU and improved virtualization stack. This guide presents a simplified and automated method to install Proxmox VE 9 on a clean Debian 13 system using two installation scripts.</p>



<p>The method follows the same approach as my previous Proxmox 8 on Debian 12 guide, but adapted for Debian 13 and Proxmox VE 9.</p>



<h2 class="wp-block-heading">Prerequisites</h2>



<ul class="wp-block-list">
<li>Fresh Debian 13 (Trixie) installation</li>



<li>Root access</li>



<li>Internet connectivity</li>
</ul>



<p>All commands must be executed as root.</p>



<h2 class="wp-block-heading">Part 1 – System Preparation &amp; Proxmox Kernel Installation</h2>



<p>Download the first script:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">wget http://soban.pl/bash/install-proxmox9-part1.sh
chmod +x install-proxmox9-part1.sh
./install-proxmox9-part1.sh</pre></div>



<p>This script:</p>



<ul class="wp-block-list">
<li>Sets hostname and updates /etc/hosts</li>



<li>Installs Proxmox archive keyring (verified via SHA512)</li>



<li>Adds Proxmox VE 9 repository for Debian 13</li>



<li>Performs full system upgrade</li>



<li>Installs proxmox-default-kernel</li>



<li>Reboots the system</li>
</ul>



<h3 class="wp-block-heading">Content of install-proxmox9-part1.sh</h3>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">#!/usr/bin/env bash
set -euo pipefail

# Part 1/2: Debian 13 (Trixie) -&gt; Proxmox VE 9
# - sets /etc/hosts
# - adds PVE repo + installs Proxmox archive keyring (verified by SHA512)
# - full-upgrade
# - installs proxmox-default-kernel
# - reboots

log() { echo "[$(date '+%F %T')] $*"; }
die() { echo "ERROR: $*" &gt;&amp;2; exit 1; }

if [[ "$(id -u)" -ne 0 ]]; then
  die "Run as root."
fi

log "=== Proxmox VE 9 install (part 1/2) on Debian 13 Trixie ==="

if ! grep -qi 'trixie' /etc/os-release; then
  log "WARNING: This does not look like Debian 13 (Trixie). Continue at your own risk."
fi

log "Network interfaces (for reference):"
ip -br -c a || true

CURRENT_HOSTNAME="$(hostname)"
CURRENT_IP="$(hostname -I | awk '{print $1}')"

read -r -p "Hostname for this node [${CURRENT_HOSTNAME}]: " HOSTNAME
HOSTNAME="${HOSTNAME:-$CURRENT_HOSTNAME}"

read -r -p "Primary IP for /etc/hosts [${CURRENT_IP}]: " IPADDR
IPADDR="${IPADDR:-$CURRENT_IP}"

if [[ -z "${HOSTNAME}" || -z "${IPADDR}" ]]; then
  die "Hostname/IP cannot be empty."
fi

log "Setting hostname to: ${HOSTNAME}"
hostnamectl set-hostname "${HOSTNAME}"

log "Backing up /etc/hosts -&gt; /etc/hosts.backup"
cp -a /etc/hosts /etc/hosts.backup

log "Writing /etc/hosts (makes hostname resolvable locally)"
cat &gt; /etc/hosts &lt;&lt;EOT
127.0.0.1       localhost
${IPADDR}       ${HOSTNAME}

# IPv6
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOT

log "Installing prerequisites"
apt update
apt install -y wget ca-certificates gnupg

log "Installing Proxmox archive keyring to /usr/share/keyrings/proxmox-archive-keyring.gpg"
KEYRING="/usr/share/keyrings/proxmox-archive-keyring.gpg"
wget -q https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg -O "${KEYRING}"

log "Verifying SHA512 of keyring"
EXPECTED_SHA512="8678f2327c49276615288d7ca11e7d296bc8a2b96946fe565a9c81e533f9b15a5dbbad210a0ad5cd46d361ff1d3c4bac55844bc296beefa4f88b86e44e69fa51"
ACTUAL_SHA512="$(sha512sum "${KEYRING}" | awk '{print $1}')"

if [[ "${ACTUAL_SHA512}" != "${EXPECTED_SHA512}" ]]; then
  die "Keyring SHA512 mismatch!
Expected: ${EXPECTED_SHA512}
Actual:   ${ACTUAL_SHA512}"
fi

log "Adding Proxmox VE 9 no-subscription repo (Trixie)"
cat &gt; /etc/apt/sources.list.d/pve-install-repo.list &lt;&lt;EOT
deb [arch=amd64 signed-by=/usr/share/keyrings/proxmox-archive-keyring.gpg] http://download.proxmox.com/debian/pve trixie pve-no-subscription
EOT

log "Updating + full-upgrade"
apt update
apt full-upgrade -y

log "Installing Proxmox kernel meta-package: proxmox-default-kernel"
apt install -y proxmox-default-kernel

log "Part 1 done. Rebooting now. After reboot run: ./install-proxmox9-part2.sh"
reboot</pre></div>



<h2 class="wp-block-heading">Part 2 – Proxmox VE 9 Installation</h2>



<p>After reboot, download and execute:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">wget http://soban.pl/bash/install-proxmox9-part2.sh
chmod +x install-proxmox9-part2.sh
./install-proxmox9-part2.sh</pre></div>



<h3 class="wp-block-heading">Content of install-proxmox9-part2.sh</h3>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">#!/usr/bin/env bash
set -euo pipefail

# Part 2/2: Debian 13 (Trixie) -&gt; Proxmox VE 9
# - verifies running PVE kernel (unless FORCE=1)
# - installs proxmox-ve + required packages
# - removes Debian kernel packages (keeps pve)
# - updates grub
# - removes os-prober
# - prints URL to GUI

log() { echo "[$(date '+%F %T')] $*"; }
die() { echo "ERROR: $*" &gt;&amp;2; exit 1; }

FORCE="${FORCE:-0}"

if [[ "$(id -u)" -ne 0 ]]; then
  die "Run as root."
fi

log "=== Proxmox VE 9 install (part 2/2) ==="

KERNEL="$(uname -r || true)"
if ! echo "${KERNEL}" | grep -qi 'pve'; then
  if [[ "${FORCE}" != "1" ]]; then
    die "You are NOT running a PVE kernel (uname -r: ${KERNEL}).
Reboot and select the Proxmox kernel first.
If you really want to continue anyway: FORCE=1 ./install-proxmox9-part2.sh"
  else
    log "WARNING: Continuing despite not running PVE kernel because FORCE=1"
  fi
else
  log "OK: running PVE kernel: ${KERNEL}"
fi

log "Update package lists"
apt update

log "Install Proxmox VE packages"
# postfix is optional but commonly installed by docs; choose config during prompts
DEBIAN_FRONTEND=readline apt install -y proxmox-ve postfix open-iscsi chrony

log "Upgrade remaining packages"
apt full-upgrade -y

log "Removing Debian kernel meta-package and non-PVE kernels (best-effort)"
# Remove Debian meta kernel (keeps proxmox kernel)
apt remove -y linux-image-amd64 || true

# Purge any installed linux-image-* that is NOT a pve kernel
mapfile -t KPKGS &lt; &lt;(dpkg -l | awk '/^ii  linux-image-/{print $2}' | grep -vE 'pve|proxmox' || true)
if (( ${#KPKGS[@]} &gt; 0 )); then
  log "Purging non-PVE kernel packages: ${KPKGS[*]}"
  apt purge -y "${KPKGS[@]}" || true
fi

log "Update grub"
update-grub || true

log "Remove os-prober (recommended for servers; avoids odd grub side effects)"
apt remove -y os-prober || true

log "Done. Proxmox UI should be available at:"
IP="$(hostname -I | awk '{print $1}')"
echo "https://${IP}:8006"

log "Login: root + your root password"</pre></div>



<h2 class="wp-block-heading">Accessing the Web Interface</h2>



<p>After completing the second script, open:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">https://YOUR_SERVER_IP:8006</pre></div>



<p>Login with the <strong>root</strong> user and your root password. You may see a certificate warning — this is normal for fresh installations.</p>




<h2 class="wp-block-heading">Troubleshooting – 401 Unauthorized (pve-enterprise repository)</h2>



<p>If after installation or during <code>apt update</code> you encounter the following error:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">Err:8 https://enterprise.proxmox.com/debian/pve trixie InRelease
  401  Unauthorized [IP: 2001:41d0:b00:5900::34 443]
Error: Failed to fetch https://enterprise.proxmox.com/debian/pve/dists/trixie/InRelease  401  Unauthorized
Error: The repository 'https://enterprise.proxmox.com/debian/pve trixie InRelease' is not signed.
Notice: Updating from such a repository can't be done securely, and is therefore disabled by default.</pre></div>



<p>This means the <strong>enterprise repository</strong> is enabled but your system does not have a valid Proxmox subscription.  
If you are using the <em>no-subscription</em> repository (as shown in this guide), you should disable the enterprise repository.</p>



<p>Fix it by running:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">mv /etc/apt/sources.list.d/pve-enterprise.sources \
   /etc/apt/sources.list.d/pve-enterprise.sources.disabled

apt update</pre></div>



<p>After this, the update should complete successfully:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">apt update && apt dist-upgrade -y && apt autoremove -y</pre></div>



<p>If everything is correct, you should see:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">All packages are up to date.</pre></div>


<h2 class="wp-block-heading">Conclusion</h2>



<p>This method provides a clean and controlled way to deploy Proxmox VE 9 directly on Debian 13 without using the ISO installer. It is especially useful for automated environments, labs, and custom infrastructure setups.</p>
<p>Artykuł <a href="https://soban.pl/install-proxmox-ve-9-on-debian-13-trixie/">Debian 13 (Trixie) → Proxmox VE 9 – Simplified Installation on Pure Debian</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Fail2Ban Nginx Setup &#8211; Block Scanners and Exploits Without Blocking WordPress Admin</title>
		<link>https://soban.pl/fail2ban-nginx-wordpress-setup-2/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 23:10:10 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=720</guid>

					<description><![CDATA[<p>This guide shows a complete Fail2Ban installation and configuration for Nginx, designed to: block real scanners and exploit attempts (e.g. requests to /.env, /.git, /phpmyadmin, etc.), avoid blocking administrators by accident (common issue when banning only by HTTP errors), ban IP addresses after repeated suspicious activity, use a short ban time (5 minutes) to reduce [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/fail2ban-nginx-wordpress-setup-2/">Fail2Ban Nginx Setup &#8211; Block Scanners and Exploits Without Blocking WordPress Admin</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="486" height="747" src="https://soban.pl/wp-content/uploads/2026/02/image-1.png" alt="" class="wp-image-717" srcset="https://soban.pl/wp-content/uploads/2026/02/image-1.png 486w, https://soban.pl/wp-content/uploads/2026/02/image-1-195x300.png 195w" sizes="auto, (max-width: 486px) 100vw, 486px" /></figure>



<h2 class="wp-block-heading">This guide shows a complete Fail2Ban installation and configuration for Nginx, designed to:</h2>



<ul class="wp-block-list">
<li>block real scanners and exploit attempts (e.g. requests to <code>/.env</code>, <code>/.git</code>, <code>/phpmyadmin</code>, etc.),</li>
<li>avoid blocking administrators by accident (common issue when banning only by HTTP errors),</li>
<li>ban IP addresses after repeated suspicious activity,</li>
<li>use a short ban time (5 minutes) to reduce the risk of locking yourself out.</li>
</ul>



<h2 class="wp-block-heading">Why banning by HTTP errors alone can backfire</h2>



<p>Many guides suggest banning by HTTP status codes (4xx/499) only. In real life this often causes self-bans, because modern apps generate bursts of requests (AJAX, admin panels, cache rebuilds), and you can hit error statuses during normal work.</p>



<p>This setup uses a safer approach:</p>



<ul class="wp-block-list">
<li><strong>exploit paths</strong> are always suspicious,</li>
<li><strong>HTTP errors are counted only when the request has no Referer</strong> (typical for scanners),</li>
<li><strong>known bad User-Agents</strong> are counted.</li>
</ul>



<h2 class="wp-block-heading">Step 1: Install Fail2Ban</h2>



<p>Install Fail2Ban:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">apt update
apt install -y fail2ban</pre>



<p>Enable and start the service:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">systemctl enable fail2ban
systemctl start fail2ban</pre>



<p>Verify that it is running:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">fail2ban-client ping
systemctl status fail2ban</pre>



<h2 class="wp-block-heading">Step 2: Create the nginx-secure filter</h2>



<p>Create the filter file:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">nano /etc/fail2ban/filter.d/nginx-secure.conf</pre>



<p>Paste the following configuration:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">[Definition]

failregex =
    # exploit paths
    ^&lt;HOST&gt; - .* "(?:GET|POST|HEAD|PUT|DELETE|OPTIONS|PATCH|PROPFIND|CONNECT) (?:/\.env|/wp-config\.php|/phpinfo\.php|/(?:phpmyadmin|adminer)(?:/|$)|/(?:\.git|\.svn|\.hg)(?:/|$)|/vendor/phpunit/|/cgi-bin/).*" \d{3} .*

    # errors without referer (real scanners)
    ^&lt;HOST&gt; - .* "(?:GET|POST|HEAD|PUT|DELETE|OPTIONS|PATCH|PROPFIND|CONNECT) [^"]*" (?:400|403|404|405|408|413|414|429|444) [^"]* "-" ".*"

    # bad user agents
    ^&lt;HOST&gt; - .* "(?:GET|POST|HEAD|PUT|DELETE|OPTIONS|PATCH|PROPFIND|CONNECT).*" \d{3} .* "(?:[^"]*)" "(?:[^"]*(?:sqlmap|nikto|masscan|zgrab|nmap|acunetix|wpscan|dirbuster|gobuster)[^"]*)"

ignoreregex =</pre>



<h2 class="wp-block-heading">Step 3: Create the nginx-secure jail</h2>



<p>Create the jail configuration file:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">nano /etc/fail2ban/jail.d/nginx-secure.conf</pre>



<p>Paste the following configuration:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">[nginx-secure]
enabled  = true
port     = http,https
filter   = nginx-secure

logpath  = /var/log/nginx/access.log
           /var/log/nginx/access-*.log

findtime = 600
maxretry = 20
bantime  = 300

action   = iptables-multiport[name=nginx-secure, port="http,https"]

ignoreip = 127.0.0.1/8 ::1</pre>



<h2 class="wp-block-heading">Step 4: Restart Fail2Ban</h2>



<pre class="urvanov-syntax-highlighter-plain-tag">fail2ban-server -t
systemctl restart fail2ban</pre>



<h2 class="wp-block-heading">Step 5: Verify firewall integration</h2>



<p>Check that the Fail2Ban chain exists:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">iptables -S | grep f2b-nginx-secure
iptables -L f2b-nginx-secure -n -v</pre>



<h2 class="wp-block-heading">External test</h2>



<p>Run from another machine (exploit path test):</p>



<pre class="urvanov-syntax-highlighter-plain-tag">for i in 1 2 3 4 5; do
  curl -I https://soban.pl/.env
done</pre>



<p>Test &#8220;errors without Referer&#8221; logic (scanner-like request &#8211; no referer header):</p>



<pre class="urvanov-syntax-highlighter-plain-tag">for i in 1 2 3 4 5; do
  curl -sS -o /dev/null -w "%{http_code}\n" https://soban.pl/this-path-should-not-exist-$i
done</pre>



<p>After repeated suspicious requests, the IP address will be banned for 5 minutes.</p>



<h2 class="wp-block-heading">Check banned IPs</h2>



<pre class="urvanov-syntax-highlighter-plain-tag">fail2ban-client status nginx-secure</pre>



<h2 class="wp-block-heading">Unban IP address</h2>



<p>Unban an IP manually:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">fail2ban-client set nginx-secure unbanip YOUR_IP</pre>



<h2 class="wp-block-heading">Summary</h2>



<ul class="wp-block-list">
<li>blocks exploit paths and real scanners,</li>
<li>reduces self-bans by counting HTTP errors only when the Referer is missing,</li>
<li>uses a short 5-minute ban duration,</li>
<li>works with iptables-nft,</li>
<li>easy to test and easy to unban IP addresses.</li>
</ul>
<p>Artykuł <a href="https://soban.pl/fail2ban-nginx-wordpress-setup-2/">Fail2Ban Nginx Setup &#8211; Block Scanners and Exploits Without Blocking WordPress Admin</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Automatic upgrade Debian 12 → Debian 13 with optional PHP and nginx update</title>
		<link>https://soban.pl/upgrade-debian-12-to-13-2/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 11:15:42 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=709</guid>

					<description><![CDATA[<p>Upgrading Debian from version 12 (bookworm) to 13 (trixie) is an operation that should be performed in a repeatable and predictable way, especially on servers and containers (for example Proxmox LXC or virtual machines). Below you will find a simple guide and ready-to-use commands to download and run the upgrade script. Before running the upgrade: [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/upgrade-debian-12-to-13-2/">Automatic upgrade Debian 12 → Debian 13 with optional PHP and nginx update</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized">
<img loading="lazy" decoding="async" width="1024" height="682" src="https://soban.pl/wp-content/uploads/2026/02/image-1024x682.png" alt="Debian 12 to Debian 13 upgrade" class="wp-image-707" style="width:551px;height:auto" srcset="https://soban.pl/wp-content/uploads/2026/02/image-1024x682.png 1024w, https://soban.pl/wp-content/uploads/2026/02/image-300x200.png 300w, https://soban.pl/wp-content/uploads/2026/02/image-768x511.png 768w, https://soban.pl/wp-content/uploads/2026/02/image.png 1119w" sizes="auto, (max-width: 1024px) 100vw, 1024px" />
</figure>



<p>Upgrading Debian from version 12 (<strong>bookworm</strong>) to 13 (<strong>trixie</strong>) is an operation that should be performed in a repeatable and predictable way, especially on servers and containers (for example Proxmox LXC or virtual machines). Below you will find a simple guide and ready-to-use commands to download and run the upgrade script.</p>



<p><strong>Before running the upgrade:</strong> create a backup or snapshot. In Proxmox, the best option is <code>vzdump</code> or a snapshot. On bare metal, at minimum back up <code>/etc</code>, applications, and databases.</p>



<ul class="wp-block-list">
<li><strong>Proxmox LXC / VM</strong>: backup using vzdump or create a snapshot.</li>
<li><strong>Server</strong>: backup /etc, /var/www, databases (MySQL/PostgreSQL), and SSL certificates.</li>
</ul>



<p>Script download:</p>



<p><a href="https://soban.pl/bash/upgrade_to_debian13.sh" target="_blank" rel="noopener noreferrer">https://soban.pl/bash/upgrade_to_debian13.sh</a></p>



<h2 class="wp-block-heading">1) Backup before upgrade (examples)</h2>



<p>Example backup in Proxmox (run on Proxmox host, replace CTID/VMID):</p>



<pre class="urvanov-syntax-highlighter-plain-tag">vzdump 101 --mode snapshot --compress zstd --storage local</pre>



<p>Example simple filesystem backup on a server (this does not replace a full snapshot, but it&#8217;s better than nothing):</p>



<pre class="urvanov-syntax-highlighter-plain-tag">tar czf /root/backup_before_upgrade.tar.gz /etc /var/www /root</pre>



<h2 class="wp-block-heading">2) Download the script (wget / curl)</h2>



<p>The easiest way is to use <strong>wget</strong>. If the <code>wget</code> command does not work even though the package is installed, use the full path <code>/usr/bin/wget</code>.</p>



<p><strong>Variant A (standard wget):</strong></p>



<pre class="urvanov-syntax-highlighter-plain-tag">apt update
apt install -y wget
cd /root
wget -O upgrade_to_debian13.sh https://soban.pl/bash/upgrade_to_debian13.sh
chmod +x upgrade_to_debian13.sh</pre>



<p><strong>Variant B (wget with full path – useful if PATH is broken):</strong></p>



<pre class="urvanov-syntax-highlighter-plain-tag">apt update
apt install -y wget
cd /root
/usr/bin/wget -O upgrade_to_debian13.sh https://soban.pl/bash/upgrade_to_debian13.sh
chmod +x upgrade_to_debian13.sh</pre>



<p><strong>Variant C (curl):</strong></p>



<pre class="urvanov-syntax-highlighter-plain-tag">apt update
apt install -y curl
cd /root
curl -fsSL -o upgrade_to_debian13.sh https://soban.pl/bash/upgrade_to_debian13.sh
chmod +x upgrade_to_debian13.sh</pre>



<h2 class="wp-block-heading">3) Script help (parameters)</h2>



<p>Before running the upgrade, display available parameters and usage examples:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">cd /root
./upgrade_to_debian13.sh --help</pre>



<h2 class="wp-block-heading">4) Upgrade Debian 12 → Debian 13 (system only)</h2>



<p>If you are currently running Debian 12 (bookworm) and want to perform a system upgrade:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">cd /root
./upgrade_to_debian13.sh</pre>



<p>The script will create a backup of <code>/etc/apt/sources.list</code>, switch repositories to trixie, run <code>apt update</code> and <code>apt full-upgrade</code>, and finally execute <code>autoremove</code> and <code>autoclean</code>.</p>



<h2 class="wp-block-heading">5) Auto-detect PHP/nginx and update if needed</h2>



<p>If the container or VM is running a web stack and you want the script to automatically detect PHP usage (nginx + <code>fastcgi_pass</code>) and upgrade PHP and nginx if necessary:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">cd /root
./upgrade_to_debian13.sh --auto</pre>



<h2 class="wp-block-heading">6) Force PHP and nginx upgrade (PHP-FPM socket fix)</h2>



<p>If you want to force installation or upgrade of PHP and automatically fix nginx configuration to use the correct PHP-FPM socket:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">cd /root
./upgrade_to_debian13.sh --with-php --with-nginx --php-version 8.2</pre>



<p>This command installs PHP 8.2 (php-fpm and common modules) and replaces old PHP-FPM socket paths in nginx configuration with <code>/run/php/php8.2-fpm.sock</code>. Then it runs <code>nginx -t</code> and reloads or restarts services.</p>



<h2 class="wp-block-heading">7) Already running Debian 13? PHP/nginx only mode</h2>



<p>If the system is already running Debian 13 (trixie) and you only want to upgrade PHP and nginx without modifying system repositories:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">cd /root
./upgrade_to_debian13.sh --php-nginx-only --with-php --with-nginx --php-version 8.2</pre>



<h2 class="wp-block-heading">8) Dry-run mode (test mode)</h2>



<p>If you want to see what the script will do without making any changes:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">cd /root
./upgrade_to_debian13.sh --auto --dry-run</pre>



<h2 class="wp-block-heading">9) Troubleshooting: wget installed but not working</h2>



<p>If <code>apt</code> reports wget is installed but the shell shows <code>command not found</code>, it is usually a PATH issue. The easiest workaround is to use the full path: <code>/usr/bin/wget</code>.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">echo "$PATH"
command -v wget || true
ls -l /usr/bin/wget || true
/usr/bin/wget --version || true</pre>



<h2 class="wp-block-heading">Summary</h2>



<p>This solution provides a convenient way to upgrade Debian 12 → Debian 13 and optionally fix common PHP/nginx issues after upgrade (PHP-FPM socket paths, nginx config testing, and service restart). Always create a backup before upgrading and start by running <code>--help</code> to review available options.</p>



<p>Script: <a href="https://soban.pl/bash/upgrade_to_debian13.sh" target="_blank" rel="noopener noreferrer">https://soban.pl/bash/upgrade_to_debian13.sh</a></p>
<p>Artykuł <a href="https://soban.pl/upgrade-debian-12-to-13-2/">Automatic upgrade Debian 12 → Debian 13 with optional PHP and nginx update</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Proxmox VM Auto-Upgrade Script (qm + vzdump) with Network Tests and Auto-Restore</title>
		<link>https://soban.pl/proxmox-vm-auto-upgrade-script/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Fri, 23 Jan 2026 15:56:05 +0000</pubDate>
				<category><![CDATA[Patching]]></category>
		<category><![CDATA[Proxmox]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=680</guid>

					<description><![CDATA[<p>Proxmox VM Auto-Upgrade Script (qm + vzdump) with Network Tests and Auto-Restore This article describes a simple (but effective) automation script for Proxmox VE that: Where to download the script You can download the script directly from my website: soban.pl/bash/upgrade_proxmox_qm.sh Required folders Before you run anything, create two folders for scripts and logs: Install the [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/proxmox-vm-auto-upgrade-script/">Proxmox VM Auto-Upgrade Script (qm + vzdump) with Network Tests and Auto-Restore</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="498" height="745" src="https://soban.pl/wp-content/uploads/2026/01/image-1.png" alt="" class="wp-image-681" style="width:452px;height:auto" srcset="https://soban.pl/wp-content/uploads/2026/01/image-1.png 498w, https://soban.pl/wp-content/uploads/2026/01/image-1-201x300.png 201w" sizes="auto, (max-width: 498px) 100vw, 498px" /></figure>



<p>Proxmox VM Auto-Upgrade Script (qm + vzdump) with Network Tests and Auto-Restore</p>



<p>This article describes a simple (but effective) automation script for Proxmox VE that:</p>



<ul class="wp-block-list">
<li>creates a backup of a VM (optional),</li>



<li>starts the VM if it was originally stopped,</li>



<li>runs apt upgrade + reboot inside the VM,</li>



<li>performs network tests before and after the update,</li>



<li>restores from backup automatically if tests fail (optional),</li>



<li>shuts down the VM again if it was originally stopped.</li>
</ul>



<h3 class="wp-block-heading">Where to download the script</h3>



<p>You can download the script directly from my website:</p>



<p><strong>soban.pl/bash/upgrade_proxmox_qm.sh</strong></p>



<h3 class="wp-block-heading">Required folders</h3>



<p>Before you run anything, create two folders for scripts and logs:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">mkdir -p /root/automate_scripts /root/logs</pre></div>



<h3 class="wp-block-heading">Install the script</h3>



<p>Download the file into <code>/root/automate_scripts/</code> and make it executable:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cd /root/automate_scripts
curl -fsSL -o upgrade_proxmox_qm.sh "https://soban.pl/bash/upgrade_proxmox_qm.sh"
chmod +x /root/automate_scripts/upgrade_proxmox_qm.sh</pre></div>



<h3 class="wp-block-heading">How it works (high level)</h3>



<ul class="wp-block-list">
<li><strong>Backup</strong> (vzdump snapshot + zstd) is executed first (if enabled).</li>



<li>If the VM was <strong>stopped</strong>, the script starts it and waits <strong>WAIT_TIME</strong> seconds.</li>



<li>Runs <strong>network tests BEFORE update</strong>:
		<ul>
			
			
			
			
		</ul>
	





</li>



<li>Executes apt update/upgrade/dist-upgrade/autoremove/clean and finally <strong>reboots</strong> the VM.</li>



<li>Waits again (<strong>WAIT_TIME</strong>) and runs the same tests <strong>AFTER update</strong>.</li>



<li>If tests fail and a backup exists, it performs <strong>qmrestore</strong> automatically.</li>



<li>If the VM was originally stopped, it shuts down the VM at the end.</li>
</ul>



<h3 class="wp-block-heading">Usage</h3>



<p>The script expects exactly two arguments:</p>



<ul class="wp-block-list">
<li><code>VMID</code> &#8211; the Proxmox VM ID</li>



<li><code>TIME_SEC</code> &#8211; how long to wait after start/reboot (in seconds)</li>
</ul>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">/root/automate_scripts/upgrade_proxmox_qm.sh 901 500</pre></div>



<p><strong>Tip:</strong> choose a WAIT_TIME that matches your VM boot time and apt upgrade duration. Typical values are <code>300</code> to <code>1000</code> seconds depending on the VM.</p>



<h3 class="wp-block-heading">Full script (for reference)</h3>



<p>If you prefer to keep everything in one place, below is the full script exactly as used in this setup:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">#!/bin/bash

WAIT_TIME=$2  # wait time for VM start/restart (in seconds)
DO_BACKUP="y" # 'y' - create backup, 'n' - skip backup
DO_UPDATE="y" # 'y' - run system update, 'n' - skip update

echo "---------------START---------------"
date
echo "-----------------------------------"

# Argument check
if [ "$#" -ne 2 ]; then
    echo "Usage: $0 &lt;VMID&gt; &lt;TIME_SEC&gt;"
    exit 1
fi

VMID="$1"
TARGET_HOSTNAME=$(/usr/sbin/qm list | grep -w "$VMID" | awk '{print $2}')
VM_STATUS=$(/usr/sbin/qm status "$VMID" | awk '{print $2}')
HOST_MACHINE=$(hostname)
WAS_STOPPED=0

if [ "$VM_STATUS" = "stopped" ]; then
    WAS_STOPPED=1
else
    WAS_STOPPED=0
fi

# Create backup if DO_BACKUP is set to 'y'
backup_result="Backup not attempted"
if [ "$DO_BACKUP" = "y" ]; then
    echo "Creating backup for VM $VMID..."
    BACKUP_OUTPUT=$(/usr/bin/vzdump "$VMID" --storage local --mode snapshot --compress zstd)
    BACKUP_FILE=$(echo "$BACKUP_OUTPUT" | grep -oP 'vzdump-qemu-[^\s]+' | tr -d "'")

    if [ -z "$BACKUP_FILE" ]; then
        echo "Backup failed: No backup file created."
        backup_result="Backup created: NOK"
        exit 1
    else
        echo "Backup created successfully: $BACKUP_FILE"
        backup_result="Backup created: OK"
    fi
else
    echo "Backup not attempted (backup is disabled)."
fi

# Start VM if it was originally stopped
if [ "$WAS_STOPPED" -eq 1 ]; then
    echo "Starting VM $VMID for update..."
    /usr/sbin/qm start "$VMID"
    echo "Waiting $WAIT_TIME seconds for VM to start..."
    sleep "$WAIT_TIME"
fi

# Test functions
perform_ping_test() {
    source="$1"
    target="$2"
    if ssh root@"$source" "ping -c 3 -W 2 $target" &gt;/dev/null 2&gt;&amp;1; then
        echo "Ping from $source to $target: OK"
        return 0
    else
        echo "Ping from $source to $target: NOK"
        return 1
    fi
}

test_curl() {
    source="$1"
    target="$2"
    if ssh root@"$source" "curl -s --head --connect-timeout 5 $target" &gt;/dev/null 2&gt;&amp;1; then
        echo "Curl from $source to $target: OK"
        return 0
    else
        echo "Curl from $source to $target: NOK"
        return 1
    fi
}

perform_local_ping_test() {
    source="$1"
    target="$2"
    if ping -c 3 -W 2 "$target" &gt;/dev/null 2&gt;&amp;1; then
        echo "Ping from $source to $target: OK"
        return 0
    else
        echo "Ping from $source to $target: NOK"
        return 1
    fi
}

DEFAULT_GW=$(/sbin/ip route | grep default | awk '{print $3}')

perform_tests() {
    status=0
    perform_local_ping_test "$HOST_MACHINE" "$TARGET_HOSTNAME" || status=1
    perform_ping_test "$TARGET_HOSTNAME" "8.8.8.8" || status=1
    perform_ping_test "$TARGET_HOSTNAME" "$DEFAULT_GW" || status=1
    test_curl "$TARGET_HOSTNAME" "http://google.com" || status=1
    return ${status:-0}
}

# General tests before update
echo "--- General tests BEFORE update ---"
if perform_tests; then
    echo "All network tests before update: OK"
    echo "$backup_result"

    if [ "$backup_result" == "Backup created: OK" ] || [ "$backup_result" == "Backup not attempted" ]; then
        echo "BEFORE status: OK"
    else
        echo "BEFORE status: NOK"
    fi
else
    echo "Some network tests before update: NOK"
    echo "$backup_result"
    echo "BEFORE status: NOK"
    [ "$WAS_STOPPED" -eq 1 ] &amp;&amp; /usr/sbin/qm shutdown "$VMID"
    exit 1
fi
echo "-----------------------------------"

# System update and reboot
update_result="Upgrade system: NOK"
if [ "$DO_UPDATE" = "y" ]; then
    echo "--- Updating VM $VMID ---"
    if ssh root@"$TARGET_HOSTNAME" "/usr/bin/apt update &amp;&amp; \
                          /usr/bin/apt upgrade -y &amp;&amp; \
                          /usr/bin/apt dist-upgrade -y &amp;&amp; \
                          /usr/bin/apt autoremove -y &amp;&amp; \
                          /usr/bin/apt autoclean &amp;&amp; \
                          /usr/bin/apt clean &amp;&amp; \
                          /usr/bin/apt --purge autoremove &amp;&amp; \
                          /sbin/reboot"; then
        echo "---END Updating VM $VMID ---"
        echo "Upgrade system: OK"
        update_result="Upgrade system: OK"
    else
        echo "Upgrade system: NOK"
        update_result="Upgrade system: NOK"
        [ "$WAS_STOPPED" -eq 1 ] &amp;&amp; /usr/sbin/qm shutdown "$VMID"
        echo "Update failed. Exiting."
        exit 1
    fi
fi

# Wait for VM reboot if update was performed
if [ "$DO_UPDATE" = "y" ]; then
    echo "Waiting $WAIT_TIME seconds for VM to reboot..."
    sleep "$WAIT_TIME"
fi

# Tests after reboot if update was performed
if [ "$DO_UPDATE" = "y" ]; then
    echo "--- Network tests AFTER update ---"
    if perform_tests; then
        echo "All network tests after update: OK"
        echo "$update_result"
        echo "AFTER status: OK"
    else
        echo "Some network tests after update: NOK"
        echo "$update_result"
        echo "Attempting to restore from backup..."

        if [ "$DO_BACKUP" = "y" ]; then
            /usr/sbin/qm stop "$VMID"
            /usr/sbin/qmrestore "/var/lib/vz/dump/$BACKUP_FILE" "$VMID" --force

            if [ "$WAS_STOPPED" -eq 1 ]; then
                /usr/sbin/qm shutdown "$VMID"
            fi

            echo "Restore attempt finished. Please check VM status."
            echo "AFTER status: NOK"
        else
            echo "No backup available for restoration. The VM might not function properly after failed update."
            echo "AFTER status: NOK"
        fi
    fi
    echo "-----------------------------------"
fi

# Shut down VM if it was originally stopped
if [ "$WAS_STOPPED" -eq 1 ]; then
    echo "Shutting down VM $VMID (originally stopped)."
    /usr/sbin/qm shutdown "$VMID"
fi

echo "---------------END---------------"
date
echo "-----------------------------------"</pre></div>



<h3 class="wp-block-heading">Cron jobs (weekly schedule + per-VM logs)</h3>



<p>Below is an example crontab that runs upgrades once a week (different VM each weekday) and writes separate logs to <code>/root/logs/</code>.</p>



<p>Edit root crontab:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">crontab -e</pre></div>



<p>Paste rules like these (comments in English):</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">15 0 * * 1 /root/automate_scripts/upgrade_proxmox_qm.sh 901 500 &gt; /root/logs/kali.log 2&gt;&amp;1                 # Monday: upgrade Kali Linux (VMID 901)
15 0 * * 2 /root/automate_scripts/upgrade_proxmox_qm.sh 903 500 &gt; /root/logs/proxmox-test-01.log 2&gt;&amp;1      # Tuesday: upgrade proxmox-test-01 (VMID 903)
15 0 * * 3 /root/automate_scripts/upgrade_proxmox_qm.sh 904 500 &gt; /root/logs/ubuntu-lte.log 2&gt;&amp;1           # Wednesday: upgrade ubuntu-lte (VMID 904)
15 0 * * 4 /root/automate_scripts/upgrade_proxmox_qm.sh 905 1000 &gt; /root/logs/backup-machine.log 2&gt;&amp;1      # Thursday: upgrade backup-machine (VMID 905)</pre></div>



<h3 class="wp-block-heading">Quick checks / troubleshooting</h3>



<ul class="wp-block-list">
<li>Make sure root can SSH into the VM by hostname (the script uses <code>ssh root@&lt;vm-hostname&gt;</code>).</li>



<li>Make sure DNS (or /etc/hosts) resolves the VM hostname correctly from the Proxmox host.</li>



<li>If apt needs user interaction, ensure your VMs are set up for non-interactive upgrades (or pin/hold packages that prompt).</li>
</ul>



<p>That’s it. Drop the script into <code>/root/automate_scripts/</code>, send logs into <code>/root/logs/</code>, and your weekly VM maintenance becomes mostly fire-and-forget.</p>
<p>Artykuł <a href="https://soban.pl/proxmox-vm-auto-upgrade-script/">Proxmox VM Auto-Upgrade Script (qm + vzdump) with Network Tests and Auto-Restore</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Dell WD19/WD19S: firmware update on Proxmox/Debian without USB timeouts (fwupd + autosuspend fix)</title>
		<link>https://soban.pl/dell-wd19s-firmware-update-linux-proxmox-debian-usb-timeout-fix/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Sun, 18 Jan 2026 21:06:13 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=670</guid>

					<description><![CDATA[<p>If you’re trying to update the firmware of a Dell WD19/WD19S docking station on Proxmox (or Debian) using fwupdmgr, you may hit the classic Operation timed out error during the Erasing… stage. In practice, the update fails due to USB power management (autosuspend). Below you’ll find a simple, effective fix and a ready-to-run script you [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/dell-wd19s-firmware-update-linux-proxmox-debian-usb-timeout-fix/">Dell WD19/WD19S: firmware update on Proxmox/Debian without USB timeouts (fwupd + autosuspend fix)</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="669" src="https://soban.pl/wp-content/uploads/2026/01/image-1024x669.png" alt="" class="wp-image-667" style="aspect-ratio:1.5306645407436934;width:654px;height:auto" srcset="https://soban.pl/wp-content/uploads/2026/01/image-1024x669.png 1024w, https://soban.pl/wp-content/uploads/2026/01/image-300x196.png 300w, https://soban.pl/wp-content/uploads/2026/01/image-768x502.png 768w, https://soban.pl/wp-content/uploads/2026/01/image.png 1113w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><br>If you’re trying to update the firmware of a Dell WD19/WD19S docking station on Proxmox (or Debian) using <code>fwupdmgr</code>, you may hit the classic <em>Operation timed out</em> error during the <strong>Erasing…</strong> stage. In practice, the update fails due to USB power management (autosuspend). Below you’ll find a simple, effective fix and a ready-to-run script you can use on a server or laptop.</p>



<h2 class="wp-block-heading">Symptoms</h2>



<p>Most commonly, during a dock firmware update (WD19/WD19S), you’ll see an error similar to:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">failed to write-firmware: failed to erase bank: failed after 5 retries: failed to SetReport: USB error: Operation timed out [-7]</pre></div>



<p>At this point, <code>fwupdmgr</code> may show the WD19S device as <strong>Update State: Failed</strong> or keep reporting <strong>pending activation</strong>, but the flash process never completes.</p>



<h2 class="wp-block-heading">Why does this happen?</h2>



<p>During flashing, the dock performs long-running operations. If the system tries to save power on USB (autosuspend), control transfers can fail. The result is a timeout exactly during the flash bank erase stage (<em>erase bank</em>).</p>



<h2 class="wp-block-heading">Quick fix: disable USB autosuspend during the update</h2>



<p>The simplest solution is to temporarily set autosuspend to <code>-1</code> (disabled). This setting lasts until reboot (unless you make it permanent in the kernel cmdline), but it’s more than enough for the update process.</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">echo -1 &gt; /sys/module/usbcore/parameters/autosuspend</pre></div>



<p>Then run the firmware update:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">fwupdmgr refresh --force
fwupdmgr update</pre></div>



<h2 class="wp-block-heading">After the update: “pending activation” and unplug requirement</h2>



<p>After a successful firmware installation for WD19/WD19S, <code>fwupdmgr</code> often prints the following message:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">The update will continue when the device USB cable has been unplugged.
WD19S is pending activation; use fwupdmgr activate to complete the update.</pre></div>



<p>Do the following in this exact order:</p>



<ul class="wp-block-list">
<li>Unplug the USB-C cable from the dock (from the laptop).</li>



<li>(Optional) Unplug the dock power for 10–15 seconds and plug it back in.</li>



<li>Plug the USB-C cable back in.</li>



<li>Run the activation step:</li>
</ul>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">fwupdmgr activate</pre></div>



<p>Finally, verify the status:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">fwupdmgr get-updates
fwupdmgr get-devices | less</pre></div>



<h2 class="wp-block-heading">Ready-to-use script: install + update + autosuspend disable (with restore)</h2>



<p>Below is a ready-to-run script that:</p>



<ul class="wp-block-list">
<li>installs <code>fwupd</code></li>



<li>refreshes LVFS metadata</li>



<li>temporarily disables USB autosuspend (so WD19S won’t fail with timeouts)</li>



<li>runs firmware updates</li>



<li>restores the previous autosuspend value afterwards (even if the update fails)</li>
</ul>



<p>You can copy the script directly from this article, but if you prefer a faster way, you can download it from:</p>



<p><strong>https://soban.pl/bash/dell_updage.sh</strong></p>



<p>Example download and run:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cd /root/scripts
curl -fsSL https://soban.pl/bash/dell_updage.sh -o dell_updage.sh
chmod +x dell_updage.sh
./dell_updage.sh</pre></div>



<p>If you want to preview the script before running it:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">curl -fsSL https://soban.pl/bash/dell_updage.sh | less</pre></div>



<p>If you don’t have <code>less</code> installed:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">apt update
apt install -y less</pre></div>



<h2 class="wp-block-heading">Script (full content)</h2>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">#!/bin/bash
set -euo pipefail

# dell upgrade:
# - installs fwupd
# - refreshes metadata
# - runs fwupdmgr update
# - TEMPORARILY disables USB autosuspend to avoid WD19/WD19S timeouts
# - restores autosuspend setting after update

echo "[INFO] Installing fwupd..."
apt update
apt install -y fwupd

echo "[INFO] Refreshing firmware metadata..."
fwupdmgr refresh --force
fwupdmgr get-updates || true

# Save current autosuspend value (if exists)
AUTOSUSPEND_PATH="/sys/module/usbcore/parameters/autosuspend"
OLD_AUTOSUSPEND=""

if [[ -f "$AUTOSUSPEND_PATH" ]]; then
  OLD_AUTOSUSPEND="$(cat "$AUTOSUSPEND_PATH" || true)"
  echo "[INFO] Current usbcore autosuspend: ${OLD_AUTOSUSPEND}"
else
  echo "[WARN] autosuspend sysfs file not found: $AUTOSUSPEND_PATH"
fi

restore_autosuspend() {
  if [[ -f "$AUTOSUSPEND_PATH" &amp;&amp; -n "${OLD_AUTOSUSPEND}" ]]; then
    echo "[INFO] Restoring usbcore autosuspend back to: ${OLD_AUTOSUSPEND}"
    echo "${OLD_AUTOSUSPEND}" &gt; "$AUTOSUSPEND_PATH" || true
  fi
}
trap restore_autosuspend EXIT

# Disable autosuspend to prevent USB timeout during dock firmware erase/write
if [[ -f "$AUTOSUSPEND_PATH" ]]; then
  echo "[INFO] Disabling USB autosuspend (set to -1) to avoid dock update timeouts..."
  echo -1 &gt; "$AUTOSUSPEND_PATH"
fi

read -p "Do you want to update the entire device? (y/n): " answer
if [[ "$answer" == "y" || "$answer" == "Y" ]]; then
  echo "[INFO] Running fwupdmgr update..."
  fwupdmgr update || {
    echo "[ERROR] fwupdmgr update failed."
    echo "[HINT] If this is Dell dock (WD19/WD19S), try: unplug USB-C, replug, then run: fwupdmgr activate"
    exit 1
  }

  echo "[INFO] Update finished."
  echo "[INFO] If you updated a Dell dock and it says 'pending activation':"
  echo "       1) Unplug USB-C cable from the dock"
  echo "       2) (Optional) Unplug dock power for 10 seconds, plug back"
  echo "       3) Run: fwupdmgr activate"
else
  echo "[INFO] Skipping firmware update."
fi

echo "[INFO] Done."</pre></div>



<h2 class="wp-block-heading">Running the script</h2>



<p>The simplest way:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">chmod +x dell_updage.sh
./dell_updage.sh</pre></div>



<h2 class="wp-block-heading">FAQ &amp; tips</h2>



<ul class="wp-block-list">
<li><strong>The update still fails?</strong> Disconnect all peripherals from the dock (monitors/LAN/USB), leave only power and USB-C, do a hard reset of the dock (unplug power for 30s), and try again.</li>



<li><strong>“pending activation” after update</strong> – this is normal for WD19/WD19S. You must unplug USB-C, plug it back in, then run <code>fwupdmgr activate</code>.</li>



<li><strong>Does this update the laptop BIOS?</strong> Not always. <code>fwupdmgr</code> shows “System Firmware” (BIOS/UEFI) separately from the dock. This article focuses on the dock and the USB timeout issue.</li>
</ul>



<h2 class="wp-block-heading">Summary</h2>



<p>If Dell WD19/WD19S firmware updates fail on Proxmox/Debian during the <em>Erasing…</em> stage, in most cases it’s enough to disable USB autosuspend temporarily. The script above does that automatically and restores the previous setting afterwards, so your system keeps working normally.</p>
<p>Artykuł <a href="https://soban.pl/dell-wd19s-firmware-update-linux-proxmox-debian-usb-timeout-fix/">Dell WD19/WD19S: firmware update on Proxmox/Debian without USB timeouts (fwupd + autosuspend fix)</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Upgrade Proxmox VE 8.x to 9.0 (Debian 12 to Debian 13) – Step-by-Step with Script</title>
		<link>https://soban.pl/how-to-upgrade-proxmox-ve-8-x-to-9-0-debian-12-to-debian-13-step-by-step-with-script/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Mon, 11 Aug 2025 11:51:58 +0000</pubDate>
				<category><![CDATA[Proxmox]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=644</guid>

					<description><![CDATA[<p>Introduction Proxmox VE 9.0 (based on Debian 13 &#8220;Trixie&#8221;) has been released, and it brings updated packages, a new kernel, and improved stability. This guide will walk you through the in-place upgrade from Proxmox VE 8.4.x (Debian 12 &#8220;Bookworm&#8221;) to Proxmox VE 9.0. The process will be automated using a ready-made upgrade script that: Download [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/how-to-upgrade-proxmox-ve-8-x-to-9-0-debian-12-to-debian-13-step-by-step-with-script/">How to Upgrade Proxmox VE 8.x to 9.0 (Debian 12 to Debian 13) – Step-by-Step with Script</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://soban.pl/wp-content/uploads/2025/08/image.png" alt="" class="wp-image-648" style="width:416px;height:auto" srcset="https://soban.pl/wp-content/uploads/2025/08/image.png 1024w, https://soban.pl/wp-content/uploads/2025/08/image-300x300.png 300w, https://soban.pl/wp-content/uploads/2025/08/image-150x150.png 150w, https://soban.pl/wp-content/uploads/2025/08/image-768x768.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Introduction</h2>



<p>Proxmox VE 9.0 (based on Debian 13 &#8220;Trixie&#8221;) has been released, and it brings updated packages, a new kernel, and improved stability. This guide will walk you through the <strong>in-place upgrade</strong> from Proxmox VE 8.4.x (Debian 12 &#8220;Bookworm&#8221;) to Proxmox VE 9.0.</p>



<p>The process will be automated using a ready-made upgrade script that:</p>



<ul class="wp-block-list">
<li>Checks your current version</li>



<li>Runs the <code>pve8to9</code> pre-upgrade check</li>



<li>Backs up your current APT sources</li>



<li>Updates repositories from Bookworm to Trixie</li>



<li>Performs a full dist-upgrade</li>



<li>Logs all changes before and after the upgrade</li>
</ul>



<h2 class="wp-block-heading">Download and run the upgrade script</h2>



<p>You can download the ready upgrade script directly from our server, make it executable, and run it:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">wget https://soban.pl/bash/upgrade-pve8-to-9.sh -O /root/upgrade-pve8-to-9.sh
chmod +x /root/upgrade-pve8-to-9.sh
LOGF="/root/pve8to9.$(date +%F-%H%M%S).nohup.log"; nohup env NO_REBOOT=0 SKIP_PRECHECK=0 /root/upgrade-pve8-to-9.sh &gt; "$LOGF" 2&gt;&amp;1 &amp; echo $! &gt;/run/pve8to9.pid
tail -f "$LOGF"</pre></div>



<p>If you lose connection (which can happen during a Proxmox upgrade), you can follow the logs with:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">tail -f /root/pve-upgrade-latest.log</pre></div>



<p>Be patient and wait for the script to finish — it may take some time.</p>



<h2 class="wp-block-heading">Full script source</h2>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">#!/bin/bash
# Proxmox VE 8 -&gt; 9 in-place upgrade (Debian 12 "bookworm" -&gt; Debian 13 "trixie")
# Hardened: nuke/lock Enterprise repo, move backups OUT of APT dir, ensure single no-sub,
# robust pve8to9 detection/installation, switch to trixie, non-interactive upgrade, post-boot check.
set -euo pipefail

LOG="/root/pve-upgrade-$(date +%Y%m%d-%H%M%S).log"
SINK="/etc/apt/disabled-sources"        # OUTSIDE of APT scan path
APT_BACKUP_DIR="/root/apt-sources-backup-$(date +%Y%m%d-%H%M%S)"
NO_REBOOT="${NO_REBOOT:-0}"
FORCE_UPGRADE="${FORCE_UPGRADE:-0}"
SKIP_PRECHECK="${SKIP_PRECHECK:-0}"

# Ensure sane PATH for non-interactive shells
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH:-}"
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none
export UCF_FORCE_CONFFOLD=1

shopt -s nullglob

msg() { echo "$*" | tee -a "$LOG"; }
die() { echo "ERROR: $*" | tee -a "$LOG"; exit 1; }
ts()  { date +%F-%H%M%S; }

sink() { # move file out of sources.list.d safely
  local f="$1" base
  [[ -e "$f" ]] || return 0
  base="$(basename "$f")"
  mkdir -p "$SINK"
  mv -f "$f" "$SINK/$base.bak.$(ts)"
}

divert_add() {
  local p="$1"
  if ! dpkg-divert --list | grep -Fq "diversion of $p"; then
    dpkg-divert --quiet --local --rename --add "$p" || true
  fi
  rm -f "$p" || true
}

cleanup_nonlist_sources() {
  mkdir -p "$SINK"
  find /etc/apt/sources.list.d -maxdepth 1 -type f \
    ! -name '*.list' ! -name '*.sources' \
    -exec mv -f {} "$SINK"/ \; || true
}

# STRICT verify: only fail on ACTIVE enterprise refs
verify_no_enterprise() {
  local bad=0
  # 1) Active lines in *.list (not commented)
  if grep -RIsn '^[[:space:]]*deb[[:space:]].*enterprise\.proxmox\.com' /etc/apt/sources.list /etc/apt/sources.list.d 2&gt;/dev/null; then
    bad=1
  fi
  # 2) Deb822 .sources that mention enterprise AND are effectively enabled
  while IFS= read -r -d '' f; do
    if grep -qi 'enterprise\.proxmox\.com' "$f"; then
      # treat missing Enabled as enabled, only "Enabled: no" is safe
      if ! grep -qi '^[[:space:]]*Enabled:[[:space:]]*no[[:space:]]*$' "$f"; then
        echo "[VERIFY] Enabled enterprise in: $f" | tee -a "$LOG"
        bad=1
      fi
    fi
  done &lt; &lt;(find /etc/apt/sources.list.d -maxdepth 1 -type f -name '*.sources' -print0 2&gt;/dev/null)
  (( bad == 0 )) || die "Enterprise repo still detected. Clean failed."
}

# Disabled deb822 stub WITHOUT enterprise domain (so greps never trip)
write_disabled_enterprise_sources() {
  cat &gt; /etc/apt/sources.list.d/pve-enterprise.sources &lt;&lt;'EOF'
Types: deb
URIs: https://example.invalid/proxmox           # placeholder to avoid enterprise domain
Suites: trixie
Components: pve-enterprise
Enabled: no
EOF
  chmod 0644 /etc/apt/sources.list.d/pve-enterprise.sources
}

# --------- FIXED: robust locator for pve8to9 + debug ----------
locate_pve8to9() {
  hash -r 2&gt;/dev/null || true
  local tool=""
  tool="$(type -P pve8to9 2&gt;/dev/null || true)"
  [[ -z "$tool" ]] &amp;&amp; tool="$(command -v pve8to9 2&gt;/dev/null || true)"
  [[ -z "$tool" &amp;&amp; -x /usr/bin/pve8to9 ]] &amp;&amp; tool="/usr/bin/pve8to9"
  [[ -z "$tool" &amp;&amp; -x /usr/sbin/pve8to9 ]] &amp;&amp; tool="/usr/sbin/pve8to9"
  [[ -z "$tool" ]] &amp;&amp; tool="$(/usr/bin/which pve8to9 2&gt;/dev/null || true)"
  if [[ -z "$tool" ]] &amp;&amp; command -v dpkg &gt;/dev/null 2&gt;&amp;1; then
    local cand
    cand="$(dpkg -L pve-manager 2&gt;/dev/null | grep -E '/pve8to9$' || true)"
    [[ -n "$cand" &amp;&amp; -x "$cand" ]] &amp;&amp; tool="$cand"
  fi
  echo "$tool"
}

run_pve8to9_precheck() {
  [[ "$SKIP_PRECHECK" == "1" ]] &amp;&amp; { msg "SKIP_PRECHECK=1 set — skipping pve8to9."; return 0; }

  msg "Running pve8to9 --full precheck..."
  msg "PATH=$PATH"
  type -a pve8to9 2&gt;&amp;1 | sed 's/^/[type] /' | tee -a "$LOG" || true
  [[ -e /usr/bin/pve8to9 ]] &amp;&amp; ls -l /usr/bin/pve8to9 | sed 's/^/[ls] /' | tee -a "$LOG" || true

  local tool; tool="$(locate_pve8to9)"

  if [[ -z "$tool" ]]; then
    msg "pve8to9 not found — attempting to ensure 'pve-manager' is installed..."
    apt-get update -y &gt;&gt; "$LOG" 2&gt;&amp;1 || true
    apt-get install -y pve-manager &gt;&gt; "$LOG" 2&gt;&amp;1 || true
    cleanup_nonlist_sources; verify_no_enterprise
    hash -r 2&gt;/dev/null || true
    tool="$(locate_pve8to9)"
  fi

  if [[ -z "$tool" ]]; then
    msg "pve8to9 still not available on this system. Continuing without precheck."
    return 0
  fi

  msg "pve8to9 found at: $tool"
  local tmp rc
  tmp="$(mktemp)"
  set +e
  "$tool" --full | tee -a "$LOG" | tee "$tmp" &gt;/dev/null
  rc=${PIPESTATUS[0]}
  set -e
  if grep -qE 'FAILURES:\s*[1-9]+' "$tmp"; then
    rm -f "$tmp"
    die "pve8to9 reported FAILURES. Check log above."
  fi
  rm -f "$tmp"
  msg "pve8to9 executed (rc=$rc). No FAILURES."
}
# ---------------------------------------------------------------

# ----- header / live log hint -----
echo "== Proxmox VE 8 -&gt; 9 upgrade started: $(date) ==" | tee -a "$LOG"
echo "$$" &gt; /run/pve8to9.pid
ln -sfn "$LOG" /root/pve-upgrade-latest.log
echo "Live log: tail -f /root/pve-upgrade-latest.log" | tee -a "$LOG"
echo "If started via nohup, also watch its file (example: /root/pve8to9.&lt;ts&gt;.nohup.log)" | tee -a "$LOG"

# 0) PRE-NUKE ENTERPRISE + move backups OUT of APT dir
msg "[PRE-NUKE] Backup APT lists and clean directory..."
mkdir -p "$APT_BACKUP_DIR"
cp -a /etc/apt/sources.list "$APT_BACKUP_DIR"/ 2&gt;/dev/null || true
cp -a /etc/apt/sources.list.d "$APT_BACKUP_DIR"/ 2&gt;/dev/null || true
cleanup_nonlist_sources

# Remove any *.sources referencing Enterprise
for s in /etc/apt/sources.list.d/*.sources; do
  [[ -f "$s" ]] || continue
  grep -qi 'enterprise\.proxmox\.com' "$s" &amp;&amp; { msg " -&gt; removing: $s"; sink "$s"; }
done
# Remove typical filenames
sink /etc/apt/sources.list.d/pve-enterprise.sources
sink /etc/apt/sources.list.d/pve-enterprise.list

# For *.list with Enterprise: comment lines or remove if Enterprise-only
for l in /etc/apt/sources.list.d/*.list; do
  [[ -f "$l" ]] || continue
  if grep -qi 'enterprise\.proxmox\.com' "$l"; then
    if awk 'BEGIN{IGNORECASE=1} /^[[:space:]]*deb/ &amp;&amp; $0 !~ /enterprise\.proxmox\.com/ {ok=1} END{exit ok?0:1}' "$l"; then
      msg " -&gt; commenting Enterprise lines in: $l"
      sed -ri 's|^\s*deb\s+https?://enterprise\.proxmox\.com|#DISABLED-BY-SCRIPT &amp;|I' "$l"
    else
      msg " -&gt; removing Enterprise-only list: $l"
      sink "$l"
    fi
  fi
done

# Comment Enterprise in main sources.list
[[ -f /etc/apt/sources.list ]] &amp;&amp; sed -ri 's|^\s*deb\s+https?://enterprise\.proxmox\.com|#DISABLED-BY-SCRIPT &amp;|I' /etc/apt/sources.list || true

# Diversions + disabled deb822 file (with example.invalid), then re-clean any .distrib/.bak
divert_add /etc/apt/sources.list.d/pve-enterprise.list
divert_add /etc/apt/sources.list.d/pve-enterprise.sources
write_disabled_enterprise_sources
cleanup_nonlist_sources
verify_no_enterprise

# 1) Sanity checks
if [[ $EUID -ne 0 ]]; then die "Run as root."; fi
if ! command -v pveversion &gt;/dev/null 2&gt;&amp;1; then die "Not a Proxmox VE host."; fi
CUR_VER_RAW="$(pveversion || true)"; msg "Current pveversion: $CUR_VER_RAW"
if ! echo "$CUR_VER_RAW" | grep -qE 'pve-manager/8\.'; then
  msg "Expected Proxmox 8.x. Detected: $CUR_VER_RAW"
  [[ "$FORCE_UPGRADE" == "1" ]] || die "Set FORCE_UPGRADE=1 to override."
fi

# BEFORE snapshot
{
  echo; echo "===== BEFORE UPGRADE ====="; date
  echo "# uname -a"; uname -a || true
  echo; echo "# pveversion"; pveversion || true
  echo; echo "# qm list"; qm list || true
  echo; echo "# pct list"; pct list || true
} &gt;&gt; "$LOG" 2&gt;&amp;1

# 2) pve8to9 precheck (robust)
run_pve8to9_precheck

# 3) Keyring + initial apt refresh
apt-get update -y &gt;&gt; "$LOG" 2&gt;&amp;1 || true
apt-get install -y proxmox-archive-keyring &gt;&gt; "$LOG" 2&gt;&amp;1 || true
verify_no_enterprise
cleanup_nonlist_sources

# 4) Switch bookworm -&gt; trixie
msg "Switching Debian repositories: bookworm -&gt; trixie ..."
sed -i 's/bookworm/trixie/g' /etc/apt/sources.list || true
find /etc/apt/sources.list.d -maxdepth 1 -type f -exec sed -i 's/bookworm/trixie/g' {} \; || true

# 5) Ensure single no-subscription entry
sed -ri '/download\.proxmox\.com\/debian\/pve.*pve-no-subscription/s/^/#DUPLICATE-BY-SCRIPT /' /etc/apt/sources.list || true
for l in /etc/apt/sources.list.d/*.list; do
  [[ -f "$l" ]] || continue
  [[ "$l" == "/etc/apt/sources.list.d/pve-no-subscription.list" ]] &amp;&amp; continue
  sed -ri '/download\.proxmox\.com\/debian\/pve.*pve-no-subscription/s/^/#DUPLICATE-BY-SCRIPT /' "$l" || true
done
cat &gt; /etc/apt/sources.list.d/pve-no-subscription.list &lt;&lt;'EOF'
deb http://download.proxmox.com/debian/pve trixie pve-no-subscription
EOF
chmod 0644 /etc/apt/sources.list.d/pve-no-subscription.list

verify_no_enterprise
cleanup_nonlist_sources

# 6) Full non-interactive upgrade
msg "Running apt-get update + non-interactive upgrade/dist-upgrade..."
TMPU="$(mktemp)"
apt-get update 2&gt;&amp;1 | tee -a "$LOG" | tee "$TMPU" &gt;/dev/null
if grep -q 'enterprise\.proxmox\.com' "$TMPU"; then rm -f "$TMPU"; die "APT tried to reach Enterprise during update."; fi
rm -f "$TMPU"

apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y | tee -a "$LOG"
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade -y | tee -a "$LOG"

# Second cleanup pass
cleanup_nonlist_sources

apt-get autoremove -y | tee -a "$LOG" || true
apt-get update -y &gt;&gt; "$LOG" 2&gt;&amp;1 || true

# 7) One-shot post-boot verification
POST_SH="/root/pve-postcheck.sh"
POST_SVC="/etc/systemd/system/pve-upgrade-postcheck.service"
cat &gt; "$POST_SH" &lt;&lt;'EOS'
#!/bin/bash
set -euo pipefail
LOG_FILE="/root/pve-upgrade-post-$(date +%Y%m%d-%H%M%S).log"
{
  echo "===== AFTER UPGRADE (first boot) ====="; date
  echo "# uname -a"; uname -a || true
  echo; echo "# pveversion"; pveversion || true
  echo; echo "# apt policy (trixie check)"; apt-cache policy | sed -n '1,120p' || true
} &gt;&gt; "$LOG_FILE" 2&gt;&amp;1
systemctl disable --now pve-upgrade-postcheck.service &gt;/dev/null 2&gt;&amp;1 || true
rm -f /root/pve-postcheck.sh
EOS
chmod +x "$POST_SH"
cat &gt; "$POST_SVC" &lt;&lt;'EOS'
[Unit]
Description=Proxmox upgrade post-check (one-shot)
After=multi-user.target pvedaemon.service pve-cluster.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash /root/pve-postcheck.sh
[Install]
WantedBy=multi-user.target
EOS
systemctl daemon-reload
systemctl enable pve-upgrade-postcheck.service &gt;&gt; "$LOG" 2&gt;&amp;1 || true

# 8) Pre-reboot snapshot
{
  echo; echo "===== PRE-REBOOT SNAPSHOT ====="; date
  echo "# Installed pve kernels:"; dpkg -l | grep -E '^ii\s+pve-kernel' | sort -V || true
} &gt;&gt; "$LOG" 2&gt;&amp;1

msg "Upgrade phase completed. Log: $LOG"
if [[ "$NO_REBOOT" == "1" ]]; then
  msg "NO_REBOOT=1 set — skipping reboot. Please reboot manually."
else
  msg "Rebooting now to complete the upgrade..."
  sleep 3
  reboot
fi</pre></div>



<p>Below is the full content of the script for reference. It is recommended to download the latest version from the link above to ensure you have the most up-to-date fixes.</p>



<h2 class="wp-block-heading">Post-upgrade verification</h2>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">pveversion</pre></div>


<p>Expected output should look like:</p>
<p>pve-manager/9.x.x/xxxxxxxx (running kernel: 6.x.x-x-pve)<br />Check the running kernel version:</p>


<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">uname -a</pre></div>


<p>Review the upgrade log to confirm no errors occurred:</p>


<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">less /root/pve-upgrade-*.log</pre></div>


<p>If you used the post-check service created by the script, you can view its results:</p>


<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">less /root/pve-upgrade-post-*.log</pre></div>
<p>Artykuł <a href="https://soban.pl/how-to-upgrade-proxmox-ve-8-x-to-9-0-debian-12-to-debian-13-step-by-step-with-script/">How to Upgrade Proxmox VE 8.x to 9.0 (Debian 12 to Debian 13) – Step-by-Step with Script</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Dynamic Tmux Window Titles with SSH and Hostname</title>
		<link>https://soban.pl/dynamic-tmux-window-titles-with-ssh-and-hostname/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Tue, 15 Apr 2025 14:55:56 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<category><![CDATA[tmux]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=629</guid>

					<description><![CDATA[<p>Want your Tmux window titles to automatically show the hostname you connect to via SSH — and restore the local name after you disconnect? This guide will walk you through setting that up step by step. 1. Tmux configuration – ~/.tmux.conf In your Tmux configuration file, set the default shell command to a custom Bash [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/dynamic-tmux-window-titles-with-ssh-and-hostname/">Dynamic Tmux Window Titles with SSH and Hostname</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://soban.pl/wp-content/uploads/2025/04/image-1.png" alt="" class="wp-image-631" style="width:455px;height:auto" srcset="https://soban.pl/wp-content/uploads/2025/04/image-1.png 1024w, https://soban.pl/wp-content/uploads/2025/04/image-1-300x300.png 300w, https://soban.pl/wp-content/uploads/2025/04/image-1-150x150.png 150w, https://soban.pl/wp-content/uploads/2025/04/image-1-768x768.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><br>Want your Tmux window titles to automatically show the hostname you connect to via SSH — and restore the local name after you disconnect? This guide will walk you through setting that up step by step.</p>



<h2 class="wp-block-heading">1. Tmux configuration – ~/.tmux.conf</h2>



<p>In your Tmux configuration file, set the default shell command to a custom Bash init file (<code>.bash_tmux</code>) that will handle window title updates.</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">set-option -g default-command 'bash --rcfile ~/.bash_tmux'</pre></div>



<h2 class="wp-block-heading">2. Bash init script – ~/.bash_tmux</h2>



<p>This file runs at shell startup inside Tmux. It sets the window name to your local hostname and overrides the <code>ssh</code> command to change the window title dynamically.</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">#!/bin/bash
# ~/.bash_tmux
# Custom Bash init file for Tmux sessions with dynamic tab naming

# Override the default ssh command to dynamically rename the Tmux window
ssh() {
  if [ -n "$TMUX" ]; then
    # Loop through arguments to find the target host (first non-flag argument)
    for arg in "$@"; do
      if [[ "$arg" != -* ]]; then
        if [[ "$arg" == *@* ]]; then
          host="${arg#*@}"  # extract host from user@host
        else
          host="$arg"
        fi
        break
      fi
    done

    # Strip any trailing junk or whitespace
    host="$(echo "$host" | cut -d' ' -f1)"

    # Rename the Tmux window to the SSH target
    [ -n "$host" ] &amp;&amp; tmux rename-window "$host"

    # Save the local hostname to restore later
    local_host="$(hostname -s)"

    # Run the actual SSH command
    command ssh "$@"

    # Restore the original window name after logout
    tmux rename-window "$local_host"
  else
    # Not in Tmux — just run ssh normally
    command ssh "$@"
  fi
}

# Load the user's regular bash configuration
source ~/.bashrc

# On shell start, if in Tmux, set the window name to the current hostname
if [ -n "$TMUX" ]; then
  tmux rename-window "$(hostname -s)"
fi</pre></div>



<h2 class="wp-block-heading">3. Reload Tmux config without restarting</h2>



<p>To apply the changes without restarting the Tmux session, run the following:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">tmux source-file ~/.tmux.conf</pre></div>



<p>To manually reload the current shell with the new <code>.bash_tmux</code> configuration:</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">exec bash --rcfile ~/.bash_tmux</pre></div>



<h2 class="wp-block-heading">4. Final result</h2>



<ul class="wp-block-list">
<li>New Tmux windows automatically show the local hostname</li>



<li>When connecting via SSH, the window is renamed to the remote host</li>



<li>When disconnecting, the original local name is restored</li>
</ul>



<p>Clean, readable, and perfect for sysadmins, devops engineers, and Tmux lovers who appreciate automatic order in their terminal tabs 💪</p>
<p>Artykuł <a href="https://soban.pl/dynamic-tmux-window-titles-with-ssh-and-hostname/">Dynamic Tmux Window Titles with SSH and Hostname</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The most important Linux commands that every user should know</title>
		<link>https://soban.pl/the-most-important-linux-commands-that-every-user-should-know/</link>
		
		<dc:creator><![CDATA[soban]]></dc:creator>
		<pubDate>Thu, 20 Feb 2025 10:56:30 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://soban.pl/?p=627</guid>

					<description><![CDATA[<p>The Linux system is a powerful tool that offers users tremendous flexibility and control over their working environment. However, to fully harness its potential, it is worth knowing the key commands that are essential for both beginners and advanced users. In this article, we will present and discuss the most important Linux commands that every [&#8230;]</p>
<p>Artykuł <a href="https://soban.pl/the-most-important-linux-commands-that-every-user-should-know/">The most important Linux commands that every user should know</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1017" height="1024" src="https://soban.pl/wp-content/uploads/2025/02/image-4-1017x1024.png" alt="" class="wp-image-625" style="width:511px;height:auto" srcset="https://soban.pl/wp-content/uploads/2025/02/image-4-1017x1024.png 1017w, https://soban.pl/wp-content/uploads/2025/02/image-4-298x300.png 298w, https://soban.pl/wp-content/uploads/2025/02/image-4-150x150.png 150w, https://soban.pl/wp-content/uploads/2025/02/image-4-768x774.png 768w, https://soban.pl/wp-content/uploads/2025/02/image-4.png 1105w" sizes="auto, (max-width: 1017px) 100vw, 1017px" /></figure>



<p>The Linux system is a powerful tool that offers users tremendous flexibility and control over their working environment. However, to fully harness its potential, it is worth knowing the key commands that are essential for both beginners and advanced users. In this article, we will present and discuss the most important Linux commands that every user should know.</p>



<h2 class="wp-block-heading">1. Basic Navigation Commands</h2>



<ul class="wp-block-list">
<li><code>pwd</code> &#8211; Displays the current directory path you are in:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">pwd</pre></div>



<li><code>ls</code> &#8211; Lists the contents of a directory. You can use the <code>-l</code> option for a detailed view or <code>-a</code> to show hidden files:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">ls -a</pre></div>



<li><code>cd</code> &#8211; Changes the directory. For example, <code>cd /home/user</code> will move you to the <code>/home/user</code> directory:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cd ~</pre></div>



<li><code>mkdir</code> &#8211; Creates a new directory:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">mkdir projects</pre></div>



<li><code>rmdir</code> &#8211; Removes an empty directory:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">rmdir old_files</pre></div>
</ul>



<h2 class="wp-block-heading">2. File Management</h2>



<ul class="wp-block-list">
<li><code>cp</code> &#8211; Copies files or directories:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">cp document.txt new_directory/</pre></div>



<li><code>mv</code> &#8211; Moves or renames files/directories:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">mv file.txt /home/user/new_directory/</pre></div>



<li><code>rm</code> &#8211; Removes files or directories. Use the <code>-r</code> option to remove a directory with its contents:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">rm -r old_data</pre></div>



<li><code>touch</code> &#8211; Creates an empty file or updates the modification time of an existing file:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">touch report.txt</pre></div>
</ul>



<h2 class="wp-block-heading">3. Process Management</h2>



<ul class="wp-block-list">
<li><code>ps</code> &#8211; Displays currently running processes. Use the <code>-aux</code> option to see all processes:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">ps -aux</pre></div>



<li><code>top</code> &#8211; Displays a dynamic list of processes in real time:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">top</pre></div>



<li><code>kill</code> &#8211; Stops a process by its ID:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">kill 1234</pre></div>



<li><code>bg</code> and <code>fg</code> &#8211; Manage background and foreground processes:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">fg</pre></div>
</ul>



<h2 class="wp-block-heading">4. User and Permission Management</h2>



<ul class="wp-block-list">
<li><code>sudo</code> &#8211; Allows a command to be executed with administrator privileges:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">sudo apt update</pre></div>



<li><code>chmod</code> &#8211; Changes permissions for files/directories:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">chmod 755 script.sh</pre></div>



<li><code>chown</code> &#8211; Changes the owner of a file/directory:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">chown admin:admin file.txt</pre></div>



<li><code>useradd</code> and <code>userdel</code> &#8211; Adds and removes users:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">useradd janek</pre></div>
</ul>



<h2 class="wp-block-heading">5. Networking and Communication</h2>



<ul class="wp-block-list">
<li><code>ping</code> &#8211; Checks the connection with another host:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">ping 192.168.1.1</pre></div>



<li><code>ifconfig</code> &#8211; Displays information about network interfaces:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">ifconfig</pre></div>



<li><code>ssh</code> &#8211; Connects remotely to another computer:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">ssh user@192.168.1.2</pre></div>



<li><code>scp</code> &#8211; Copies files over SSH:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">scp file.txt user@host:/home/user/</pre></div>
</ul>



<h2 class="wp-block-heading">6. Command Usage Examples</h2>



<p>Below is an example of using several discussed commands:</p>



<ul class="wp-block-list">
<li><code>chmod</code> &#8211; Changes permissions for files/directories:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">chmod 755 script.sh</pre></div>



<li><code>chown</code> &#8211; Changes the owner of a file/directory:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">chown admin:developers logs.txt</pre></div>



<li><code>useradd</code> and <code>userdel</code> &#8211; Adds and removes users:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">useradd janek</pre></div>
</ul>



<h2 class="wp-block-heading">7. Disk and File System Management</h2>



<ul class="wp-block-list">
<li><code>df</code> &#8211; Displays information about disk space availability:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">df -h</pre></div>



<li><code>du</code> &#8211; Shows the size of files and directories:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">du -sh documents</pre></div>



<li><code>mount</code> &#8211; Mounts a file system:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">mount /dev/sdb1 /mnt/external</pre></div>



<li><code>umount</code> &#8211; Unmounts a file system:</li>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">umount /mnt/external</pre></div>
</ul>



<h2 class="wp-block-heading">8. Searching for Files</h2>



<ul class="wp-block-list">
<li><code>find</code> &#8211; Searches for files in the system:</li>



<li><code>locate</code> &#8211; Quickly searches for files in the system:</li>



<li><code>grep</code> &#8211; Searches for patterns in files:</li>



<li><code>which</code> &#8211; Finds the full path to an executable file:</li>
</ul>



<h2 class="wp-block-heading">9. Communicating with the System</h2>



<ul class="wp-block-list">
<li><code>echo</code> &#8211; Displays text on the screen:</li>



<li><code>cat</code> &#8211; Displays the contents of a file:</li>



<li><code>more</code> &#8211; Displays the contents of a file page by page:</li>



<li><code>less</code> &#8211; Similar to more, but offers more navigation options:</li>



<li><code>man</code> &#8211; Displays the user manual for a command:</li>
</ul>



<h2 class="wp-block-heading">10. Working with Archives</h2>



<ul class="wp-block-list">
<li><code>tar</code> &#8211; Creates or extracts archives:</li>



<li><code>zip</code> &#8211; Creates a ZIP archive:</li>



<li><code>unzip</code> &#8211; Extracts ZIP files:</li>



<li><code>tar -xvzf</code> &#8211; Extracts a TAR.GZ archive:</li>



<li><code>gzip</code> &#8211; Compresses files in .gz format:</li>



<li><code>gunzip</code> &#8211; Extracts .gz files:</li>
</ul>



<h2 class="wp-block-heading">11. System Monitoring</h2>



<ul class="wp-block-list">
<li><code>uptime</code> &#8211; Displays the system uptime and load:</li>



<li><code>dmesg</code> &#8211; Displays system messages related to boot and hardware:</li>



<li><code>iostat</code> &#8211; Shows input/output system statistics:</li>



<li><code>free</code> &#8211; Displays information about RAM:</li>



<li><code>netstat</code> &#8211; Displays information about network connections:</li>



<li><code>ss</code> &#8211; A modern version of netstat, used for monitoring network connections:</li>
</ul>



<h2 class="wp-block-heading">12. Working with System Logs</h2>



<ul class="wp-block-list">
<li><code>journalctl</code> &#8211; Reviews system logs:</li>



<li><code>tail</code> &#8211; Displays the last lines of a file:</li>



<li><code>logrotate</code> &#8211; Automatically manages logs:</li>
</ul>



<h2 class="wp-block-heading">13. Advanced File Operations</h2>



<ul class="wp-block-list">
<li><code>ln</code> &#8211; Creates a link to a file:</li>



<li><code>xargs</code> &#8211; Passes arguments from input to other commands:</li>



<li><code>chmod</code> &#8211; Changes permissions for files/directories:</li>



<li><code>chattr</code> &#8211; Changes file attributes:</li>
</ul>


<p>Linux offers a wide array of commands that allow for complete control over the computer. Key commands such as <code>ls</code>, <code>cd</code>, <code>cp</code>, and <code>rm</code> are used daily to navigate through the file system, manage files, and directories. To effectively master these commands, it&#8217;s best to start with those that are most useful in everyday work. For instance, commands for navigating directories and managing files are fundamental and require practice to become intuitive. Other commands, such as <code>ps</code> for monitoring processes, <code>ping</code> for testing network connections, or <code>chmod</code> for changing permissions, are also worth knowing to fully leverage the power of the Linux system.</p>
<p><!-- /wp:post-content --></p>
<p><!-- wp:paragraph --></p>
<p>To learn effectively, it&#8217;s advisable to start by experimenting with commands in practice. Creating files, directories, copying, and deleting data allows for familiarity with their operation. Over time, it&#8217;s worthwhile to start combining different commands to solve more advanced problems, such as monitoring processes, managing users, or working with system logs. One can also use documentation, such as <code>man</code> or websites, to delve into the details of each command and its options.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Remember, regular use of the terminal allows for learning habits that make handling the Linux system more natural. Frequent use of commands, solving problems, and experimenting with new commands is the best way to master the system and fully utilize it.</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p>Linux is indeed a powerful tool that provides great control over the system&#8230; but remember, don&#8217;t experiment on production! After all, experimenting on a production server is a bit like playing Russian roulette — only with bigger consequences. If you want to feel like a true Linux wizard, always test your commands in a development environment. Only then will you be able to learn from mistakes instead of searching for the cause of several gigabytes of data disappearance. And if you don&#8217;t know what you&#8217;re doing, simply summon your trusty weapon: <code>man</code>!</p>
<p><!-- /wp:paragraph --></p>
<p>Artykuł <a href="https://soban.pl/the-most-important-linux-commands-that-every-user-should-know/">The most important Linux commands that every user should know</a> pochodzi z serwisu <a href="https://soban.pl">soban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
