Ubuntu SSH Server Setup

Khimananda Oli 8 min read Virtualization
Ubuntu SSH Server Setup

By Khimananda Oli | Last reviewed: August 2026

A fresh Ubuntu installation does not accept remote connections by default, leaving you locked out of headless servers or cloud instances until you configure remote access correctly. This Ubuntu SSH server setup guide walks you through installing OpenSSH, enforcing key-based authentication, and hardening the daemon against automated attacks before exposing it to any network. Whether you are provisioning a new VPS in Kathmandu or managing a fleet of AWS EC2 instances, these steps establish a secure baseline that prevents credential stuffing and unauthorized root access.

How do you install and verify OpenSSH on Ubuntu?

The OpenSSH server package is not included in minimal Ubuntu cloud images or container base layers. You must explicitly install it using APT. Before running any installation commands, ensure your package index is current to avoid pulling outdated binaries with known vulnerabilities.

sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
systemctl status ssh

The enable --now flag both starts the service immediately and configures it to launch on boot, which is critical for surviving reboots in production environments. When you check the status, look for "active (running)" in green. If the service fails to start, check journalctl -u ssh -n 50 --no-pager for syntax errors in the configuration file.

Installopenssh-serverGenerate KeysED25519 + Copy IDHarden Configsshd_config editsFirewall & TestUFW + Verify
Four-stage Ubuntu SSH server setup workflow from package installation through firewall verification

After confirming the service is running, perform an initial connectivity test from your local machine using verbose mode. This reveals handshake details and confirms the server responds before you begin modifying configurations:

ssh -v user@your-server-ip

If this connects successfully with password authentication, the baseline installation works. Now you can proceed to securing it. Never skip this verification step; debugging connectivity after applying hardening measures without a known-good baseline wastes significant time.

How do you configure SSH key authentication securely?

Password authentication is the single largest attack surface on any SSH daemon. Automated bots scan public IP ranges continuously, attempting credential stuffing against exposed ports. Key-based authentication eliminates this vector entirely when configured correctly. For a complete treatment of hardening beyond keys, see my guide on how to harden SSH with key auth, Fail2Ban, and port hardening.

Generate modern ED25519 keys

RSA keys require 4096 bits for adequate security in 2026, but ED25519 provides equivalent strength at 256 bits with faster operations and smaller signatures. Generate a key pair on your local machine, never on the server itself:

ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_prod

The -C comment field helps identify keys when auditing authorized_keys files across multiple servers. Use descriptive comments including hostname or purpose.

Deploy the public key safely

Use ssh-copy-id to append your public key to the remote server's authorized_keys file. This tool handles permissions and directory creation automatically, preventing common mistakes:

ssh-copy-id -i ~/.ssh/id_ed25519_prod.pub user@your-server-ip

Verify key authentication works before disabling passwords. Open a new terminal window and connect specifying the key explicitly:

ssh -i ~/.ssh/id_ed25519_prod user@your-server-ip

If this succeeds without prompting for a password, key authentication is functional. Keep your original password-authenticated session open as a fallback until all hardening is complete and verified.

Set correct file permissions

OpenSSH refuses authentication if permissions are too permissive. The server enforces this strictly to prevent unauthorized key injection:

  • ~/.ssh directory: 700 (drwx------)
  • ~/.ssh/authorized_keys: 600 (-rw-------)
  • ~/.ssh/id_ed25519_prod (private key): 600 (-rw-------)
  • ~/.ssh/id_ed25519_prod.pub (public key): 644 (-rw-r--r--)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R $USER:$USER ~/.ssh

What sshd_config settings harden Ubuntu SSH effectively?

Edit /etc/ssh/sshd_config directly or use drop-in files under /etc/ssh/sshd_config.d/ for better maintainability. Drop-ins are processed alphabetically after the main config, making upgrades safer since package updates won't overwrite customizations.

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

Apply these directives for production-grade security:

# Disable password and root authentication
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AuthenticationMethods publickey

