Your RS Computers Debian VPS already has SSH installed. To secure a Debian 13 VPS, start with the login you received, add a separate administrator with an SSH key, check that the key works, then restrict authentication and the firewall. Finish by checking automatic security updates and a recoverable backup. There is no need to reinstall SSH to follow this guide.
We tested the core commands on 11 October 2026 in a fresh Debian 13 container on our Linux lab VPS. The container reported Debian 13.7 and OpenSSH 10.0p2. Key authentication, the effective SSH settings, an nftables input policy and an automatic firewall rollback all formed part of the lab. A container has its own network namespace but shares the host kernel; this was not a test of every cloud image or provider firewall.
Before securing a Debian 13 VPS, keep a way back in
Keep your current SSH session open throughout this procedure. Confirm that you can use the provider's recovery console or ask support how to regain access. Open a second terminal for new login tests. Do not treat an existing SSH session as proof that new sessions will work.
The examples use a root shell for administration. If you signed in with an account that has sudo access, run sudo -i first. Check the existing SSH service and its configured ports:
systemctl is-active ssh
sshd -T | grep -E '^(port|pubkeyauthentication|passwordauthentication|permitrootlogin) '
ss -lntp
active means the service is running. Read the port from the effective configuration and confirm it in the listener list. Do not copy a default port over a custom one. If the service check disagrees with an SSH connection that is clearly working, investigate the image's service or socket setup before restarting anything.
| Checkpoint | Evidence to have before continuing |
|---|---|
| Recovery access | A working console or confirmed recovery procedure, plus your open SSH session |
| Administrator account | A fresh key login and successful sudo authentication |
| SSH restrictions | Valid configuration and a new connection after reloading it |
| Firewall | A rollback timer, then successful new connections through the permitted ports |
This firewall example is for a fresh web VPS using SSH on TCP 22 and a website on TCP 80 and 443. If you already run Docker, a VPN, a control panel or an existing firewall manager, adapt its rules instead of installing this separate policy. Use your actual SSH port if it differs from 22.
As root on the server, install the additional administration tools. SSH is already present:
apt update
apt install -y sudo nftables unattended-upgrades nano
The package manager should finish without errors. If repositories time out, fix the network or mirror problem before continuing. Plan the installation of pending system updates around the services running on the machine.
Create an administrator and install a public key
On your own computer, generate a key if you do not already have one. Choose a passphrase when prompted and do not overwrite an existing key you still need:
ssh-keygen -t ed25519
The public key is the file ending in .pub. Keep the private key on your computer. A key passphrase protects that private file; the server account's password is a different credential. As root on the server, create an account called deploy, give it a strong local password for sudo, and prepare its SSH directory. If the account already exists, use it after checking its role rather than running adduser again:
adduser deploy
usermod -aG sudo deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys
Paste the complete public key as one line. In nano, save with Ctrl+O, confirm the filename with Enter, then exit with Ctrl+X. Do not paste the private key. Then fix ownership and permissions:
chown deploy:deploy /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
From the second terminal on your computer, replace YOUR_SERVER_IP with the server address and connect. If SSH uses a custom port, add -p YOUR_SSH_PORT to the ssh command. Verify the host fingerprint using the provider console before accepting a new host key:
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no deploy@YOUR_SERVER_IP
sudo -v
The SSH options make this a key-only test: a password fallback must not hide a broken key setup. A prompt for the private key's passphrase is fine. Once connected, sudo -v may ask for the deploy account's password and is normally silent on success. Proceed only after both steps work. Our lab used a temporary key and confirmed a new key-only connection and membership in the sudo group.
If the key is rejected, fix that before disabling passwords
From the root session that is still open, inspect the path and recent authentication messages:
namei -l /home/deploy/.ssh/authorized_keys
journalctl -u ssh --since '-15 minutes' --no-pager
| What you see | What to check |
|---|---|
| Permission denied (publickey) | The username, the offered key, and whether its public half is on that account's authorized_keys line |
| Bad ownership or modes in the server log | The home directory must not be writable by other users; .ssh and authorized_keys must have the correct owner and permissions |
| Connection timed out | The address, port, route and any existing firewall; authentication has not started yet |
| Connection refused | The SSH listener and the requested port, or a firewall actively rejecting the connection |
A changed host-key warning needs its own investigation. After a legitimate reinstall, verify the new fingerprint through a trusted recovery channel before updating the client record. Removing the warning without checking the identity of the server defeats that check.
Disable password and direct root SSH login
Run these commands as root in the original session:
cat > /etc/ssh/sshd_config.d/00-vps-hardening.conf <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sshd -t
sshd -T | grep -E '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin) '
A successful sshd -t is silent. Our effective settings reported public-key authentication enabled and the other three options disabled. If those results match your intention, validate once more and reload only if validation succeeds:
sshd -t && systemctl reload ssh
Open a new key-only connection as deploy before closing either working terminal. Password authentication for SSH is now disabled; the account password still serves its separate role for sudo.
OpenSSH generally uses the first value it obtains for a setting, so an earlier configuration or a conditional Match section can affect the result. Inspect the effective configuration for the relevant user and connection if it differs. Do not assume a file was applied just because it exists. The Debian OpenSSH manual documents these settings.
For a configuration containing Match rules, substitute the client's source IP and hostname in this read-only check. The example address is reserved for documentation:
sshd -T -C user=deploy,addr=192.0.2.50,host=client.example \
| grep -E '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin) '
The sshd test-mode documentation explains the connection parameters. We checked this command against the lab configuration. It evaluates the named connection; it does not try to connect to that address.
If the change fails, use your still-open root session to move this newly created drop-in out of sshd_config.d, run sshd -t again and reload SSH. Keep the recovery console available until the new login works.
Apply a firewall with an automatic escape route
First inspect the existing rules as root with nft list ruleset. Stop here if a firewall manager or application already maintains rules. On the fresh VPS, save the following as /root/vps-guard.nft. Keep the filename and table name unchanged for the rollback command:
nano /root/vps-guard.nft
table inet vps_guard {
chain input {
type filter hook input priority 0; policy drop;
iifname "lo" accept
ct state established,related accept
ct state invalid drop
meta l4proto { icmp, ipv6-icmp } accept
udp sport 67 udp dport 68 accept
udp sport 547 udp dport 546 accept
tcp dport { 22, 80, 443 } accept
}
}
This permits established traffic, loopback, ICMP including IPv6 control traffic, DHCP replies and the three TCP services. It does not expose the database port. In the lab, a request from the host to the container still reached port 80, while a test HTTP service on port 9090 became unreachable after applying the table. Outbound and forwarded traffic are not filtered by this table; a router or container host needs a different design. Debian's nftables guide provides the broader context.
Check the syntax, schedule a rollback in three minutes, and apply the file:
nft -c -f /root/vps-guard.nft && \
systemd-run --unit=vps-firewall-rollback --on-active=3m --timer-property=AccuracySec=1s \
/usr/sbin/nft delete table inet vps_guard && \
nft -f /root/vps-guard.nft
The commands are joined with && so a syntax error or failure to schedule the timer stops the sequence before the firewall is applied. Read the result and confirm that the timer was created.
Open a fresh SSH connection from your computer immediately and check the website if one is installed. If you lose new connections, wait for the timer to remove this table and reconnect. Our lab used a five-second timer and confirmed that the test table was removed. The systemd-run manual explains transient timers.
Only after successful external checks, cancel the pending rollback before its deadline. If the timer has already removed the table, repeat the timed application and connection checks before saving it. On this fresh VPS with no other nftables configuration to preserve, back up the package's config if present, install your baseline and enable loading it on boot:
systemctl stop vps-firewall-rollback.timer
test ! -f /etc/nftables.conf || cp -a /etc/nftables.conf /root/nftables.conf.before
install -m 600 /root/vps-guard.nft /etc/nftables.conf
systemctl enable nftables
nft list table inet vps_guard
Do not reload this file repeatedly while editing: nftables can append rules to an existing table. Use a reviewed replacement procedure for later changes. Check boot persistence during a planned reboot when recovery access is available; our lab did not reboot the host VPS.
Enable and inspect automatic updates
As root, set the periodic update switches and run a dry run:
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
EOF
unattended-upgrade --dry-run --debug
Review the allowed origins printed by the dry run and the settings in /etc/apt/apt.conf.d/50unattended-upgrades. This step does not promise automatic updates for every third-party repository. Our fresh lab reported no packages eligible for unattended upgrade after installation. Automatic package updates also do not remove the need to plan kernel reboots and application checks. See Debian's periodic updates guidance.
Check that the scheduled jobs exist, rather than assuming the configuration file alone schedules them:
systemctl list-timers --all apt-daily.timer apt-daily-upgrade.timer --no-pager
On our Debian lab both timers appeared with scheduled runs. Actual times vary because the jobs may include randomized delays. If the list is empty or the timers are disabled, inspect their unit status and the image's update configuration. Review /var/log/unattended-upgrades/ after a scheduled run and keep a separate plan for third-party applications.
Keep the baseline useful after day one
Review listening services with ss -lnt, remove software you do not need, and maintain an off-server backup with a tested restore. When adding a service, decide whether it needs to listen publicly or only on localhost. A database bound to localhost is usually a better starting point than opening its port to the internet.
RS Computers provides KVM VPS hosting in Kosovo, the Netherlands and Ireland. For the next steps, see our backup guide and monitoring guide. These controls reduce common risks, but the applications you install still need their own updates and access rules.
Frequently asked questions
Do I need to install SSH on a new RS Computers Debian VPS?
No. SSH is installed by default on the Debian VPS image. Start with the provided login, check the current service and port, then configure your administrator account and key.
Do SSH keys make Fail2ban unnecessary?
Keys and disabled password login remove password guessing as a route into SSH. Fail2ban can still be useful for reducing repeated unwanted requests or protecting other supported services, but it adds another policy to monitor and does not replace updates or application security.
Should I change the SSH port?
It can reduce routine scan noise, but it does not replace keys, updates or access controls. Test your actual port in both the server firewall and any provider firewall.
Why keep ICMP and IPv6 ICMP working?
They carry useful error and network-control messages. Blocking all of them can break diagnostics and normal network behavior, including IPv6 operation.
Can I paste this firewall into a Docker server?
No. This example is scoped to a fresh web VPS. Docker networking and published ports require a firewall design that accounts for forwarding and Docker's rules.