Debian

Install and Configure SSH Server on Ubuntu 24.04 / Debian 13

OpenSSH is the standard tool for secure remote access to Linux servers. It encrypts all traffic between client and server, replacing older insecure protocols like Telnet and rlogin. Every production Linux server needs a properly configured SSH server – it is the primary way you manage systems remotely.

Original content from computingforgeeks.com - post 96

This guide covers a full OpenSSH server setup on Ubuntu 24.04 LTS and Debian 13, from installation through advanced hardening. We walk through key-based authentication, firewall rules, fail2ban, SSH tunneling, multi-factor authentication, and troubleshooting. The official OpenSSH documentation is a good reference for additional configuration options.

Prerequisites

Before starting, make sure you have:

  • A server running Ubuntu 24.04 LTS or Debian 13 with root or sudo access
  • A static IP address or hostname for the server
  • Network connectivity between client and server on TCP port 22 (or your chosen SSH port)
  • A local machine (Linux, macOS, or Windows with OpenSSH client) for connecting

Step 1: Install OpenSSH Server on Ubuntu 24.04 / Debian 13

OpenSSH server is available in the default repositories for both Ubuntu and Debian. Update the package index and install it.

sudo apt update
sudo apt install -y openssh-server

After installation, verify that the SSH package is installed correctly.

dpkg -l | grep openssh-server

The output confirms the package version and installation status:

ii  openssh-server 1:9.6p1-3ubuntu13.5 amd64 secure shell (SSH) server, for secure access from remote machines

Step 2: Start and Enable the SSH Service

Enable the SSH daemon so it starts automatically on boot, then start it immediately.

sudo systemctl enable --now ssh

Verify the service is running with no errors:

sudo systemctl status ssh

You should see the service active and running:

● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-03-22 10:15:32 UTC; 5s ago
   Main PID: 1234 (sshd)
      Tasks: 1 (limit: 4614)
     Memory: 1.8M
        CPU: 25ms
     CGroup: /system.slice/ssh.service
             └─1234 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

Confirm that SSH is listening on port 22:

ss -tlnp | grep sshd

The output should show sshd listening on all interfaces:

LISTEN 0      128          0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=1234,fd=3))
LISTEN 0      128             [::]:22           [::]:*    users:(("sshd",pid=1234,fd=4))

Step 3: Configure SSH Server (sshd_config)

The main SSH server configuration file is /etc/ssh/sshd_config. Before making changes, create a backup of the original.

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

Open the configuration file for editing:

sudo vi /etc/ssh/sshd_config

Update the following directives. Uncomment any line that starts with # and set the values as shown:

# Change the default port (optional but recommended)
Port 2222

# Disable root login - use a regular user with sudo instead
PermitRootLogin no

# Disable password authentication after setting up SSH keys (Step 5)
# Keep this as 'yes' until you confirm key-based login works
PasswordAuthentication yes

# Restrict SSH access to specific users
AllowUsers deployer admin

# Disable empty passwords
PermitEmptyPasswords no

# Set maximum authentication attempts
MaxAuthTries 3

# Set login grace time (seconds to authenticate before disconnecting)
LoginGraceTime 60

# Disable X11 forwarding unless specifically needed
X11Forwarding no

# Use Protocol 2 only (default on modern OpenSSH but explicit is better)
Protocol 2

The AllowUsers directive is one of the most effective restrictions – only listed usernames can log in via SSH. Replace deployer and admin with your actual usernames.

Validate the configuration syntax before restarting:

sudo sshd -t

If the command returns no output, the configuration is valid. Restart SSH to apply changes:

sudo systemctl restart ssh

Important: If you changed the port, keep your current SSH session open and test connecting on the new port from a second terminal before closing the original session. This prevents lockouts.

ssh -p 2222 deployer@your-server-ip

Step 4: Set Up SSH Key-Based Authentication

Key-based authentication is more secure than passwords. It uses a cryptographic key pair – a private key on your local machine and a public key on the server. Generate a key pair on your local machine (not the server).

ssh-keygen -t ed25519 -C "[email protected]"

The Ed25519 algorithm is the recommended choice – it is faster and more secure than RSA for new keys. You will be prompted for a file location and passphrase:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub

Always set a passphrase on your private key. It adds a second layer of protection if someone gains access to your key file.

Copy the public key to the server using ssh-copy-id:

ssh-copy-id -p 2222 deployer@your-server-ip

This appends your public key to ~/.ssh/authorized_keys on the server. If ssh-copy-id is not available (some minimal systems), copy the key manually:

cat ~/.ssh/id_ed25519.pub | ssh -p 2222 deployer@your-server-ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Test that key-based authentication works by connecting without being prompted for a password (you may be prompted for your key passphrase):