# Limit exposure
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30

# Restrict ciphers and algorithms
KexAlgorithms [email protected],curve25519-sha256
Ciphers [email protected],[email protected]
MACs [email protected],[email protected]

# Logging
LogLevel VERBOSE
Password AuthBrute ForceCredential StuffingCompromiseKey AuthChallenge-ResponseNo Secret TransitSecure Access
SSH authentication comparison showing password vulnerability versus key-based security in Ubuntu SSH server setup

Always validate configuration syntax before restarting the daemon. A typo can lock you out completely:

sudo sshd -t

This command returns silently on success or prints specific line numbers on error. Only restart after clean validation:

sudo systemctl reload ssh

Use reload instead of restart to apply changes without dropping existing sessions. This matters during maintenance windows when other administrators may be connected.

How do you restrict SSH access with UFW firewall rules?

Network-level filtering provides defense-in-depth even when SSH hardening is complete. Uncomplicated Firewall (UFW) wraps nftables with a manageable syntax suitable for most Ubuntu deployments. For deeper firewall architecture decisions, review how to configure UFW on Ubuntu effectively.

Allow SSH from trusted sources only

Never expose port 22 to 0.0.0.0/0 on public servers. Restrict to your office IP, VPN subnet, or bastion host:

sudo ufw allow from 203.0.113.50/32 to any port 22 proto tcp comment 'Admin workstation'
sudo ufw allow from 10.8.0.0/24 to any port 22 proto tcp comment 'WireGuard VPN'
sudo ufw deny 22/tcp

The explicit deny rule catches any source not matched by preceding allow rules. Order matters: UFW processes rules top-to-bottom and stops at first match.

Enable and verify UFW

If UFW is inactive, enable it carefully. Ensure you have console access (cloud provider web console or physical access) before enabling remotely:

sudo ufw enable
sudo ufw status numbered

Review the numbered output to confirm rules appear in expected order. Test connectivity from an allowed IP and verify rejection from a disallowed IP using a mobile hotspot or different network.

Configuration AspectInsecure DefaultHardened SettingRisk Mitigated
AuthenticationPassword enabledPubkeyAuthentication onlyCredential stuffing, brute force
Root LoginPermitRootLogin yesPermitRootLogin noDirect root compromise
Port ExposureOpen to 0.0.0.0/0Restricted to trusted IPsAutomated scanning, exploit attempts
Cryptographic AlgorithmsLegacy CBC, SHA1ChaCha20-Poly1305, ETM MACsProtocol downgrade attacks
Session LimitsNo timeoutsClientAliveInterval 300Abandoned session hijacking

What common mistakes break Ubuntu SSH server setup?

Even experienced engineers make predictable errors during SSH configuration. These issues cause lockouts, silent failures, or false security assumptions.

  1. Closing your only session before testing: Always open a second terminal after config changes. If reload breaks authentication, the original session remains active for rollback.
  2. Editing sshd_config directly without backups: Run sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F) before every edit. Version control the directory with etckeeper for audit trails.
  3. Ignoring SELinux/AppArmor contexts: On Ubuntu, AppArmor profiles may block SSH from reading authorized_keys in non-standard locations. Check aa-status and review /var/log/syslog for denials.
  4. Assuming key deployment succeeded: ssh-copy-id can silently fail if the remote shell outputs unexpected text (motd banners, profile scripts). Verify manually with cat ~/.ssh/authorized_keys on the server.
  5. Forgetting IPv6: UFW rules applied to IPv4 don't automatically cover IPv6. If your server has global IPv6 addressing, add corresponding v6 rules or disable IPv6 in sshd_config with AddressFamily inet.
Layer 1: Network (UFW)IP allowlisting, port restriction, rate limitingLayer 2: SSH Daemon (sshd_config)Key-only auth, algorithm restrictions, session limitsLayer 3: OS Controls (AppArmor, Permissions)File ownership, mandatory access control, audit logging
Three-layer defense model for Ubuntu SSH server setup combining network, daemon, and operating system controls

