RDP Monster

Ubuntu Enable SSH: Install OpenSSH Server and Harden It

Ubuntu Enable SSH: Install OpenSSH Server and Harden It

Enable SSH on Ubuntu: install, start, open the firewall

SSH on Ubuntu comes from the openssh-server package. Ubuntu Server offers to install it during setup and nearly every cloud or VPS image ships with it already listening; Ubuntu Desktop does not install it at all.

1. Install openssh-server

sudo apt update
sudo apt install -y openssh-server

If the package is already there, apt says so and changes nothing. The install also registers a UFW application profile named OpenSSH, used in step 3.

2. Enable and start the service

sudo systemctl enable --now ssh
systemctl status ssh

On Ubuntu the unit is called ssh; sshd is an alias. enable --now starts the daemon now and at every boot. Since Ubuntu 22.10 sshd is socket-activated: ssh.socket owns port 22 and starts ssh.service on the first incoming connection, so a status of inactive (dead) with TriggeredBy: ssh.socket right after install is normal. The port is open. For the wider picture, see listing services with systemctl.

3. Allow SSH through UFW

Ubuntu ships UFW disabled. If you turn it on, allow SSH first; enabling the firewall before the rule exists is the classic way to lock yourself out of a remote machine.

sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status

ufw allow OpenSSH uses the application profile and opens 22/tcp. If you later move sshd, allow the new port with sudo ufw allow 2222/tcp and delete the old rule. Find the server's address with hostname -I.

Connect from Windows, macOS or Linux

Every current desktop operating system has an OpenSSH client built in, and the syntax is identical everywhere:

ssh username@SERVER_IP
ssh -p 2222 username@SERVER_IP      # non-default port
  • Windows 10 and 11: open PowerShell or Windows Terminal and type the command; the OpenSSH client has shipped with Windows since 2018 (version 1809). If ssh is not recognised, add it under Settings > Apps > Optional features.
  • macOS: Terminal, same command.
  • Linux: any terminal; openssh-client is installed by default on Ubuntu.

On the first connection, accept the server's host key fingerprint with yes; it is stored in ~/.ssh/known_hosts and you will be warned if it ever changes. Then type the account password. The next section replaces it with a key.

Switch to key-based authentication

Password logins are what botnets brute-force around the clock; keys make those attempts pointless. Generate an Ed25519 key pair on your own computer, never on the server:

ssh-keygen -t ed25519 -C "laptop-2026"

Accept the default path (~/.ssh/id_ed25519) and set a passphrase; it encrypts the private key on disk, and an SSH agent means you type it once per session. Only the .pub file ever leaves your machine.

Copy the public key to the server

On macOS and Linux, ssh-copy-id does it in one step, using your password one last time:

ssh-copy-id -i ~/.ssh/id_ed25519.pub username@SERVER_IP

The Windows build of OpenSSH does not include ssh-copy-id; pipe the key over from PowerShell instead:

type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh username@SERVER_IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Both methods append the key to that user's ~/.ssh/authorized_keys. Permissions matter: sshd silently ignores the file when ~/.ssh is not mode 700 or authorized_keys is writable by anyone but its owner. From a new terminal, ssh username@SERVER_IP should now log you in without the account password. Do not touch the next section until it does.

Harden sshd_config: no passwords, no root, allow-listed users

