GUIDE: How To Setup SSH (internal network)

❯❯ What is SSH?

SSH is a communication protocol used for establishing secure, encrypted connection tunnels between hosts. It is a very common tool for sysadmins, IT workers, developers and any person that needs to maintain access to a server from afar.

❯❯ How to use SSH.

SSH is used to connect and administer remote servers as explained earlier. The common commands are ssh (to connect and establish a remote shell session), scp (to securely copy files over an SSH tunnel), sftp (to transfer files interactively), rsync (to sync files, kind of smart copying).

The basic common SSH command usage forms are:
** note that a command is considered to be on the same line until the comment hash appears **

Basic SSH command usage (templates for connecting\copying are shown)
click to copy install SSH code segment on ubuntu/debian
ssh -p port_num -i ~/.ssh/id_file remote_user_name@remote_host_IP # initiate a remote secure shell connection

(sudo) scp -P port_num -i ~/.ssh/id_file files_to_copy (-r) remote_user_name@remote_host_IP:remote_dir # copy files to remote server

❯❯ Install and setup SSH.

Most linux distributions have the SSH client and server services installed by default.
If, for some reason, the distribution doesn't include the SSH packages (maybe in some minimal installations), use the following commands to install the packages on Debian/Ubuntu:

Installing SSH on ubuntu/debian system
click to copy install SSH code segment on ubuntu/debian
sudo apt update && sudo apt upgrade -y
sudo apt install openssh-client openssh-server

On Fedora/Centos/Alma/Rocky/RHEL:

Installing SSH on RHEL-based system
click to copy install SSH code segment on ubuntu/debian
sudo dnf upgrade -y
sudo dnf install openssh-server openssh-clients

Common commands for working with the SSH process:

Controlling the SSH process on Ubuntu/Debian:
click to copy install SSH code segment on ubuntu/debian
sudo apt systemctl enable --now ssh # make sure service starts on boot
sudo apt systemctl status ssh # show information about SSH process
sudo apt systemctl restart ssh # terminates and starts SSH again
sudo apt systemctl reload ssh # use to refresh SSH configuration
sudo apt systemctl start ssh # start SSH process manually (if not enabled)
sudo apt systemctl stop ssh # terminate the SSH process

For RHEL-based distros the commands are the same except the service name is sshd.

❯❯ Configure SSH Properly.

For security reasons, hardening your SSH configuration is a must-have skill for any sysadmin. The most basic configuration changes to be done are: change the default connection port (default is 22, and many bots are spam connecting to try and bruteforce machines), Setting login attempts limitations to avoid bruteforce (for regular password login), setting up private/public key authentication (preferrable over password auth) and creating known connection blocks.
It is important to understand there are two different configuration files at /etc/ssh, one for the SSH client, and one for the SSH server.
The SSH client includes config for your machine trying to connect to a remote host (config file is at /etc/ssh/ssh_config).
The SSH server includes config for your machine accepting connections from other hosts to itself (config file is at /etc/ssh/sshd_config).

We will describe these configuration steps one by one.

Changing the default connection port:

Open config file and locate port directive:
click to copy install SSH code segment on ubuntu/debian
sudo vim /etc/ssh/sshd_config
(in vim) /Port
change Port 22 to other nontrivial port number which is free

If password-based authentication is to be used, limit numbers of login attempts:
Open config file and limit login privileges:
click to copy install SSH code segment on ubuntu/debian
sudo vim /etc/ssh/sshd_config
(in vim) /MaxAuthTries
Uncomment the directive and set desired number (3 is reasonable)
(in vim) /LoginGraceTime
Uncomment the directive and set desired number (1-2 is reasonable)
:wq

The previous is basic anti bruteforce measures, but not sufficient against spam bots.
Thus, we will install an additional tool, that actually bans IPs that try to connect stubbornly.
This tool works with "jails", which are kind of "ban config" files per service.

Add fail2ban as a "jailer" tool against stubborn bruteforce bots:
click to copy install SSH code segment on ubuntu/debian
sudo apt install fail2ban -y # install the tool
sudo systemctl enable --now fail2ban # instruct OS to fire service on boot
sudo systemctl start fail2ban # start the service
sudo systemctl status fail2ban # check whether the service started and is running

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # create local copy
sudo vim /etc/fail2ban/jail.local
(in vim) /[sshd] # locate the sshd service block

Under [sshd] block set:
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 12h
findtime = 1m