When troubleshooting failed connections, increase client verbosity progressively: ssh -vvv reveals full handshake negotiation, algorithm selection, and authentication method attempts. Match this against server-side logs at LogLevel VERBOSE to pinpoint mismatches.

Finalizing Your Ubuntu SSH Server Setup

A properly hardened Ubuntu SSH server setup requires three elements working together: cryptographic key authentication replacing passwords, restrictive firewall rules limiting exposure, and validated configuration preventing lockouts. Document your final sshd_config in version control alongside infrastructure-as-code definitions so deployments remain reproducible. For teams managing multiple servers, consider automating this entire process with Ansible playbooks as described in my guide to automating server setup with Ansible. If your environment demands compliance-ready infrastructure or you need help auditing existing SSH configurations across a fleet, reach out to discuss your requirements.

Frequently Asked Questions

Run sudo apt update followed by sudo apt install openssh-server. Verify the service is active using systemctl status ssh. This installs the latest stable OpenSSH version available in the official Ubuntu repositories for secure remote access.

Yes. Change Port 22 to a non-standard value like 2222 in /etc/ssh/sshd_config to reduce automated brute-force noise. Restart sshd afterward and ensure your firewall allows the new port before disconnecting.

Edit /etc/ssh/sshd_config and set PermitRootLogin to no. Restart the SSH service with systemctl restart ssh. Always verify standard user sudo access works before disabling root to prevent accidental lockouts during administration.

Absolutely. Generate keys locally, copy the public key using ssh-copy-id, and set PasswordAuthentication to no in sshd_config. Key-based auth prevents brute-force attacks and is significantly more secure than password-only authentication for production servers.

Run sudo ufw allow ssh or specify a custom port like sudo ufw allow 2222/tcp. Verify rules with sudo ufw status numbered. Always confirm SSH connectivity before enabling UFW to avoid locking yourself out of the server.

Check if UFW or iptables blocks the port, verify sshd is running via systemctl status ssh, and confirm the listening address in sshd_config. Cloud provider security groups often block inbound SSH by default and require manual rule updates.

Add AllowUsers username1 username2 to /etc/ssh/sshd_config and restart the service. This whitelist approach denies all other accounts including root. Combine with key-based auth for defense-in-depth on multi-user Ubuntu servers.

No. OpenSSH server is free open-source software included in Ubuntu repositories with zero licensing fees. You only pay for underlying compute resources from your cloud provider or hardware costs for self-hosted infrastructure deployments.

Install libpam-google-authenticator, run google-authenticator as the target user, and add pam_google_authenticator.so to /etc/pam.d/sshd. Set ChallengeResponseAuthentication to yes in sshd_config. This adds TOTP verification alongside existing key or password authentication methods.

Set .ssh directory to 700 and authorized_keys file to 600 using chmod. The home directory must not be group or world writable. Incorrect permissions cause silent authentication failures even when keys are correctly configured in the file.

Disable password auth, use fail2ban to ban repeated failures, limit MaxAuthTries to three in sshd_config, and enforce key-only access. These layered controls dramatically reduce attack surface without impacting legitimate administrator workflows on Ubuntu servers.

Yes. Create separate config files and systemd unit files for each instance specifying unique Port and PidFile values. This allows isolated access paths for different teams or services while maintaining independent security policies per listener.

Run sudo sshd -t to validate syntax before restarting. Keep an active session open while testing new configs in a second terminal. Use systemctl reload ssh instead of restart to apply changes without dropping existing connections.

Check /var/log/auth.log for authentication events, failed logins, and key rejections. Use journalctl -u ssh -f for real-time systemd journal output. These logs are essential for auditing access and diagnosing connection issues on Ubuntu systems.

Run sudo apt update && sudo apt upgrade openssh-server regularly. Subscribe to Ubuntu Security Notices for CVE alerts. Always test configuration compatibility after major version upgrades since deprecated options may cause service failures on restart.