Lab: your own SSH server
Turn a Linux computer you own into an SSH server and use it from SecureShell Go: check its host key, sign in with a key, copy files both ways, and reach a mock API on it through a tunnel. You finish by putting everything back the way it was.
Level: beginner · Time: 45 to 60 minutes · Before this: the five lessons of this track
What you need
- A Linux computer you own, where you can use
sudo, and where you are sitting at the keyboard. The steps are written for Ubuntu 22.10 or later; differences for Ubuntu 22.04 are noted. This lab calls it the server. - A client: an Android phone with SecureShell Go, or a second Linux computer with SecureShell Go. See Install SecureShell Go.
- Both on the same network, such as your home Wi-Fi. Not a guest network: it may stop devices from seeing each other.
- Mock Studio on the server, and the file todo-api.mockstudio.json from the Todo API lab.
- Optional: ApiWorkbench on the phone, for part 7.
The examples use the address 192.168.1.20 and the account maya. Use your own server's address and account wherever you see them.
Your own computer only
Do this lab on a computer that is yours. Turning on an SSH server, changing its settings or its firewall on someone else's machine needs their permission, and on a work computer it may break your organisation's rules.
Part 1: turn on SSH
On the server, open a terminal and install the SSH server:
bashsudo apt install openssh-serverExpected: the package installs. If it says
openssh-server is already the newest version, SSH was already installed; carry on.Check that it is listening:
bashsystemctl status ssh.socketExpected:
Active: active (listening). Press q to leave. On Ubuntu 22.04, runsystemctl status sshinstead and look foractive (running).Check the port:
bashss -tln | grep ':22 'Expected: two lines, one with
0.0.0.0:22and one with[::]:22. The server accepts SSH on every interface.Check the firewall:
bashsudo ufw statusExpected:
Status: inactiveon a fresh Ubuntu desktop. If it saysactive, allow SSH from your LAN, using your own range:bashsudo ufw allow from 192.168.1.0/24 to any port 22 proto tcp
Part 2: find the server's address
On the server, run:
bashhostname -I whoamiExpected: the first address, such as
192.168.1.20, and your account name, such asmaya. Write both down.
Part 3: read the host key on the server's own screen
On the server, run:
bashssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubExpected: one line like
256 SHA256:L8BPGUED… root@maya-desktop (ED25519). Leave it on the screen.This is the fingerprint you got from a source you trust: the server itself, read with your own eyes, not over the network.
Part 4: connect and compare
In SecureShell Go, tap +. In Add host, fill in:
- Label (optional):
Lab server - Host:
192.168.1.20 - Port:
22 - Username:
maya
Keep Password selected, type the account's password, and tap Save & connect.
- Label (optional):
The Unknown host dialog appears. Check that Key type is
ssh-ed25519, then compare its SHA256 fingerprint with the one on the server's screen, character by character.If the dialog shows another key type, read the matching file on the server instead, such as
/etc/ssh/ssh_host_ecdsa_key.pub.If they match, tap Accept & save. If they do not, tap Reject and stop: something is wrong with the address or the network.
Expected: the terminal opens with the server's prompt, such as
maya@maya-desktop:~$.In the SecureShell Go terminal, run:
bashhostname whoExpected: the server's name, and a line for your session ending with your phone's or client's address in brackets, such as
(192.168.1.35).
Part 5: switch to a key
Tap Disconnect and confirm. On the host list, tap ⋮ next to Lab server and choose Edit.
Under the sign-in choice, select Private key, then tap Generate new key.
Expected: the New key generated dialog shows a public line starting with
ssh-ed25519. Tap Done. The private key now fills Private key (PEM).Tap Save changes.
Open the form again (⋮ › Edit) and tap Install public key on server…. Enter the account password and tap Install.
Expected: Public key installed on the server.
Tap Lab server to connect.
Expected: the terminal opens without asking for a password.
On the server's own terminal, look at what was added:
bashtail -n 1 ~/.ssh/authorized_keys ls -ld ~/.ssh ~/.ssh/authorized_keysExpected: a line ending in
secureshellgo@192.168.1.20, and the permissionsdrwx------for the folder and-rw-------for the file.
Part 6: copy files both ways
On the server, make a file to fetch:
bashecho "Hello from the server" > ~/from-server.txtIn the SecureShell Go session, tap Browse files. You start in your home folder on the server.
Long-press
from-server.txtand choose Download. When it finishes, tap Open in Transfers.Expected: the file opens on your phone and reads
Hello from the server. It is saved in your device's Downloads.Tap Upload here and pick a small file from your phone, such as a photo.
On the server, run:
bashls -l ~Expected: the file you uploaded is in the list.
Part 7: reach a mock API through a tunnel
Mock Studio's Todo API runs on the server at port 4010. You will reach it from the phone at localhost:14010, through SSH.
Phone Server 192.168.1.20
┌─────────────────────────┐ ┌─────────────────────────────┐
│ browser or ApiWorkbench │ │ │
│ http://localhost:14010 │ SSH, port 22│ sshd ──► localhost:4010 │
│ │ │═════════════►│ Mock Studio │
│ SecureShell Go listens │ │ Todo API (sample) │
│ on 127.0.0.1:14010 │ │ │
└─────────────────────────┘ └─────────────────────────────┘On the server, open Mock Studio. Select Import, choose Mock Studio project file and pick
todo-api.mockstudio.json. Select Start server.Check it on the server:
bashcurl http://localhost:4010/healthExpected: a small JSON reply containing
"status": "ok"and the current time.In SecureShell Go, tap the Tunnels button on the host list, then Add tunnel. Fill in:
- Name:
Todo mock - Carried by:
Lab server - Type: Local forward
- Local port:
14010 - Destination host:
localhost - Destination port:
4010
Leave Allow other devices to use it off. Save.
- Name:
In the Tunnels list, switch Todo mock on.
Expected: the tunnel starts and shows how many connections it carries.
Open the phone's browser and go to
http://localhost:14010/health.Expected: the same JSON as in step 2. In Mock Studio on the server, the request appears in Live.
Optional: in ApiWorkbench on the phone, send a GET request to
http://localhost:14010/health.Expected: 200 OK and the same body.
If the page does not load
Keep a terminal session to Lab server open in SecureShell Go while you test: with a session open, Android keeps the app running in the background. If localhost does not work in the browser, try http://127.0.0.1:14010/health. If the tunnel shows an error, set Destination host to 127.0.0.1.
Notice what happened: the phone talked to its own localhost. SecureShell Go carried the connection inside SSH, and the SSH server on the computer opened it to port 4010 there. To Mock Studio, the request came from the computer itself.
Break it, try it
Each of these shows one idea from the lessons. Put things back after each one.
Stop the tunnel. Switch Todo mock off and reload the page. The browser cannot connect at all: nothing on the phone listens on port 14010 now, so the connection is refused. Switch it back on.
Stop the mock. In Mock Studio, stop the server and reload the page, with the tunnel still on. The page still fails, even though the tunnel is running: the tunnel reached the computer, but nothing listened on port 4010 there. Start the server again.
Go direct, then close the door. In the phone's browser, open http://192.168.1.20:4010/health, without the tunnel. It works, because Mock Studio listens on all interfaces (lesson 1). Now, on the server, if sudo ufw status said inactive in part 1, turn on a firewall that allows only SSH from your LAN:
sudo ufw allow from 192.168.1.0/24 to any port 22 proto tcp
sudo ufw enableReload the direct address: it now times out, because the firewall drops it silently. Reload http://localhost:14010/health: it still works. The firewall only lets in port 22, and the tunnel's traffic arrives inside SSH. You undo the firewall in the clean-up.
Forget the host key. On the host list, tap ⋮ › Forget host keys next to Lab server, then connect. The Unknown host dialog appears again: the app no longer trusts the server until you compare the fingerprint once more. Compare it with the server's screen and accept.
Optional: keys only, with a way back
This turns off password sign-in on the server (lesson 5). Your key from part 5 must work first, and you stay at the server's keyboard throughout, so you cannot lock yourself out.
Keep a SecureShell Go session to Lab server open.
On the server, create the settings file:
bashprintf 'PasswordAuthentication no\nKbdInteractiveAuthentication no\nPermitRootLogin no\n' | sudo tee /etc/ssh/sshd_config.d/10-keys-only.confExpected:
teeprints the three lines it wrote.Test the settings, then apply them:
bashsudo sshd -t sudo systemctl restart sshExpected: no output from either command. Your open session in SecureShell Go keeps working.
Try a password sign-in from the server to itself:
bashssh -o PubkeyAuthentication=no maya@localhostThe first time,
sshasks you to check the host key forlocalhost. It is the server's own key: compare it with part 3 and typeyes.Expected:
maya@localhost: Permission denied (publickey).Passwords are no longer accepted.In SecureShell Go, disconnect and connect to Lab server again.
Expected: it connects with your key, as before.
To undo it:
sudo rm /etc/ssh/sshd_config.d/10-keys-only.conf
sudo systemctl restart sshClean up
Do these at the server's keyboard.
In SecureShell Go, open Tunnels and switch Todo mock off, or tap Stop all.
In Mock Studio, stop the server.
If you turned on ufw in "Break it, try it", turn it off again:
bashsudo ufw disableIf ufw was already on before the lab, leave it on, and remove only the rule you added:
sudo ufw status numberedshows each rule with a number, andsudo ufw deletefollowed by that number removes it.Remove the lab key from the server. First find it, then delete that line, keeping a backup:
bashgrep -n "secureshellgo@192.168.1.20" ~/.ssh/authorized_keys sed -i.bak '/secureshellgo@192.168.1.20/d' ~/.ssh/authorized_keysExpected:
grepshows one numbered line. Aftersed, run thegrepagain: it prints nothing. When you are sure nothing else was removed, delete the backup withrm ~/.ssh/authorized_keys.bak. You can also delete the line by hand withnano ~/.ssh/authorized_keys.In SecureShell Go, tap ⋮ next to Lab server and choose Delete. In Delete host?, tick Also forget its trusted host key(s) and confirm. This removes the host, its saved password and its private key from your device.
Delete the lab files on the server:
bashrm ~/from-server.txtDelete the file you uploaded in part 6 too.
If you do not need SSH on this computer, turn it off:
bashsudo systemctl disable --now ssh.socket ssh.serviceOn Ubuntu 22.04, use
sudo systemctl disable --now ssh.Expected:
ss -tln | grep ':22 'prints nothing. If you keep SSH on, consider keeping the keys-only file from the optional part.
Check yourself
Question 1 of 6
In part 4, why do you compare the fingerprint with ssh-keygen -lf run on the server's own screen?
What you learned
- An SSH server on Ubuntu is one package, and
ss -tlnproves it is listening. - The host-key fingerprint is checked against the server's own screen, not the network.
- A key installed in
authorized_keysreplaces the password, and deleting its line takes it away. - SFTP copies files both ways over the same connection.
- A local forward reaches a service on the server through SSH, even when a firewall blocks the service's own port.
Next steps
- Forward ports with tunnels in SecureShell Go
- Todo API lab: test the mock you reached through SSH
- Pair two machines with CrossShell