Keep your current session open while you edit; if the new configuration breaks something, it is your way back in. /etc/ssh/sshd_config begins with Include /etc/ssh/sshd_config.d/*.conf, and sshd keeps the first value it reads for each keyword, so a drop-in beats anything further down in the main file. And cloud images often ship /etc/ssh/sshd_config.d/50-cloud-init.conf with PasswordAuthentication yes, which is why editing the main file so often appears to do nothing. The fix is a drop-in whose name sorts first:

sudo nano /etc/ssh/sshd_config.d/00-hardening.conf

Paste the following, replacing username with your own login:

PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
AllowUsers username
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2

PermitRootLogin no assumes you have an unprivileged account with sudo rights. If you have been working as root so far, create a sudo user on Linux and copy your key to it before applying the file. Then validate the syntax, reload, and check the values sshd actually uses once all includes are merged, which is what sshd -T prints:

sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -Ei 'passwordauthentication|permitrootlogin|allowusers|port'

Open a second terminal and log in with your key before closing the first one. What each directive does:

DirectiveValueEffect
PasswordAuthenticationnoKeys only; password brute force becomes impossible rather than slow.
KbdInteractiveAuthenticationnoCloses the challenge-response path PAM could use for passwords (formerly ChallengeResponseAuthentication).
PermitRootLoginnoRoot cannot log in over SSH, key or not; use sudo.
AllowUsersyour login(s)Unlisted users are refused before authentication; [email protected]/24 pins a user to a network.
MaxAuthTries3Three failed attempts per connection, then disconnect.
LoginGraceTime30Unauthenticated connections are cut after 30 seconds.
ClientAliveInterval / ClientAliveCountMax300 / 2Probes a quiet client every five minutes and drops it after two unanswered probes; live clients answer automatically.
X11ForwardingnoOff unless you forward graphical applications.

Keepalive has a client side too: ServerAliveInterval 60 in ~/.ssh/config on your own machine stops NAT routers from dropping idle sessions.

Changing the SSH port is not security

Moving sshd off port 22 is popular advice. What it buys you is fewer log lines. Mass scanners sweep all 65,535 ports and find sshd on 2222 within hours; anyone targeting you finds it in seconds with nmap. Keys, no root login, an allow-list and fail2ban are the security; the port is cosmetic. It still helps on a busy server by keeping the authentication log readable; just never count it as a layer of defence.

If you do change it, keep this order: open the new port in UFW, change the port, restart, test from a second terminal, then remove the old rule. Uncomment #Port 22 in /etc/ssh/sshd_config, set the new port, then:

sudo ufw allow 2222/tcp
sudo sshd -t
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket    # Ubuntu 22.10 and later
sudo systemctl restart ssh           # Ubuntu 22.04 and earlier

On socket-activated releases the socket unit, not sshd, decides which port is bound; Ubuntu ships a systemd generator that reads Port from the sshd configuration during daemon-reload and updates ssh.socket. Confirm with sudo ss -tlnp | grep sshd. The guide on checking open ports on Linux explains the output. If sshd is stubbornly still on 22, disable socket activation and let the service bind the port itself: sudo systemctl disable --now ssh.socket && sudo systemctl enable --now ssh.service. Once ssh -p 2222 works from a fresh terminal, run sudo ufw delete allow OpenSSH.

Add fail2ban, and consider two-factor authentication

With passwords disabled, brute force cannot succeed, but each attempt still costs a fork and a log line. fail2ban watches the authentication log and bans addresses that fail repeatedly:

sudo apt install -y fail2ban
sudo nano /etc/fail2ban/jail.local

Put this in the file:

[sshd]
enabled = true
port = ssh
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Never edit jail.conf; it is replaced on upgrades and jail.local overrides it. port = ssh resolves through /etc/services, so write port = 2222 if you moved the daemon. backend = systemd reads the journal directly and works whether or not your image writes /var/log/auth.log. fail2ban-client status sshd lists banned addresses; sudo fail2ban-client set sshd unbanip 203.0.113.7 releases one. By default fail2ban's rules are evaluated before UFW's, so the two coexist.

Two-factor authentication

Where a key plus passphrase is not enough, libpam-google-authenticator adds a time-based code on top of the key: install it, run google-authenticator as the login user, add auth required pam_google_authenticator.so to /etc/pam.d/sshd (and comment out its @include common-auth line), then set KbdInteractiveAuthentication yes and AuthenticationMethods publickey,keyboard-interactive in sshd. A real gain against a stolen laptop, and one more thing to lose: keep the scratch codes off the server.

Troubleshooting: connection refused, timed out, permission denied

Connection refused

The server answered but nothing listens on that port: sshd is stopped, bound elsewhere, or you typed the wrong port. From the provider's console, run systemctl status ssh and sudo ss -tlnp | grep ssh. A syntax error stops sshd from starting at all; sudo sshd -t prints the offending line and journalctl -u ssh -n 50 shows the last start.

Connection timed out

Packets are dropped, not refused, which almost always means a firewall: UFW without the allow rule (sudo ufw status verbose), a security group in the provider's panel, or your own network blocking outbound 22 (a phone hotspot rules that out). ssh -v username@SERVER_IP shows where the handshake stalls.

Permission denied (publickey)

The server is reachable and rejecting you. Check, in order: the username, whether that user's authorized_keys holds the key you are offering (ssh -i ~/.ssh/id_ed25519 -v forces a specific key), the permissions on ~/.ssh, and whether the login is missing from AllowUsers. On the server, journalctl -u ssh -n 30 names the reason; Authentication refused: bad ownership or modes is the permissions problem described earlier.

Host key warning

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED after a rebuild is expected: run ssh-keygen -R SERVER_IP and reconnect. If you did not reinstall anything, find out why before typing a password anywhere. Locked out entirely? The provider's console is the way back in.

Everything above assumes a machine where you hold root and can afford to break sshd and repair it from a console. A Linux VPS from rdp.monster is exactly that machine: full root access, dedicated CPU and RAM, unlimited (fair-use) bandwidth, no KYC, payment in crypto or fiat, from $8.99 per month, and the server is online about 10 seconds after payment confirms, plenty of time to have keys in place before the first scanner finds port 22.

Frequently Asked Questions

Does Ubuntu come with SSH enabled by default?

Ubuntu Desktop does not; Ubuntu Server and most cloud images do.
Ubuntu Desktop installs only the SSH client, so nothing listens on port 22 until you run sudo apt install openssh-server. Ubuntu Server asks during installation whether to install the OpenSSH server and can import your GitHub or Launchpad keys at the same time. Cloud and VPS images almost always ship with openssh-server installed, enabled and accepting connections, because it is the only way the provider can hand you the machine. Check with systemctl status ssh.

How do I check whether SSH is running on Ubuntu?

Run systemctl status ssh, then confirm port 22 is listening with ss.
systemctl status ssh tells you whether the service is active or enabled. Because Ubuntu 22.10 and later use socket activation, the service may legitimately show inactive (dead) with TriggeredBy: ssh.socket when nobody is connected, so the more reliable test is sudo ss -tlnp | grep ssh: a line showing 0.0.0.0:22 or [::]:22 means SSH is listening. From another machine, ssh -v username@SERVER_IP confirms it end to end.

Is it safe to leave SSH on port 22?

Yes, provided passwords are disabled and keys are used; the port number adds no protection.
Port 22 attracts constant automated login attempts, but those attempts cannot succeed against a server with PasswordAuthentication no and a key pair, and fail2ban removes most of the noise. Moving sshd to 2222 or 22222 hides it only from the laziest scanners; port scanners such as nmap and masscan find it in minutes, and internet-wide indexes list it anyway. Treat a non-default port as a log-hygiene measure, not as a security control, and never skip keys because you changed the port.

What is the difference between ssh and sshd on Ubuntu?

ssh is the client program; sshd is the server daemon, whose Ubuntu unit is named ssh with sshd as an alias.
ssh is the client you run on your laptop to open a connection; it comes from the openssh-client package. sshd is the daemon that answers on the server, from openssh-server, configured in /etc/ssh/sshd_config (the client reads ssh_config). Ubuntu and Debian name the systemd unit ssh.service and declare sshd.service as an alias, so systemctl restart ssh and systemctl restart sshd do the same thing; on Fedora, RHEL and Arch the unit is simply sshd.

Adrien Roche, Infrastructure & Hosting Editor

Systems engineer with 10+ years operating Windows Server and Linux fleets. Adrien runs the rdp.monster infrastructure documentation and writes our guides on RDP, VPS hosting, server administration, networking and privacy tooling.

Register to our reseller program

Your information

If you have any question, contact us by clicking here !
Name(Required)
Enter your email address, you must have an account on manager.rdp.monster !

Your company

Enter your website address if you have one
Quickly explain how you're going to sell services to your customers. For example, talk to people on forums.

Even monsters love cookies!

We use cookies to enhance your browsing experience, serve personalized ads or content, and analyze our traffic. By clicking "Accept", you consent to our use of cookies.