Managing remote servers with SSH and SFTP connections: a step-by-step guide
Tags: ssh, sftp, devops, security
Published: 2021-07-17 17:54:00

#Table of contents

1. [Introduction](#c0)
2. [Creating remote servers](#c1)
* [Accessing the remote server via cmd terminal (using password)](#c2)
* [Updating packages on the new server](#c3)
* [About the SSH key](#c4)
* [Creating SSH keys](#c5)
* [Accessing the public key](#c6)
* [Sending the public key to a remote server](#c7)
* [Accessing the remote server via cmd terminal (using SSH key)](#c8)
* [Sending files from the client to the server](#c9)
* [Sending files from the server to the client](#c10)
* [Creating a user on the server](#c11)
* [Disabling password access on the server](#c12)
* [Disabling root access on the server](#c13)
* [Create a SSH config file (very handy)](#c14)
* [Hosting a website on the server](#c15)
* [A lightweight client to manage SSH servers](#c17)
* [Transfering files over SFTP](#c16)
* [Auditing SSH keys](#c18)


## Introduction <a name="c0"></a>

Among the benefits to using SSH to manage remote machines, we can list:

* No need for passwords
* Encrypted communication

>Many people, specially for `Windows`, tend to recommend a GUI client called `PuTTY` to set SSH connections. As long as you are on `Windows 10`, `OpenSSH` is already native on you computer, so do not bother installing `PuTTY`. 

By the end of this article you will have learned how to:

* Create remote `servers`
* Create SSH connection from `Windows/Linux` devices to access these `servers`
* Disable password authentication on the `servers`, so they will become less vulnerable to brute-force attacks
* Transfer files back and forth between local devices and these `servers`
* Host your custom website on remote `servers`

## Creating remote servers <a name="c1"></a>

We will use [Digital Ocean](https://cloud.digitalocean.com/) for this part. Creating a `server` is very straightforward. Look for a **create droplet** option there. Here we have some settings suggestions for the new `server` to be created:

* **Choose a image/OS**: Ubuntu
* **Choose plan**: The cheapest one
* **Choose a datacenter**: Whichever is closer to you
* **Authentication method**: Password. We will set SSH manually and then disable password authentication (save this password to a text file for now, though)
* **Number of droplets (servers)**: 1
* **Choose a hostname**: ubuntu-one

Now hit the "create droplet" button

Some reference screenshots:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pq08uz1awffw5ljcunov.png)
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2iw7gx1ghynsnln9ar2b.png)
 
Once the server is created, you will have access to its IP address. Mine was `142.93.169.195`, and yours will be a different one.

Check that the machine is "real" by verifying its IP address on this website:

`http://ifconfig.co/?ip=142.93.169.195` (use your IP, not this one)

### Accessing the remote server via cmd terminal (using password)<a name="c2"></a>

    ssh root@142.93.169.195

Where:
`root`: user
`142.93.169.195`: server IP

You will be prompted for a message regarding **ECDSA key fingerprint**. Type **"yes"**.

> Once you say **yes** to this, notice that in `$HOME/.ssh` folder there will be a `known_hosts` file. This file "remembers" the `servers` that the current `client` device has previously connected to. Every time you connect to a new `server`, its fingerprint will be saved here (and you will be notified of that). This is a mechanism to verify that the `server` you are connecting to is actually the one you think it is.

You will be prompted for the password (the one you set when the `server` was created). Paste it here.

And there it is. If your terminal changed to `root@ubuntu-one`, you are connected to the remote `server`!

### Updating packages on the new server <a name="c3"></a>

**This is optional**, but recommended, as you problably will install additional softwares on this `server`. Run on the `server`:

    apt update
    apt upgrade

### About the SSH key <a name="c4"></a>

SSH is the authentication method that we will use as an alternative to using passwords when accessing remote `servers`. The SSH key is a 2-part key. Here's how they differ:

* **Public:** It is intented to be shared, and placed on the `server` that you will connect to.
* **Private:** It is not supposed to be shared or even seen by anyone else. If this part gets to the wrong hands, someone might be able to use it on their `client` computer and access the `servers` the key is intended for! :warning:  

You can have multiple SSH keys stored on your device. Once you have one, send the `public` part to the `server`. There, it will be stored in a dedicated place. To establish a connection, you will select a `private` key and the `server` will check for a match with their pre-existing `public` keys.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6sqzj5rl0hozt4gpbapq.png)

### Creating SSH keys <a name="c5"></a>

To make it easier, download and run one of the following scripts. They use the `ed25519` algorithm to create the keys, since it provides a more sophisticated encryption and generates a smaller key as well.


>When creating a SSH key, you will be prompted for an optional `passphrase` that will be requested when you try to use it. It is **highly** recommended that you set a `passphrase`, because if your `private` key gets leaked and it has no `passphrase`, someone else can actually it on their `client` computer and very likely will be able to access the `servers` that the key has access to. 😱 

#### Windows (PowerShell)

{% gist https://gist.github.com/costa86/322dbbb1150ea585932517c080173e5b %}

#### Linux (bash)

{% gist https://gist.github.com/costa86/7bb776bfcd87769d423c785e1f1fca03 %}

Tipically, the SSH keys are stored under the `$HOME/.ssh` directory (the `.` means that `.ssh` is a hidden folder), but you can have them elsewhere. I created a SSH key named `costa`, so here I can expect to see the 2-part key in 2 files: 

* `costa` (private, with no extension)
* `costa.pub` (public)

### Accessing the public key <a name="c6"></a>

See its contents with:

    cat costa.pub 

Or using a text editor, and you wil get something like this: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN7ioJG5Axxcksw47AujdY/Lke8ZJoWRPSDsV6pc/reK costa`


### Sending the public key to a remote server <a name="c7"></a>
Log in to the `server`, then:

    cd /root/.ssh

There you will find the `authorized_keys` file, which is where the `public` keys must be inserted into. Paste the `public` key here manually by opening the file using a text editor:

    nano authorized_keys

Or directly using the `>>` command: 

    echo <your_public_key_content> >> authorized_keys

 >If you use this second option, make sure you use `>>` (append) and not `>` (overwrite) :warning:

Think of the `authorized_keys` file as a vault that holds all the `public` keys from all devices authorized to SSH connect into this `server` using a SSH key.

### Accessing the remote server via cmd terminal (using SSH key) <a name="c8"></a>

Now that the `public` is on the `server`, we should be all set for accessing the `server` with the SSH key! 
First, if you are on the `server`, exit from it using the `exit` command.
Back on the `client`, access the `server` with the following command. This time you will not be prompted for the password.

    ssh -i <private_key_file> <user>@<ip>

>Notice that you don't actually need to provide the `private` key path using `-i`, as the keys stored under `/.ssh` are picked automatically.  But as you begin to add more keys, chances are that at some point you will start to get errors for unmatching keys. To avoid this kind of problem, I suggest that you always specify the key.

### Sending files from the client to the server <a name="c9"></a>
Back on the `client`, let us create a sample file in the current directory you are in:

    touch hello.txt 

Now let us send it to the `server`:

    scp -i <private_key> hello.txt root@142.93.169.195:

Where:
`:`: the directory where `hello.txt` will be saved on the `server`. In this case, the main/root folder.

Go back to the `server` and verify that `hello.txt` is there.

### Sending files from the server to the client <a name="c10"></a>

>This procedure is a little counter-intuitive, because you need to be on the `client` side. It is as if you are *fetching* a file previously stored on the `server`.

Being on `client`, I would like to have `hello.txt` (the one already saved on the `server`) sent to the `client`. First, delete `hello.txt` we just created on the `client`:

    rm hello.txt
    
Now fetch `hello.txt`:

    scp -i <private_key> root@142.93.169.195:hello.txt .

Where:
`:`: indicates the file path on the `server`
`.` (at the end): the path I want the file to be saved on the `client`. Notice the space before the `.`. Now, make sure you can see `hello.txt` on the `client`.

### Creating a user on the server <a name="c11"></a>

The following script will create a new user, grant it `sudo` permissions and grab a copy of the `root` user's `authorized_keys` file. Keep in mind that each user has its own `authorized_keys` file. :warning:

{% gist https://gist.github.com/costa86/1776dfe47e2a2dea296d4ec97544b71d %}

From the `client`, send `create-user.sh` to the main folder on the `server`:

    scp create-user.sh root@142.93.169.195:

Back on the `server`, you will see that `create-user.sh` is there. Run it to create a new user:

    . create-user.sh

Notice that your terminal changed to `<new_user>@ubuntu-one`. Now check the contents of the `authorized_keys` of the `<new_user>`:

    cat /home/<new_user>/.ssh/authorized_keys
 
 You will see here the same `public` key that you added to the `root` user. That means that now you can SSH connect to this `server` as `<new_user>`, instead of `root`, by using the same `private` key.  

Now you can replace `root` with `<new_user>` when connecting to the `server`.

### Disabling password access on the server <a name="c12"></a>

**This is not required**, but notice that if you try to connect to the `server` without a SSH key, you will still be prompted for the password. We will disable that so the `server` will be protected against brute-force attacks using passwords. On the `server`, run:

    sudo nano /etc/ssh/sshd_config

>Notice that in order to change this file, you need `sudo` permissions, hence the `sudo` command. 

This file contains settings regarding SSH. In its contents, look for `PasswordAuthentication`. It is problably set to `yes`, so change it to `no`. Also, make sure it is **not** commented as well (`#`). Save the changes and close this file.
Now you need to restart the SSH service for the changes to take effect: :warning:

    systemctl restart sshd

From this moment on, you will no longer be prompted for the password when trying to SSH connect to the `server`!😎

>The settings in the `/etc/ssh/sshd_config` file apply to all the users, as the `/etc` folder in Linux has a global scope.

### Disabling root access on the server <a name="c13"></a>

**This is not required** either, but keep in mind that there are many security concerns about remote connecting to a server as the `root` user. This user is like a *God mode* on Linux machines, so a lot of damage can be done by this user on the `server`! :warning:

To disable `root` access, go back to:

    sudo nano /etc/ssh/sshd_config

Set `PermitRootLogin` to `no`. Now restart the SSH Daemon service again: 

    systemctl restart sshd

Now go ahead and try to access the `server` as the `root` user. You are **not** supposed to be able to log in.

### Create a SSH config file (very handy) <a name="c14"></a>

This file makes it a lot easier to SSH connect to remote `servers` without needing to type their IP address and user. It is very helpful, especially if you plan to connect to multiple `servers`.

On the `client`, use the following template to create a file named `config`, and place it in your `/.ssh` folder:

{% gist https://gist.github.com/costa86/92ebafec384a184f9785676d486b3f5e %}

> In case you are wondering about the `Port`, 22 is the default `port` for SSH connections. It can be changed on the `/etc/ssh/sshd_config` file on the `server`. Also, the settings under `Host *` are broadcasted to all the`Hosts` 

 Once this file is set, the SSH connections can be made as such:

    ssh <custom_name>

In short, now you can replace the **user + IP address + private key + port** with a simple custom alias. Very convenient, right? 😎

### A lightweight client to manage SSH servers <a name="c17"></a>

[SHECRET](https://github.com/costa86/shecret) is one of my projects on GitHub. It is a lightweight command line SSH/SFTP client . You can also use it to create SSH keys using the `ed25519` algorithm!
 
![Image description](https://raw.githubusercontent.com/costa86/shecret/master/images/main.png)
 
### Hosting a website on the server <a name="c15"></a>

We will use `Apache` as a HTTP server. Install it on the `server`:
    
    sudo apt install apache2 -y

On the `client`, go to your `browser` and visit the IP address of the `server`. You will see a page similar to this one:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwnnq25cuk3ibpg15114.png)

The next step is finding this page on the `server` and replace it with our custom website content. 
Back on the `server`, go to this directory:

    cd /var/www/html

You will find a `index.html` file here. If you inspect its contents, you will notice that this is the file you are seeing on the page above.

We will use my personal portfolio as an example for our custom website.
Back on the `client`, download it [here](https://github.com/costa86/portfolio/archive/refs/heads/master.zip) as a `.zip` file, and send it to the `server` (main folder):

    scp portfolio-master.zip <custom_name>:

Back on the `server` and , having the `portfolio-master.zip` file there, move this file to the `/var/www/html/` directory:

    sudo mv portfolio-master.zip /var/www/html/

Go there:

    cd /var/www/html/


Install `unzip` to unzip this file:

    sudo apt install unzip

Now you can unzip it:
    
    unzip portfolio-master.zip

You may also delete the preexisting `index.html` file, as we will use a different one:

    rm index.html

After the unzipping, we get a `/portfolio-master` folder. We do not need the folder, only its contents. So we will move them into the current folder (`/var/www/html/`): 

    sudo mv portfolio-master/* .

Where:
`*`: all the files in `/portfolio-master` folder
`.`: the current directory

Now you are expected to see a bunch of files in `/var/www/html/`, including a brand new `index.html` file.
On the `client` side, visit the IP address again on the `browser` and you will see my portfolio page!

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tef21x0yccfz4u50u2cn.png)

You may now safely delete the `/portfolio-master` folder and` portfolio-master.zip` file, as we do not need them anymore:

    sudo rm -r portfolio-master/
    sudo rm portfolio-master.zip

### Transfering files over SFTP <a name="c16"></a>

We learned that `scp` can be used to transfer files back and forth from `client` to `server`. However, this approach has some limitations:

* You need to know the files and their respective paths on `remote` and `local` machines, prior to issuing the command.
* If the transfer is interrupted for some reason, you need to start over. This can become a issue when transfering large files or the internet connection is instable. 

In short, it is the **FTP (File Transfer Protocol)** with SSH-batteries included. Which means you can use the same credentials you are already using for SSH. Among the benefits to using SFTP:

* You can choose which files to transfer as you walk through the `server` directories.
* If the transfer is interrupted, it can be resumed.
* It works within its **own shell**, which has very useful features.

At this point I assume you are using the `config` file to manage your SSH connections, so in order to connect using SFTP from the `local`:

    sftp <custom_connection_name>

Your shell is supposed to have changed to `sftp>`. :warning: 
Some of the main possibilities with SFTP:

#### Download files from `server` to `local`:

    get <filename>

#### Upload files from `local` to `server`:

    put <filename>

#### Resume failed download:

If a download fails or is interrupted, you can resume it:

    reget <filename>

#### Resume failed upload:

If a upload fails or is interrupted, you can resume it:

    reput <filename>

Using a single command:

    echo 'put <local_file_path_to_upload>'| sftp -i <key> <user>@<ip>
    echo 'get <remote_file_path_to_download>'| sftp -i <key> <user>@<ip>


#### Get disk usage information about the `server`:
Handy to use before sending large files to the `server`.

    df

#### List the directories on the `local` machine:
Personally I find this one very handy.
    
    lls

#### Switch to the shell on the `local` machine:
    
    !
    #when you are done, exit

For more commands, type `help`.

### Auditing SSH keys <a name="c18"></a>

As you grant more people SSH access to your server, chances are at some point you will want to know which keys have been used to log in, and when, an so on. On Linux,  `journactlctl` works as an auditing tool for that. In our scenario, let's say I want to know about SSH connections for **today** on my `server`.
	
	journalctl -u ssh -S today

You wil find some entries similar to this one:
 *Oct 06 02:46:03 ubuntu sshd[2403]: Accepted publickey for costa from 192.168.18.1 port 54006 ssh2: ED25519 SHA256:KcZdwz9jSWutRXORHXH995E2ThQn9zci1yaeSaaPKxc*

At first glance, you might think this is a reference to a public SSH stored in your `authorized_keys`. Actually, it is the hash code for the public key. Now, to inspect the hash codes for the keys in `authorized_keys`:

	ssh-keygen -l -f .ssh/authorized_keys

Now you can look for a match with the `journalctl` entries. In our case: *SHA256:KcZdwz9jSWutRXORHXH995E2ThQn9zci1yaeSaaPKxc* 

> You can inspect the hash code for a SSH key with `ssh-keygen -l -f <public_or_private_key_file>`. You will notice that both public and private key share the same hash!

That's it, people.
### Thanks for the time reading this!
Follow me:
[LinkedIn](https://www.linkedin.com/in/costa86/) | [Dev.to](https://dev.to/costa86) | [Buy me a coffee](https://www.buymeacoffee.com/costa86) | [GitHub](https://github.com/costa86)