gotburnout

Hetzner VPS Setup

From a blank server to a secured production-ready machine. Choose how you want to set up your server.

Automatically (AI)
Universal skill for Claude Code, Cursor, Windsurf, and Antigravity.
Manually
14 steps for complete manual control over the process.

Variables Preparation

In the commands below, you will need to substitute your values instead of the curly braces:

  • {username} — the name of your regular user (e.g., dev)
  • {nickname} — a short name for the server for convenience (e.g., hetzner-main)
  • {SERVER_IP} — the public IP address of your new server

1 Creating an SSH Key (Local)

Executed on your computer (Mac or Linux) BEFORE you connect to the server.

Terminal (Local)
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N "" cat ~/.ssh/{nickname}_key.pub

Copy the output of the second command (it starts with ssh-ed25519 ...). This is your public key.

2 Login as Root

Connect to the server using the password Hetzner sent to your email.

Terminal
ssh root@{SERVER_IP}
Hetzner may ask you to change the password. Enter the current password, then the new temporary one twice. If the connection drops after this — just connect again using the new password.

3 System Update

Updating all packages in non-interactive mode (without grub popups).

Root Terminal
apt update && DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt upgrade -y

4 Creating a User with sudo

Working as root is dangerous. We create a regular user and give them administrator privileges.

Root Terminal
useradd -m -s /bin/bash {username} echo "{username}:ВАШ_НОВИЙ_СКЛАДНИЙ_ПАРОЛЬ" | chpasswd usermod -aG sudo {username}

5 SSH Key Deployment

We will write your public key, which you copied in Step 1, to the server.

Root Terminal
mkdir -p /home/{username}/.ssh echo "{PUBLIC_KEY_CONTENT}" > /home/{username}/.ssh/authorized_keys chmod 700 /home/{username}/.ssh chmod 600 /home/{username}/.ssh/authorized_keys chown -R {username}:{username} /home/{username}/.ssh

6 Login Check

MANDATORY CHECKPOINT

Do not close the root session! Open a new terminal window on your PC and try to log in using the key. You can only proceed after a successful login.

New Terminal (Local)
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}

Check if sudo works (the system should ask for the password you set in Step 4 and output "root"):

User Terminal
sudo whoami

7 Firewall (UFW)

Execute all subsequent commands as your new user (with sudo). Setting up the "deny all incoming except SSH, HTTP, and HTTPS" policy.

User Terminal
sudo apt install -y ufw sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow ssh sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw --force enable sudo ufw status

8 Kernel Protection (sysctl)

Applying parameters to protect against network attacks.

User Terminal
sudo tee /etc/sysctl.d/99-security.conf << 'EOF' net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 EOF sudo sysctl -p /etc/sysctl.d/99-security.conf

9 Basic Packages and Time

Accurate time is critical for logs, SSL certificates, and fail2ban.

User Terminal
sudo apt install -y chrony curl wget git unzip net-tools sudo systemctl enable chrony

10 Local SSH Config

Setting up a shortcut on your local PC to connect with a short command ssh {nickname} in the future.

Terminal (Local)
mkdir -p ~/.ssh && touch ~/.ssh/config && chmod 600 ~/.ssh/config cat >> ~/.ssh/config << 'EOF' Host {nickname} HostName {SERVER_IP} User {username} IdentityFile ~/.ssh/{nickname}_key IdentitiesOnly yes EOF

11 Security Check

Verify that the short command from the local PC works and that the basic protections are enabled.

Terminal (Local)
ssh {nickname} # Після успішного входу: sudo ufw status sudo sysctl net.ipv4.conf.all.rp_filter

12 Final Lockdown

We install protection against brute force (fail2ban) and permanently disable password login and root login.

User Terminal
sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF [DEFAULT] bantime = 1h findtime = 10m maxretry = 5 [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 24h JAILEOF sudo systemctl enable fail2ban && sudo systemctl restart fail2ban sudo sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config sudo sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config sudo systemctl restart sshd
Done! The server is fully configured and secured.