ssh -p 2222 deployer@your-server-ip

Step 5: Disable Password Authentication

Once you have confirmed that key-based login works, disable password authentication entirely. This eliminates brute-force password attacks.

sudo vi /etc/ssh/sshd_config

Set the following directives:

PasswordAuthentication no
KbdInteractiveAuthentication no
UsePAM no

Restart the SSH service:

sudo systemctl restart ssh

Verify that password login is rejected. From your local machine, try connecting with password authentication forced:

ssh -p 2222 -o PubkeyAuthentication=no deployer@your-server-ip

The connection should be denied with “Permission denied (publickey)” – confirming that only key-based login is allowed.

Step 6: Configure UFW Firewall for SSH

A firewall is essential on any server exposed to the internet. UFW (Uncomplicated Firewall) is the default firewall management tool on Ubuntu and Debian. If you are using the default SSH port, allow it through the firewall. For a deeper look at UFW rules and usage, check out UFW firewall usage commands with examples.

Install UFW if it is not already present:

sudo apt install -y ufw

If you changed the SSH port to 2222 in Step 3, allow that port instead of the default:

sudo ufw allow 2222/tcp comment "SSH"

If you kept the default port 22:

sudo ufw allow OpenSSH

Enable the firewall and check its status:

sudo ufw enable
sudo ufw status verbose

The output should show your SSH port allowed:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
2222/tcp                   ALLOW IN    Anywhere                   # SSH
2222/tcp (v6)              ALLOW IN    Anywhere (v6)              # SSH

For tighter security, restrict SSH access to specific IP addresses or subnets only:

sudo ufw allow from 10.0.1.0/24 to any port 2222 proto tcp comment "SSH from office network"

Step 7: SSH Hardening with Fail2ban

Fail2ban monitors log files for failed authentication attempts and temporarily bans offending IP addresses. This is critical for any internet-facing SSH server, even with key-based authentication enabled.

Install fail2ban:

sudo apt install -y fail2ban

Create a local configuration file. Never edit the main /etc/fail2ban/jail.conf directly – it gets overwritten on upgrades.

sudo vi /etc/fail2ban/jail.local

Add the following SSH jail configuration:

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
ignoreip = 127.0.0.1/8 10.0.1.0/24

This configuration bans an IP for 1 hour (3600 seconds) after 3 failed attempts within 10 minutes (600 seconds). The ignoreip directive prevents your own network from being locked out. Adjust the port number to match your SSH configuration.

Enable and start fail2ban:

sudo systemctl enable --now fail2ban

Check the SSH jail status to confirm it is active:

sudo fail2ban-client status sshd

The output shows the jail is running with the filter active:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Beyond fail2ban, these sshd_config directives further harden your SSH server. Make sure they are set in /etc/ssh/sshd_config:

# Disconnect idle sessions after 5 minutes
ClientAliveInterval 300
ClientAliveCountMax 0

# Limit concurrent unauthenticated connections
MaxStartups 10:30:60

# Disable agent forwarding unless needed
AllowAgentForwarding no

# Disable TCP forwarding unless needed
AllowTcpForwarding no

# Log more detail for auditing
LogLevel VERBOSE

Restart SSH after applying these changes:

sudo systemctl restart ssh

Step 8: SSH Tunneling and Port Forwarding

SSH tunneling lets you forward traffic through an encrypted connection. This is useful for accessing services on remote networks or securing traffic for applications that do not support encryption natively. For more SSH tunnel techniques, see how to create SSH tunnels on Linux.

Local Port Forwarding

Forward a port on your local machine to a service on the remote server or a host accessible from the server. This example forwards local port 8080 to a web application running on port 3000 on the remote server:

ssh -L 8080:localhost:3000 -p 2222 deployer@your-server-ip

Access the application by opening http://localhost:8080 in your browser. The traffic is encrypted through the SSH tunnel.

Remote Port Forwarding

Make a local service accessible from the remote server. This forwards port 9090 on the server to port 9090 on your local machine:

ssh -R 9090:localhost:9090 -p 2222 deployer@your-server-ip

Dynamic Port Forwarding (SOCKS Proxy)

Create a SOCKS proxy through the SSH connection. This routes all traffic from applications configured to use the proxy through the SSH tunnel:

ssh -D 1080 -p 2222 -N deployer@your-server-ip

The -N flag tells SSH not to execute a remote command – just establish the tunnel. Configure your browser or application to use localhost:1080 as a SOCKS5 proxy.

Step 9: Multi-Factor Authentication with Google Authenticator

