Cubis Engineers

Server access and security

Replace unsafe defaults with SSH keys, limited identities, a default-deny firewall, and a safe change sequence.

SecurityIntermediateUpdated Aug 13, 2026sshhardeningufwfail2bansudo

Secure access is the first production task. Complete it before deploying an application or placing data on the server.

1. Create and install an SSH key

Run key generation on your workstation:

Terminal
ssh-keygen -t ed25519 -a 64 -C 'you@cubis'
ssh-copy-id root@203.0.113.10
ssh root@203.0.113.10

Protect the private key with a passphrase and never copy it to the server. The .pub file is safe to distribute.

2. Create a named operator

Terminal
adduser deploy
usermod -aG sudo deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/
chown deploy:deploy /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys

Open a second terminal and verify ssh deploy@203.0.113.10 plus sudo -v. Keep the root session open until all access changes work.

3. Harden the SSH daemon

Create an included config instead of rewriting the vendor file:

/etc/ssh/sshd_config.d/10-cubis-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers deploy
Terminal
sudo sshd -t                       # syntax check: no output means valid
sudo systemctl reload ssh          # Ubuntu/Debian service name
ssh -o PreferredAuthentications=publickey deploy@203.0.113.10

Changing the SSH port

A non-default port reduces log noise, not the need for key authentication. If you change it, allow the new port in the cloud firewall and UFW before reloading SSH.

4. Apply a default-deny firewall

Cloud firewalls and host firewalls solve different problems; use both when available.

Terminal
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status numbered

Do not expose database ports such as 5432, 3306, 6379, or 27017 to the public internet. Bind them to loopback, a private interface, or a private network.

5. Reduce brute-force noise

Terminal
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Fail2ban adds protection, but it does not replace SSH keys or a firewall. Check that its SSH rule reads the correct systemd journal or log for your distribution.

6. Keep security updates moving

Terminal
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
systemctl status unattended-upgrades

Define how reboots are scheduled; unattended package installation does not guarantee that a new kernel is running.

Before using the server in production

  • A named human identity can connect with a passphrase-protected key.
  • Root and password SSH login are disabled and verified in a new session.
  • Inbound traffic defaults to deny.
  • Only justified public ports exist in cloud and host firewalls.
  • Application and database processes run without root.
  • Security updates and reboot ownership are defined.
  • Provider console or recovery access was tested.

Record what you changed Save the results of sshd -T, ufw status verbose, and ss -tulpn with the server handoff. Include the update and reboot policy. Never include private keys or secrets.

On this page