All guides
Getting started
VPS
- VPS operating systems
- VPS snapshots and
off-site backups - How to host your own VPN on a VPS with WireGuard
- How to run a Tor relay, bridge or onion service on a VPS
- How to
self-host BTCPay Server on a VPS - How to run a Bitcoin or Monero node on a VPS
Dedicated servers
- Using IPMI and the KVM console on a dedicated server
- Choosing a RAID layout for your dedicated server
Windows RDP
Windows Server 2019 , 2022 or 2025 vsWindows 10 and 11 for RDP- How to connect to a Windows RDP server from any device
GPU servers
Security
On this page
- Install updates and automatic security updates
- Create a sudo user
- Log in with an SSH key
- Disable password and root logins
- Change the SSH port (optional)
- Set up a firewall
- Block brute force with fail2ban
- Keep the clock in sync
- Audit with Lynis
- Back up before you need to
- Notes for Tor relays and VPN servers
- If your server is compromised
A new server receives automated login attempts soon after it goes online. Work through this checklist in order, within the first hour. Commands are for Debian and Ubuntu, with notes for AlmaLinux and Rocky Linux where they differ. Run them as root until your sudo user exists, and replace aliceSERVER_IP
Install updates and automatic security updates
apt update
apt full-upgrade -y
apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
Answer yes in the dialog. It writes /etc/apt/apt.conf.d/20auto-upgrades, and security updates then install daily. To reboot automatically when an update requires it, such as a new kernel, set these lines in /etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
On AlmaLinux and Rocky Linux, install upgrade_type = securityapply_updates = yes/etc/dnf/automatic.conf
dnf upgrade --refresh -y
dnf install -y dnf-automatic
systemctl enable --now dnf-automatic.timer
Reboot if the kernel was updated.
Create a sudo user
Working as root turns every typo into a
apt install -y sudo
adduser alice
usermod -aG sudo alice
On AlmaLinux and Rocky Linux, the admin group is called wheel
useradd -m -G wheel alice
passwd alice
Log in with an SSH key
On your computer, create a key pair protected by a passphrase, copy the public key to the new account, then log in with it and check that sudo works:
ssh-keygen -t ed25519 -C "alice laptop"
ssh-copy-id alice@SERVER_IP
ssh alice@SERVER_IP
sudo -v
On Windows, use the PowerShell command from the getting started guide instead of ssh-copy-id
Disable password and root logins
Continue only once the key login and sudo work for your new user. Create /etc/ssh/sshd_config.d/00-hardening.conf with these lines:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
X11Forwarding no
AllowUsers alice
The 00-sshd_config.dsshd_config50-cloud-init.conf01-permitrootlogin.confAllowUsers
sshd -t
sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|kbdinteractive|allowusers'
systemctl restart ssh
On AlmaLinux and Rocky Linux, the service is called sshdalice
Change the SSH port (optional)
A Port 2222
ufw allow 2222/tcp
systemctl restart ssh
systemctl daemon-reload
systemctl restart ssh.socket
On AlmaLinux and Rocky Linux, SELinux and firewalld must allow the new port as well:
dnf install -y policycoreutils-python-utils
semanage port -a -t ssh_port_t -p tcp 2222
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
systemctl restart sshd
Test the new port from a new terminal before you remove the rule for
ssh -p 2222 alice@SERVER_IP
Set up a firewall
ufw on Debian and Ubuntu
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw limit 22/tcp
ufw allow 443/tcp
ufw enable
ufw status verbose
limit
nftables
For direct control, write your own ruleset to /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid drop
iif "lo" accept
meta l4proto { icmp, ipv6-icmp } accept
tcp dport { 22, 443 } accept
}
}
Check the file, then load it now and at every boot:
nft -c -f /etc/nftables.conf
systemctl enable --now nftables
Use either ufw or your own nftables file, not both. flush ruleset
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
Block brute force with fail2ban
apt install -y fail2ban python3-systemd
Create /etc/fail2ban/jail.localignoreipport
[DEFAULT]
backend = systemd
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 YOUR_IP
[sshd]
enabled = true
port = 22
systemctl enable fail2ban
systemctl restart fail2ban
fail2ban-client status sshd
The systemd/var/log/auth.log
fail2ban-client set sshd unbanip IP_ADDRESS
On AlmaLinux and Rocky Linux, fail2ban comes from EPEL:
dnf install -y epel-release
dnf install -y fail2ban
With
Keep the clock in sync
timedatectl set-ntp true
timedatectl set-timezone UTC
timedatectl
Look for System clock synchronized: yes. If set-ntp
apt install -y systemd-timesyncd
AlmaLinux and Rocky Linux enable chrony by default. Accurate time matters for TLS,
Audit with Lynis
apt install -y lynis
lynis audit system
Lynis checks hundreds of settings and prints warnings, suggestions and a hardening index. Details land in /var/log/lynis.log/var/log/lynis-report.dat
Back up before you need to
Hardening lowers the risk; backups make an incident recoverable. On a VPS, take a snapshot once this checklist is done, and set up encrypted
Notes for Tor relays and VPN servers
Tor relays
- Our guide to running a Tor relay, bridge or onion service has the full setup for each role.
Non-exit relays and bridges only pass encrypted traffic within the Tor network; make that explicit with inExitRelay 0 ./etc/tor/torrc- Exit relays are different: their traffic to websites appears to come from your IP and draws abuse reports. Read the acceptable use policy before you run one. Outbound
port 25 is closed by default. - Install tor from the Tor Project's repository and let unattended-upgrades update it; the Tor relay guide has the exact origin lines for Debian and Ubuntu.
- Open only the ORPort in the firewall, and keep any ControlPort or metrics port on localhost.
- Bandwidth is unmetered under fair use. If you expect sustained high traffic, cap it with
andRelayBandwidthRate , orRelayBandwidthBurst , inAccountingMax .torrc - Run a relay on its own server: relay addresses are public, and many services block them.
WireGuard VPN servers
The full setup, from keys to phone clients, is in how to host your own VPN with WireGuard. In short: open the WireGuard port, enable IP forwarding, allow forwarding only from the tunnel to your public interface (find its name with ip -br addr
ufw allow 51820/udp
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-wireguard.conf
sysctl --system
ufw route allow in on wg0 out on eth0
chmod 600 /etc/wireguard/wg0.conf
- Add NAT for the tunnel's address range, and enable IPv6 forwarding too if you route IPv6.
- Traffic from your VPN users leaves through your server's IP. Spam, scans and attacks they send count as coming from your server under the acceptable use policy, so give access only to people you trust.
- WireGuard itself keeps no connection logs. If you promise users no logs, also check journald and firewall logging.
If your server is compromised
Typical signs: unknown processes using CPU, unexpected outbound traffic, new accounts or SSH keys, or an abuse notice from us.
- Contain it. Stop outgoing attacks first: block outbound traffic in the firewall or shut the server down. We act immediately on attacks from our network under the
zero-tolerance rules of the acceptable use policy, even when a server was hijacked. - Preserve evidence. On a VPS, take a snapshot before you change anything, and copy the logs off the server.
- Investigate with the commands below: logins, open ports, processes, cron jobs, services, root's SSH keys and accounts with user ID 0.
- Rotate every secret that was on the server: passwords, SSH keys (create new ones on a clean machine), access tokens, database passwords and TLS private keys.
- Rebuild. Reinstall from a clean template, restore data from a backup made before the
break-in , apply this checklist, and close the hole the attacker used, such as an outdated plugin, a weak password or an exposed service. - Tell us. On a dedicated or GPU server, reply by ticket to our abuse notice with what you found and fixed, or ask for help.
last -a
ss -tulpn
ps auxf
ls -la /etc/cron.d /var/spool/cron
systemctl list-units --type=service --state=running
cat /root/.ssh/authorized_keys
awk -F: '$3 == 0' /etc/passwd
Dedicated and GPU customers can open a ticket from the client area with the server’s IP address and what they tried. First reply target: under