Now, reload the config of jail2ban to apply for the SSH service:

Refresh jail2ban config:
click to copy install SSH code segment on ubuntu/debian
sudo systemctl reload fail2ban
sudo fail2ban-client status # check if jail applied
sudo fail2ban-client status sshd # get specific info about SSH service

❯❯ Using key-based authentication.

Password based authentication is frowned upon (since it is prone to bruteforce attacks and requires special system hardening as we've just seen), The better and more comfortable approach to SSH into remote hosts is by establishing a connection via shared keys. The connecting machine shares a private key it holds to "unlock" a public key the server holds. This is never done over an insecure channel, and is done only once a secure communication channel was created. This way, no entity without the exact key value that unlocks this public key can login to the server. This rids the user from bruteforce attacks, while at the same time makes SSH more comfortable to use, since the connection is faster, without repeated prompts asking for password credentials. Note, that if by some manner, your private key file is compromised a malicious actor can now SSH as if it is you! However, there is an optional fail-safe mechanism in place to avoid it, by entering a passphrase which is used to unlock the passed key value on login attempt. Additional measures to maximally secure your remote server from malicious unauthorized login is to also establish IP filtering rules (since then, the malicious actor needs to use your machine, which reduces risk), as well as setup hardware authentication options (e.g ubikeys). This guide will not dive into hardware authentication and IP filtering, but will finish with instructions on how to setup key-based authentication.


Run on the machine you intend to connect from (OPTIONAL: Enter a passphrase of your choice when prompted - you must remember it!):

Create authentication key-pair and share public key with remote host
click to copy install SSH code segment on ubuntu/debian
ssh-keygen -t ed25519 -a 100 -o -f ~/.ssh/id_remotehost # generate a key pair (private and public)

Now, two files (the keys) were generated in the folder ~/.ssh, id_remotehost and id_remotehost.pub
The next step is to share the public key with the server, so it can authorize your access using it:

Share public key with server we want to connect to:
click to copy install SSH code segment on ubuntu/debian
ssh-share-id -p portnum -i ~/.ssh/id_remotehost # script that copies pubkey

Lastly, we want to disable password-based authentication and allow only key-based authentication in the configuration file of the server we wish to connect to. Thus, on the remote host:

Disable password login & enable pubkey login:
click to copy install SSH code segment on ubuntu/debian
sudo vim /etc/ssh/sshd_config
(in vim) /PermitRootLogin
uncomment and set -> PermitRootLogin no
uncomment and set -> PubkeyAuthentication yes
uncomment and set -> PasswordAuthentication no
uncomment and set -> PermitEmptyPasswords no
uncomment and set -> KbdInteractiveAuthentication no

Lastly, in order to establish the new rules we need to reload the config for SSH.
On the remote server:

Apply new config rules to SSH server service:
click to copy install SSH code segment on ubuntu/debian
sudo systemctl reload ssh

Now, we can SSH into the remote server using the command:

Connect to remote server using key-based auth:
click to copy install SSH code segment on ubuntu/debian
ssh -p port_num -i ~/.ssh/id_remotehost remote_user_name@remote_host_IP

❯❯ Configuring connection blocks.

Connection blocks are configuration we add to the connecting side configuration file (/etc/ssh/ssh_config).
They are useful for making the connection command less verbose and tiring to type.

For example, without a defined and applied connection block we need to type:

Verbose SSH command (without connection block):
click to copy install SSH code segment on ubuntu/debian
ssh -p port_num -i ~/.ssh/id_remotehost remote_user_name@remote_host_IP

With a connection block defined and applied we can just write:
Succint SSH command (with connection block):
click to copy install SSH code segment on ubuntu/debian
ssh remote_host

Connection blocks are especially necessary when a sysadmin has a large list of machines to SSH into regularly.
Now that we see how less cumbersome the command becomes, we will define a connection block:

Add a connection block:
click to copy install SSH code segment on ubuntu/debian
sudo vim /etc/ssh/ssh_config
(in vim) GG
(in vim) i
(in insert mode):
HOST remote_host_name
        HostName remote_host_IP
        User     remote_host_username
        Port     port_num
        IdentityFile ~/.ssh/id_remotehost

Make sure to reload the SSH client config to apply the connection block:

Add a connection block:
click to copy install SSH code segment on ubuntu/debian
sudo systemctl reload ssh

profile picture

WHO AM I?

Animal Lover
Tinkerer
Teacher