Proxmox, use harden!

In the wild world of the Internet, Proxmox is vulnerable like a freshly hatched Caterpie. So let's evolve it into a Metapod and harden it!

A default Proxmox VE installation is ready to virtualise, but of course, we want to also increase the security. Because we do not want anybody to touch our Pokeballs without permission!

By default, Proxmox allows root SSH logins and password‑based authentication. For starters, this is fine, but you’re making life easy for attackers who can hammer your login endpoint with brute‑force attempts and break your shell. In this guide, you’ll:

  1. Create a dedicated admin user (so that root stays locked away)
  2. Grant that user password‑less sudo (for seamless automation)
  3. Switch to SSH key‑based authentication (to eliminate password guessing)
  4. Disable root and password logins via a drop‑in SSH config (so settings survive upgrades)

By the end, your Proxmox hypervisor will be hardened like a shiny Metapod.

You can follow each step, or if you trust me, just copy the script at the end, adjust the public key and execute the script to set everything up in seconds.


1. Create a Dedicated Admin User

Instead of logging in as root, we’ll spin up an admin account to own SSH keys and handle elevated actions.

USERNAME="admin"

# Create ‘admin’ if it doesn’t exist
if ! id "$USERNAME" &>/dev/null; then
  echo "[+] Creating user: $USERNAME"
  adduser --disabled-password --gecos "" "$USERNAME"
fi
Why? Root is the foremost target in brute‑force attacks. Hiding it reduces exposure.

2. Install sudo and Grant Password‑less Sudo

We’ll install sudo (if needed) and allow our new user to perform any command without typing a password—ideal for scripting.

# Install sudo if missing
apt update && apt install -y sudo

# Add user to sudo group
usermod -aG sudo "$USERNAME"

# Enable password‑less sudo
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" | tee "/etc/sudoers.d/99_${USERNAME}_nopass"
chmod 440 "/etc/sudoers.d/99_${USERNAME}_nopass"
Why? Automations and cron jobs won’t stall waiting for a password.

3. Enforce SSH Key‑Based Authentication

Replace the placeholder in PUBKEY= with your actual public key, then install it for admin.

PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBexampleyourkeygoeshere user@example.com"

mkdir -p /home/$USERNAME/.ssh
echo "$PUBKEY" > /home/$USERNAME/.ssh/authorized_keys
chown -R $USERNAME:$USERNAME /home/$USERNAME/.ssh
chmod 700 /home/$USERNAME/.ssh
chmod 600 /home/$USERNAME/.ssh/authorized_keys
Why? SSH keys can’t be guessed—and can be revoked or rotated easily.

4. Harden SSH via /etc/ssh/sshd_config.d

We’ll drop in a config file that disables direct root login, turns off passwords completely, and limits access to our admin user.

SSHD_HARDEN_FILE="/etc/ssh/sshd_config.d/harden.conf"

cat <<EOF > "$SSHD_HARDEN_FILE"
PermitRootLogin no
PasswordAuthentication no
AllowUsers $USERNAME
EOF
Why? Keeps your custom settings intact across OpenSSH updates and shrinks your attack surface.

5. Apply and Verify

Reload the SSH service and run through these checks:

systemctl reload sshd

Before logging out, make sure to test the new setup!

ssh admin@<proxmox_ip/hostname>

This should give you the following output:

admin@<proxmox_ip/hostname>: Permission denied (publickey). 

Now use your private key to access the machine:

ssh -i .ssh/prox.key admin@<proxmox_ip/hostname>

Now, try to become root without a password.

sudo su

📝 Complete harden-proxmox.sh Script

Save, edit the PUBKEY line, make executable, then run:

chmod +x harden-proxmox.sh
sudo ./harden-proxmox.sh
#!/bin/bash
set -e

USERNAME="admin"
SSHD_HARDEN_FILE="/etc/ssh/sshd_config.d/harden.conf"

# 1. Create user if missing
if ! id "$USERNAME" &>/dev/null; then
  echo "[+] Creating user: $USERNAME"
  adduser --disabled-password --gecos "" "$USERNAME"
fi

# 2. Install sudo & grant passwordless sudo
apt update && apt install -y sudo
usermod -aG sudo "$USERNAME"
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" | tee "/etc/sudoers.d/99_${USERNAME}_nopass"
chmod 440 "/etc/sudoers.d/99_${USERNAME}_nopass"

# 3. Configure key-based SSH
PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBexampleyourkeygoeshere user@example.com"
mkdir -p /home/$USERNAME/.ssh
echo "$PUBKEY" > /home/$USERNAME/.ssh/authorized_keys
chown -R $USERNAME:$USERNAME /home/$USERNAME/.ssh
chmod 700 /home/$USERNAME/.ssh
chmod 600 /home/$USERNAME/.ssh/authorized_keys

# 4. Harden SSH via sshd_config.d
echo "[+] Writing SSH hardening config to $SSHD_HARDEN_FILE"
cat <<EOF > "$SSHD_HARDEN_FILE"
PermitRootLogin no
PasswordAuthentication no
AllowUsers $USERNAME
EOF

# 5. Reload and done
echo "[+] Reloading sshd..."
systemctl reload sshd
echo "[✔] Proxmox hardening complete."

Now your Proxmox host sits in its Metapod shell 🎉

Happy Coding!

Subscribe to Eduard Schwarzkopf

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe