Xavi.app Operations Manual (outdated)
Prerequisites
-
Ubuntu 24.04 LTS, RHEL, or compatible Linux server instance
-
Domain A record (e.g.,
cockpit.example.com
) pointing to your server -
A non-root user with
sudo
privileges (e.g.,yourusername
) -
Hardware virtualization enabled (VT-x/AMD-V) for VM management
(verify withegrep -c '(vmx|svm)' /proc/cpuinfo
)
Install Cockpit and Extensions (Ubuntu & RHEL)
Cockpit (plus cockpit-machines
for KVM VMs and cockpit-podman
for containers) is in the default repositories of both Ubuntu 24.04 and RHEL 9 / Alma 9. Libvirt and QEMU packages are required for full VM support.
Step |
Ubuntu 24.04 LTS |
RHEL 9 / Alma 9 |
Description |
---|---|---|---|
1 – Refresh repos |
sudo apt update |
sudo dnf update -y |
Update package index |
2 – Install Cockpit |
sudo apt install -y \ cockpit cockpit-machines cockpit-podman |
sudo dnf install -y \ cockpit cockpit-machines cockpit-podman |
Web console, VM module, container module |
3 – Install libvirt / QEMU |
sudo apt install -y \ libvirt-daemon-system qemu-kvm |
sudo dnf install -y \ libvirt qemu-kvm virt-install |
Enables KVM hypervisor support |
4 – Start services |
sudo systemctl enable --now \ cockpit.socket libvirtd |
sudo systemctl enable --now \ cockpit.socket libvirtd |
Launch Cockpit & libvirt immediately |
5 – Open firewall |
# Ubuntu/nftables example sudo nft add rule inet filter input \ tcp dport 9090 accept |
# RHEL / firewalld sudo firewall-cmd --add-service=cockpit sudo firewall-cmd --add-service=cockpit --permanent sudo firewall-cmd --reload |
Allow Cockpit port 9090/TCP (optional) |
6 – Verify |
sudo systemctl status cockpit.socket sudo systemctl status libvirtd |
should showactive (running) |
Access the Cockpit Web Dashboard
-
Open
https://localhost:9090
in your browser (substitute your domain or IP). -
Log in with your sudo-enabled user (root login is disabled in the web UI).
-
Click Turn on administrative access in the sidebar for privileged actions (requires re-entering your password).
Core Features in Cockpit
-
Overview:Monitor system health, CPU/memory usage, and basic configuration.
-
Storage:Manage disks, partitions, and file systems; view I/O stats and logs.
-
Services:Control systemd services and timers (start, stop, enable, etc.).
-
Networking:Configure interfaces, monitor bandwidth, and check logs.
-
Logs:Search and filter logs by severity, date, or source.
-
Accounts:Add, edit, or remove user accounts and groups.
-
Terminal:Access a web-based shell for CLI management.
-
Virtual Machines:Create and manage KVM/QEMU VMs with
cockpit-machines
. -
Podman Containers:Visually manage containers (start, stop, logs) with
cockpit-podman
.
Enable Google Authenticator (TOTP) for Cockpit on Ubuntu 24.04
Why Add MFA?
Cockpit exposes full system-level controls (terminal, VM power-off, package installs, etc.). Adding time-based one-time passwords (TOTP) significantly reduces the risk of compromise if your primary password is leaked.
Prerequisites
-
Sudo-enabled account on the Ubuntu host running Cockpit.
-
Google Authenticator, FreeOTP, or any TOTP-compatible app on your phone.
Step1 — Install Required Packages
sudo apt update sudo apt install -y libpam-google-authenticator libqrencode-dev |
Step2 — Generate Your TOTP Secret & Scratch Codes
google-authenticator -t -d -f -r 3 -R 30 -W -Q UTF8 |
-
Scan the displayed QR code with your authenticator app.
-
Record the fivescratch codesin a safe place—they bypass MFA if you lose the phone.
Step3 — Require MFA for Cockpit via PAM
# Append the Google-Authenticator PAM module to Cockpit's stack sudo bash -c 'echo "auth required pam_google_authenticator.so nullok" >> /etc/pam.d/cockpit' |
Note: Add the linebeforerestarting Cockpit, otherwise existing sessions may be interrupted.
Step4 — Restart Cockpit
sudo systemctl restart cockpit |
Step5 — Log In with MFA
-
Browse to
https://your-server:9090
and sign in with your Linux user credentials. -
When prompted for the verification code, open your authentication app and enter the 6-digit TOTP.
Troubleshooting Tips
-
Locked Out? Log in via SSH and remove the last line from
/etc/pam.d/cockpit
, then restart Cockpit. -
Multiple Admins? Each admin must run
google-authenticator
under their own account. -
Scratch Codes Exhausted? Rerun the command in Step2 to regenerate a new secret.
Publish Cockpit Behind Nginx with Let’s Encrypt
The safest way to expose Cockpit publicly is to place it behind an Nginx reverse-proxy that terminates TLS on ports80/443 and forwards traffic to the local Cockpit service (TCP9090). The high-level workflow is:
-
Install Nginx and the Certbot Nginx plugin.
-
Create atemporaryHTTP-only virtual host (port 80) for
cockpit.example.com
. -
Run
certbot --nginx
to request a certificate & let Certbot update the vhost for SSL. -
Replace the generated
location /
block with the Cockpit reverse-proxy stanza shown below, then reload Nginx.
1. Install Prerequisites
Ubuntu 24.04 |
RHEL 9 / Alma 9 |
---|---|
sudo apt update sudo apt install -y nginx python3-certbot-nginx |
sudo dnf install -y nginx python3-certbot-nginx sudo systemctl enable --now nginx |
2. Create a Minimal Port-80 vHost
Save /etc/nginx/sites-available/cockpit.temp
(Ubuntu) or /etc/nginx/conf.d/cockpit.temp.conf
(RHEL):
server { listen 80; server_name cockpit.example.com; root /var/www/html; # any directory; not used after TLS } |
Enable and test, then reload:
# Ubuntu sudo ln -s /etc/nginx/sites-available/cockpit.temp \ /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx |
3. Obtain the Certificate
sudo certbot --nginx -d cockpit.example.com -m admin@example.com --agree-tos |
-
Certbot inserts a new
server
block withlisten 443 ssl
, certificate paths, and a redirect from HTTP→HTTPS.
4. Add the Cockpit Proxy Stanza
-
Edit the new HTTPS server block (file path as created by Certbot) so that the
location /
looks like this:
location / { proxy_pass https://127.0.0.1:9090; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket support proxy_http_version 1.1; proxy_buffering off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Prevent gzip mangling of ETags (Cockpit bug #5239) gzip off; } |
When finished:
sudo nginx -t && sudo systemctl reload nginx |
5. Firewall / SELinux Notes
-
Ubuntu nftables: ensure
tcp dport {80,443}
areaccept
. -
RHEL firewalld:
sudo firewall-cmd --permanent --add-service=http --add-service=https
thensudo firewall-cmd --reload
. -
If SELinux is enforcing, allow Nginx to proxy:
sudo setsebool -P httpd_can_network_connect 1 |
6. Renewals & Maintenance
Certbot installs a systemd timer that runs twice daily. Verify:
sudo systemctl list-timers | grep certbot |
You can test a dry-run any time:
sudo certbot renew –dry-run |
Secure Web Servers with Let’s Encrypt SSL Certificates (Certbot)
This is a general description of the various command features involved in using the Lets Encrypt Certbot to generate SSL Certificates.
Command |
Description |
---|---|
sudo apt install -y snapd |
Install Snapd package manager |
sudo snap install core; sudo snap refresh core |
Update core snap |
sudo snap install --classic certbot |
Install Certbot |
sudo ln -s /snap/bin/certbot /usr/bin/certbot |
Create symlink for Certbot (if missing) |
sudo certbot certonly --standalone -d example.com -m admin@example.com --agree-tos |
Generate SSL certificate (default configuration) |
sudo cat /etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/ example.com/privkey.pem > cockpit.cert |
Combine certificate and key |
sudo certbot --nginx -d www.example.com -d example.com -m admin@example.com --agree-tos |
Generate SSL certificate for NGINX reverse proxy. (suggested configuration) |
sudo systemctl restart nginx |
Restart nginx to apply the certificate |
sudo certbot renew --dry-run |
Test certificate renewal |
Automate Renewal:Certbot includes a systemd timer, but you can add a cron job for redundancy:
sudo crontab -e # Add: 0 0 * * * /usr/bin/certbot renew --quiet |
Installing Certbot with Nginx Module
For servers running Nginx (e.g., hosting web apps), use Certbot’s Nginx plugin to automate SSL setup for Nginx-hosted domains.
Command |
Description |
---|---|
sudo apt install -y python3-certbot-nginx |
Install Certbot Nginx module |
sudo certbot --nginx -d example.com -d www.example.com |
Configure SSL for Nginx domains |
Run sudo certbot renew
to renew all certificates.
Managing Virtual Machines via Cockpit (KVM/QEMU)
-
Ensure
libvirt-daemon-system
andcockpit-machines
are installed. -
In Cockpit, go to Virtual Machines.
-
ClickC reate New VM and fill in:
-
Name: Ubuntu-VM
-
Installation Source: /path/to/ubuntu.iso
-
OS:Ubuntu 24.04
-
Memory: 4096 MB
-
Storage: 20 GB
-
Start the VM and use the Console tab to install the OS.
-
Manage VM state and resources from the UI.
Troubleshooting: If VMs fail to start, verify hardware virtualization in BIOS and check sudo systemctl status libvirtd
.
Managing Containers with Cockpit-Podman
-
In Cockpit, select Podman Containers.
-
Click Create Container and enter:
-
Name: nginx-test
-
Image: docker.io/library/nginx
-
Port Mapping: 8080 (host) to 80 (container)
-
Click Create and Run, then test at
http://your-server-ip:8080
. -
View logs and manage the container in the UI.
Troubleshooting: If inaccessible, ensure port 8080 is open in your firewall.
Switch to Pure nftables
(replace ufw / iptables wrappers)
Ubuntu 24.04 LTS
# 1 – Install native CLI (kernel modules already present)
sudo apt update
sudo apt install -y nftables
# 2 – Disable UFW if it’s running
sudo ufw disable
sudo systemctl mask ufw
# 3 – (Optional) Remove legacy iptables wrappers
sudo apt purge iptables iptables-persistent
# 4 – Enable nftables so your ruleset loads at boot
sudo systemctl enable --now nftables
RHEL 9 / Alma 9
# Install CLI and start service
sudo dnf install -y nftables
sudo systemctl enable --now nftables
# (Optional) remove iptables compatibility layer
sudo dnf remove iptables iptables-services
Optional Extras
Package | Purpose |
---|---|
conntrack / conntrack-tools |
CLI to view or flush the connection-tracking table. |
nftables-doc |
Offline man-pages and examples. |
python3-nftables |
Python bindings for automated rule generation. |
Key Take-aways
- No extra kernel modules –
nf_conntrack
,nf_nat
, etc., are built into the stock kernel and auto-load on demand. nftables
package = user-space CLI + systemd service; that’s all you install.- Removing
ufw
/iptables
is optional but prevents confusion between legacy wrappers and nativenft
syntax.
Firewall Configuration with nftables
Configure nftables
to allow Cockpit and other services:
Command |
Description |
|
---|---|---|
|
Edit nftables rules |
|
#!/usr/sbin/nft -f ############################################################################### # COMPLETE EXAMPLE NFTABLES CONFIG #─────────────────────────────────────────────────────────────── # • Host is a KVM hypervisor running libvirt’s default NAT network # • Guest subnet: 10.0.0.0/24 (bridge interface: “virbr0”) # • Public IPs : # 203.0.113.2 ← MGMT_IP (SSH + Cockpit + HTTPS for the host) # 203.0.113.3 ← NAT_IP1 (DNAT for multiple guests) # 203.0.113.4 ← NAT_IP2 (DNAT for a single guest) # # Replace the addresses / interface names to suit your environment. ############################################################################### ############################################################################### # FILTER TABLE (inet) – Host firewall, VM isolation, Fail2Ban hook ############################################################################### table inet filter { ############################ Fail2Ban dynamic set ######################### set f2b_blocklist { # Filled by Fail2Ban actions type ipv4_addr comment "Fail2Ban—blocked sources" } chain f2b-chain { # Executes early (priority -1) type filter hook input priority -1; policy accept; ip saddr @f2b_blocklist drop } ########################################################################### chain input { type filter hook input priority 0; policy drop; # ── Hygiene ──────────────────────────────────────────────────────── ct state invalid drop ct state {established,related} accept iif lo accept ip protocol icmp icmp type echo-request accept ip6 nexthdr icmpv6 icmpv6 type echo-request accept # ── Host-level services (SSH/HTTP/HTTPS/Cockpit) ─────────────────── ip daddr 203.0.113.2 tcp dport {22,80,443,9090} accept # ── UDP reflection / amplification guard ─────────────────────────── ip daddr {203.0.113.3,203.0.113.4} udp dport {53,67} drop # ── Public services DNAT → VMs (NAT_IP1) ─────────────────────────── ip daddr 203.0.113.3 tcp dport {23-28,80,443,1935,3306} accept # ── Public services DNAT → single VM (NAT_IP2) ───────────────────── ip daddr 203.0.113.4 tcp dport {22,80,443} accept # ── DNS / DHCP from guests (libvirt NAT) ─────────────────────────── iif "virbr0" udp dport {53,67} accept # ── Default: log (rate-limited) then drop ────────────────────────── log prefix "NFT-INPUT-DROP: " group 1 limit rate 1/second drop } chain forward { type filter hook forward priority 0; policy drop; # Standard conn-tracking ct state invalid drop ct state {established,related} accept # ── Isolate VM 10.0.0.130 from other guests ──────────────────────── ip saddr 10.0.0.130 ip daddr 10.0.0.0/24 iif "virbr0" oif "virbr0" drop ip daddr 10.0.0.130 ip saddr 10.0.0.0/24 iif "virbr0" oif "virbr0" drop # Guest ↔ Guest (except isolated VM) iif "virbr0" oif "virbr0" accept # Guest → Internet iif "virbr0" oif {"bridge0","eno1","eno2"} accept # Internet (post-DNAT) → Guest iif {"bridge0","eno1","eno2"} oif "virbr0" accept # ICMP inside libvirt network ip saddr 10.0.0.0/24 ip protocol icmp accept ip daddr 10.0.0.0/24 accept # Catch-all log prefix "NFT-FORWARD-DROP: " group 1 limit rate 1/second drop } chain output { # Host-originated traffic type filter hook output priority 0; policy accept; } } ############################################################################### # NAT TABLE (ip) – DNAT, SNAT, SYN-flood protection ############################################################################### table ip nat { chain prerouting { type nat hook prerouting priority -100; policy accept; # ───────────────── 1) GLOBAL SYN caps (TLS) ─────────────────────── ip daddr {203.0.113.3,203.0.113.4} tcp dport 443 tcp flags syn \ limit rate over 100/second burst 200 packets \ log prefix "NFT-SYNFLOOD-443-GLOBAL: " drop # ───────────────── 2) Per-source caps for HTTP/HTTPS ────────────── ip daddr 203.0.113.3 tcp dport {80,443} tcp flags syn \ meter syn80_1133 size 10k { ip saddr limit rate over 10/second burst 20 packets } \ log prefix "NFT-SYN-80/443-1133: " limit rate 1/second drop ip daddr 203.0.113.4 tcp dport {80,443} tcp flags syn \ meter syn80_1134 size 10k { ip saddr limit rate over 10/second burst 20 packets } \ log prefix "NFT-SYN-80/443-1134: " limit rate 1/second drop # ───────────────── 2b) Per-source caps for SSH ──────────────────── ip daddr 203.0.113.2 tcp dport 22 tcp flags syn \ meter synssh_host size 10k { ip saddr limit rate over 5/second burst 10 packets } \ log prefix "NFT-SYN-SSH-HOST: " limit rate 1/second drop ip daddr 203.0.113.3 tcp dport 22-28 tcp flags syn \ meter synssh_pub1 size 10k { ip saddr limit rate over 5/second burst 10 packets } \ log prefix "NFT-SYN-SSH-PUB1: " limit rate 1/second drop ip daddr 203.0.113.4 tcp dport 22 tcp flags syn \ meter synssh_pub2 size 10k { ip saddr limit rate over 5/second burst 10 packets } \ log prefix "NFT-SYN-SSH-PUB2: " limit rate 1/second drop # ───────────────── 3) DNAT to internal guests ───────────────────── # NAT_IP1 (203.0.113.3) → Multiple VMs ip daddr 203.0.113.3 tcp dport 23 dnat to 10.0.0.209:22 ip daddr 203.0.113.3 tcp dport 24 dnat to 10.0.0.37:22 ip daddr 203.0.113.3 tcp dport 25 dnat to 10.0.0.215:22 ip daddr 203.0.113.3 tcp dport 26 dnat to 10.0.0.168:22 ip daddr 203.0.113.3 tcp dport 27 dnat to 10.0.0.128:22 ip daddr 203.0.113.3 tcp dport 28 dnat to 10.0.0.45:22 ip daddr 203.0.113.3 tcp dport 80 dnat to 10.0.0.209:80 ip daddr 203.0.113.3 tcp dport 443 dnat to 10.0.0.209:443 ip daddr 203.0.113.3 tcp dport 1935 dnat to 10.0.0.128:1935 ip daddr 203.0.113.3 tcp dport 3306 dnat to 10.0.0.209:3306 # NAT_IP2 (203.0.113.4) → Single VM ip daddr 203.0.113.4 tcp dport {22,80,443} dnat to 10.0.0.130 } chain postrouting { type nat hook postrouting priority 100; policy accept; # SNAT / masquerade – Guests → Internet ip saddr 10.0.0.0/24 oif {"bridge0","eno1","eno2"} snat to 203.0.113.3 ip saddr 10.0.0.130 oif {"bridge0","eno1","eno2"} snat to 203.0.113.4 } } ############################################################################### # END OF FILE ############################################################################### |
Example advanced nftables.conf
Key capabilities: Fail2Ban integration Baseline packet hygiene Host-level management access UDP reflection / amplification guard Public services to multiple guests (NAT IP-1) Public services to a single guest (NAT IP-2) Per-source & global SYN-flood protection Guest network isolation Completely blocks traffic to/from a specific VM (10.0.0.130) from other guests. Inter-guest & guest-Internet forwarding Allows guest-to-guest traffic (except isolated VM) and guest-to-Internet via uplinks. Accepts Internet traffic already DNATed to guests. Guest DHCP/DNS passthrough SNAT / Source NAT Logging & rate-limiting Commented, modular structure |
|
|
Flushes the Ruleset |
|
|
Applythe Ruleset Persistently, is loaded on system boot. |
|
|
Lists the active Ruleset |
|
|
Restart services that modify the nftables.conf |
Install and Configure Fail2Ban on Ubuntu 24.04 & RHEL 9
1. Install Packages
OS / Repo |
Command |
Description |
---|---|---|
Ubuntu 24.04 |
sudo apt update sudo apt install -y fail2ban |
Install Fail2Ban from the main repo |
RHEL 9 / Alma 9 |
sudo dnf install -y epel-release sudo dnf install -y fail2ban |
Enable EPEL and install Fail2Ban |
2. Create jail.local
Enable basic SSH protection and integrate with nftables
:
# Default banning action (e.g. iptables, iptables-new, # iptables-multiport, shorewall, etc) It is used to define # action_* variables. Can be overridden globally or per # section within jail.local file banaction = nftables-block banaction_allports = nftables-block # The simplest action to take: ban only action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] # ban & send an e-mail with whois report to the destemail. action_mw = %(action_)s %(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] # ban & send an e-mail with whois report and relevant log lines # to the destemail. action_mwl = %(action_)s %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"] # # JAILS # [sshd] #mode = normal port = ssh,23,24,25,26,27,28 logpath = %(sshd_log)s backend = %(sshd_backend)s maxretry = 2 findtime = 10m bantime = 1d journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd action = %(action_)s filter = sshd[mode=aggressive] [nftables-synflood] enabled = true filter = nftables-synflood logpath = /var/log/kern.log maxretry = 5 findtime = 300 bantime = 3600 journalmatch = _SYSTEMD_UNIT=nftables.service + PRIORITY=5 action = %(action_mwl)s [nftables-invalid] enabled = true filter = nft-invalid logpath = /var/log/kern.log maxretry = 5 findtime = 60 bantime = 6h journalmatch = _SYSTEMD_UNIT=nftables.service + PRIORITY=5 action = %(action_mwl)s [nftables-udpblock] enabled = true filter = nft-udpblock logpath = /var/log/kern.log maxretry = 10 findtime = 30 bantime = 1h journalmatch = _SYSTEMD_UNIT=nftables.service + PRIORITY=5 action = %(action_mwl)s [cockpit] enabled = true filter = cockpit journalmatch = _SYSTEMD_UNIT=cockpit.service port = 9090 maxretry = 3 findtime = 10m bantime = 12h action = %(action_mwl)s [recidive] enabled = true logpath = /var/log/fail2ban.log journalmatch = _SYSTEMD_UNIT=fail2ban.service + PRIORITY=5 backend = systemd bantime = 4w findtime = 1d maxretry = 3 action = %(action_mwl)s [pam-generic] enabled = true filter = pam-generic logpath = /var/log/auth.log # systemd backend will read journal anyway backend = systemd journalmatch = _SYSTEMD_UNIT=systemd-logind.service maxretry = 5 findtime = 10m bantime = 12h action = %(action_mwl)s |
3. Create /action.d/nftables-block.local
[Definition] actionstart = nft add table inet filter 2>/dev/null || true nft add chain inet filter f2b-chain { type filter hook input priority -1 \; policy accept \; } 2>/dev/null || true nft add set inet filter blocklist { type ipv4_addr \; } 2>/dev/null || true nft add rule inet filter f2b-chain ip saddr @blocklist drop 2>/dev/null || true actionflush = actionstop = nft flush set inet filter blocklist 2>/dev/null || true actioncheck = nft list chain inet filter f2b-chain | grep -q '@blocklist' 2>/dev/null || true actionban = nft add element inet filter blocklist { <ip> } 2>/dev/null || true actionunban = nft delete element inet filter blocklist { <ip> } 2>/dev/null || true [Init] table = filter table_family = inet chain = f2b-chain chain_type = filter chain_hook = input chain_priority = -1 addr_type = ipv4_addr addr_set = blocklist blocktype = drop nftables = nft |
4. Start & Enable the Service
sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd # verify jail is active |
Delayed Restart for Fail2Ban (ensures jails reload after nftables)
On Ubuntu 24.04 we add aone-shotsystemd service that waits until the network and nftables.service
are up, then restarts Fail2Ban 30seconds after boot. This guarantees all persistent bans are re-inserted into the live nftables ruleset on server boot.
1. Create the helper script: /usr/local/bin/restart-fail2ban-delayed.sh
|
Run:
sudo install -m 750 -o root -g root /usr/local/bin/restart-fail2ban-delayed.sh |
2. Create the systemd unit
|
3. Enable and start
|
4. Verify
|
|
Why this matters:
-
fail2ban
starts early in the boot sequence; ifnftables
loads afterward, latent bans are not present in the kernel firewall. -
This service guarantees bans are re-applied after the nftables ruleset is fully loaded.
-
The solution is distro-neutral—works the same on RHEL 9/Alma 9 by copying the same unit and helper script.
Useful Commands
-
sudo fail2ban-client status
– list all active jails. -
sudo fail2ban-client set sshd unbanip <IP>
– manually unban an IP. -
Logs:
/var/log/fail2ban.log
.
Install PHP 8.3-FPM and Essential Modules
Add Repositories (if required)
-
Ubuntu 24.04:8.3 is already in the main archive.
-
RHEL 9:Enable Remi PHP 8.3:
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm sudo dnf module reset php -y sudo dnf module enable php:remi-8.3 -y |
2. Install FPM and Modules
OS |
Command |
---|---|
Ubuntu 24.04 |
sudo apt install -y php8.3-fpm php8.3-{cli,common,mysql,gd,xml,curl,mbstring,zip,intl,imagick,opcache} |
RHEL 9 / Alma 9 |
sudo dnf install -y php-fpm php-{cli,common,mysqlnd,gd,xml,curl,mbstring,zip,intl,imagick,opcache} |
3. Enable & Tune FPM
# Start and enable: sudo systemctl enable --now php-fpm # Performance tuning (Ubuntu path shown): sudo sed -i 's/^;?pm.max_children = .*/pm.max_children = 20/' \ /etc/php/8.3/fpm/pool.d/www.conf sudo systemctl restart php-fpm |
Verify with php -v
and systemctl status php8.3-fpm
.
Install MariaDB 11 and phpMyAdmin
1. Add MariaDB Official Repository
# Ubuntu 24.04 sudo apt install -y software-properties-common curl curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -- --mariadb-server-version=11.5 |
# RHEL 9 / Alma 9 sudo curl -o /etc/yum.repos.d/MariaDB.repo \ https://r.mariadb.com/downloads/mariadb_repo_setup && \ sudo bash /etc/yum.repos.d/MariaDB.repo --mariadb-server-version=11.5 |
2. Install and Secure MariaDB
Command |
Description |
---|---|
sudo apt install -y mariadb-server # Ubuntu sudo dnf install -y MariaDB-server # RHEL |
Install server package |
sudo systemctl enable --now mariadb sudo mysql_secure_installation |
Start service & run security script |
3. Install phpMyAdmin (Manual Deploy)
cd /opt sudo wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz sudo tar xzf phpMyAdmin-*-all-languages.tar.gz sudo mv phpMyAdmin-*-all-languages /var/www/html/phpmyadmin sudo cp /var/www/html/phpmyadmin/config.sample.inc.php \ /var/www/html/phpmyadmin/config.inc.php sudo nano /var/www/html/phpmyadmin/config.inc.php /* set a random 32-char blowfish secret */ sudo chown -R www-data:www-data /var/www/html/phpmyadmin sudo systemctl reload nginx |
-
Download latest release:
-
Create a
config.inc.php
(quick setup): -
Set permissions and reload PHP-FPM / Nginx:
4. (Optional) Protect phpMyAdmin with Basic Auth
# Create password file sudo htpasswd -c /etc/nginx/.htpasswd pmaadmin # In your server block: location /phpmyadmin { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; # …existing PHP-FPM configuration… } |
Quick Reference: Components & Commands
Component / Tool |
Ubuntu 24.04 Install |
RHEL 9 / Alma 9 Install |
Main Config / URL / Menu |
---|---|---|---|
Fail2Ban |
sudo apt install fail2ban |
sudo dnf install epel-release fail2ban |
|
PHP 8.3-FPM |
sudo apt install php8.3-fpm |
sudo dnf install php-fpm |
|
MariaDB 11 |
sudo apt install mariadb-server |
sudo dnf install MariaDB-server |
|
phpMyAdmin |
Download tarball → |
|
|
Cockpit |
sudo apt install cockpit |
sudo dnf install cockpit |
|
Cockpit-Machines |
sudo apt install cockpit-machines |
sudo dnf install cockpit-machines |
“Virtual Machines” menu |
Cockpit-Podman |
sudo apt install cockpit-podman |
sudo dnf install cockpit-podman |
“Podman Containers” menu |
Certbot (stand-alone) |
sudo snap install --classic certbot |
sudo dnf install certbot |
|
Certbot Nginx Module |
sudo apt install python3-certbot-nginx |
sudo dnf install python3-certbot-nginx |
|
Netplan (base) |
sudo apt install netplan.io |
– |
|
Netplan Management Commands (Ubuntu)
-
sudo netplan apply
— apply current YAML configuration. -
sudo netplan try
— test new config & auto-rollback on failure (press Enter to accept). -
sudo netplan generate
— regenerate backend configs (NetworkManager/systemd-networkd) without applying. -
sudo netplan set <path.to.option>=<value>
— change a single value in-place (useful for scripts). -
sudo netplan info
— show renderer backends and version details. -
sudo netplan get
— display the currently combined configuration tree.
Troubleshooting Common Issues
-
VM Fails to Start: Check BIOS virtualization settings and
libvirtd
status. -
Container Not Accessible: Confirm
nftables
allows the mapped port. -
Certificate Issues: Test renewal with
sudo certbot renew –dry-run
and check/var/log/letsencrypt
.