Adding a time-based one-time password (TOTP) to SSH provides an extra layer of security beyond keys. Even if an attacker obtains your private key, they still need the TOTP code. For CentOS/RHEL-specific setup, check out how to configure SSH two-factor authentication on CentOS/RHEL.

Install the Google Authenticator PAM module:

sudo apt install -y libpam-google-authenticator

Run the setup as the user who will log in (not root):

google-authenticator

Answer the prompts as follows:

  • Time-based tokens? – Yes
  • Update .google_authenticator file? – Yes
  • Disallow multiple uses of the same token? – Yes
  • Increase time window? – No (keep the default 30-second window)
  • Enable rate limiting? – Yes

The command displays a QR code and emergency backup codes. Scan the QR code with your authenticator app (Google Authenticator, Authy, or any TOTP app). Save the emergency codes in a secure location.

Configure PAM to require the TOTP token. Open the PAM SSH configuration:

sudo vi /etc/pam.d/sshd

Add this line at the end of the file:

auth required pam_google_authenticator.so

Update /etc/ssh/sshd_config to enable challenge-response authentication:

sudo vi /etc/ssh/sshd_config

Set these directives:

KbdInteractiveAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive

The AuthenticationMethods directive requires both a valid SSH key and a TOTP code for login. Restart SSH:

sudo systemctl restart ssh

Test from a new terminal session. You should be prompted for your verification code after the key is accepted.

Step 10: Troubleshoot Common SSH Issues

When SSH connections fail, systematic debugging saves time. Here are the most common issues and their fixes. If you ever need to temporarily bypass host key verification for testing, see how to disable SSH host key checking.

Connection Refused

This means sshd is not running or is listening on a different port. Check the service and port:

sudo systemctl status ssh
ss -tlnp | grep sshd

Permission Denied (publickey)

This usually means the key is not in authorized_keys or file permissions are wrong. Fix permissions on the server:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R $USER:$USER ~/.ssh

Verbose Connection Debugging

Use the -vvv flag for maximum debug output on the client side:

ssh -vvv -p 2222 deployer@your-server-ip

On the server side, check the authentication log for errors:

sudo tail -50 /var/log/auth.log

Host Key Changed Warning

If you reinstalled the server or changed its IP, you will see a “WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED” message. Remove the old key from your known hosts file:

ssh-keygen -R your-server-ip

Slow SSH Login

Slow login is usually caused by DNS reverse lookups. Disable it in /etc/ssh/sshd_config:

UseDNS no

Restart SSH after the change. You can also mount remote directories over SSH using SSHFS on Linux for file management.

SSH Server Configuration Reference Table

This table summarizes the most commonly used sshd_config directives and their recommended values for a hardened SSH server. Refer to the Ubuntu OpenSSH server documentation for the full list of available options.

DirectiveRecommended ValueDescription
Port2222 (non-default)Change from 22 to reduce automated scan hits
PermitRootLoginnoDisable direct root login – use sudo instead
PasswordAuthenticationnoDisable after setting up SSH keys
PubkeyAuthenticationyesEnable key-based authentication
AllowUsersuser1 user2Whitelist specific users for SSH access
MaxAuthTries3Limit failed authentication attempts per connection
LoginGraceTime60Seconds to authenticate before disconnect
ClientAliveInterval300Seconds between keepalive checks for idle sessions
ClientAliveCountMax0Disconnect after this many missed keepalives
MaxStartups10:30:60Rate limit unauthenticated connections
X11ForwardingnoDisable unless graphical forwarding is needed
AllowAgentForwardingnoDisable unless needed for jump hosts
AllowTcpForwardingnoDisable unless tunneling is required
PermitEmptyPasswordsnoNever allow empty password authentication
UseDNSnoDisable reverse DNS lookup to speed up login
LogLevelVERBOSEDetailed logging for security auditing

Conclusion

You now have a fully configured and hardened SSH server on Ubuntu 24.04 or Debian 13. The setup covers key-based authentication, firewall rules, fail2ban intrusion prevention, SSH tunneling, and optional multi-factor authentication. These layers together make brute-force and unauthorized access significantly harder.

For production environments, also consider setting up centralized log monitoring for SSH authentication events, rotating host keys periodically, and using SSH certificates instead of individual authorized_keys files for large-scale deployments.

Related Articles

Php Install PHP 8.4 on Ubuntu 24.04 / 22.04 / 20.04 Security Understanding Application Security: Why You Need It to Fight Cyber Crime Security How to Install Astrill Application on Linux Debian Backup and Restore Linux Systems with Timeshift

6 thoughts on “Install and Configure SSH Server on Ubuntu 24.04 / Debian 13”

Leave a Comment

Press ESC to close