Host your stuff - Part III
Today we ssh!
Calling this Part III is a bit of a stretch. Part II and 1/2 would be more appropriate, but we do need to talk about shells. Of the secure variety, to be more specific. If you already know how ssh
works, you can sit this one out. For everyone else, let's get to it.
The Secure SHell (a.k.a. ssh
) is a thing people use to access remote computers securely. In the olden times, this was done via telnet
, rsh
, and other horrible things that I dare not mention. The problem with telnet
, rsh
, and the rest of the gang was (well, is) that communication between the client (you) and the server (the remote computer you want to access) are not encrypted. This is problematic for several reasons, but, suffice it to say, you generally don't want people eavesdropping on you. In a way, ssh
is to telnet
and rsh
what https
is to http
.
Cool! But, what's a shell?
A shell is a program that allows you to type commands into a computer, and run them. For example, the Terminal app on macOS computers is, erm... a terminal emulator that runs a shell. Typically, on UNIX-like operating systems like macOS, the various flavors of Linux, the *BSD (FreeBSD, NetBSD, OpenBSD, et al) family, amongst others, the usual suspects are the bash
, zsh
, and, to a lesser extent, fish
shells.
ksh
, tcsh
, pure sh
and whatnot. That's not important to our discussion here. Stop being pedantic! "Well, actually, macOS is also a BSD, because Darwin..." Shush. I know. Why the Terminal app is an emulator, what the differences between the various shells are, and which one is the best are topics for another time. What you do need to know is how to set up and use ssh
, and how to set up and use a normal shell like a normal person. Unless stated otherwise, we'll go with bash
because that's the shell you're most likely to encounter when self-hosting. The overwhelming majority of commands you run on bash
are going to work on zsh
and fish
and the other shells. So, don't worry too much about it for now.
But, what about Windows?
Just kidding. Windows is a bit different. You have the classic cmd.exe
, Powershell, and the new-ish Windows... ready for it? Terminal. We're not going to cover any of this here except for how to ssh
from a Windows system. Why? Because pretty much everything you self-host will be a service that runs on some UNIX-like operating system. Don't know anything about that? Don't worry. You will learn something whether you like it or not.
I'm sold! What do we do now?
Now we learn how to use ssh
. On the next installment, we'll learn how to "secure" the other side of this equation: the server, a.k.a. sshd
.
If you use macOS, pretty much any Linux, or pretty much any BSD, you're all set. ssh
is already there. If you use Windows, you're probably all set, too. On UNIX-like operating systems (macOS, Linux, *BSD), all you have to do is open a terminal and type ssh username@host
. That's it. On Windows, the Powershell will let you do the same thing. The Windows Terminal works, too. The Command Prompt (a.k.a. cmd.exe
) will not work. Other options for Windows are things like puTTY and Mobaxterm, but that's only if you can't use Powershell or Windows Terminal for whatever reason. Or, if you already know what to do.
Let's do that hockey ssh
-ing!
For the sake of argument, let's say we have a brand new Linux virtual machine running somewhere. For now, it doesn't matter where. Let's say this virtual machine has an IP address of 192.168.1.10, and then...
IP address. You will need to understand this bit of networking to follow along. 99% of the time the allocation of an IP address is going to be handled by "someone else." All you need to know is the IP address of the computer you're trying to access. Just installed the Linux virtual machine? Run
ip a
and it's one of those. Can't even access the virtual machine? Your internet router probably knows. Can't find it? Ask for help. Here's the output of the ip a
command from one of my virtual machines:
scarv@sanji:~ » ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether ec:8e:b5:78:f2:c4 brd ff:ff:ff:ff:ff:ff
altname enp0s31f6
inet 192.168.86.125/22 brd 192.168.87.255 scope global dynamic noprefixroute eno1
valid_lft 4223sec preferred_lft 4223sec
It shows two interfaces: lo
is the loopback address. That's a special IP address that points to itself. So, if I'm sitting at this machine and try to access anything with the IP 127.0.0.1, this will take me to this machine. If I ssh
into this address, I am ssh
-ing into the machine I'm ssh
-ing from, which is not terribly useful. However, the loopback interface is useful in many other cases, as we'll see as we go. This address is universal. It's part of the TCP/IP specification. Every computer with a functioning TCP/IP networking stack has this address.
The second interface is the one we are looking for: eno1
in this case. The IP address in question is 192.168.87.125
. Note that these interface names can and do vary, so don't make the mistake of assuming every computer you come across has an interface named eno1
. Don't believe me? Here's the output of another computer I run:
scarv@usopp:~ » ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 96:00:03:ba:de:f2 brd ff:ff:ff:ff:ff:ff
inet 78.46.111.222/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 2a01:4f8:c2c:d01b::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::9400:3ff:feba:def2/64 scope link
valid_lft forever preferred_lft forever
As predicted, the loopback is there, and it has the same 127.0.0.1. Our main interface, though... that's not eno1
. It's called eth0
here. macOS will call it something else. For me it's en1
and the loopback is lo0
(and the command is not ip a
, it's ifconfig
. Which, by the way, will most likely work on Linux, too, but that's not necessarily a given. When in doubt, ip a
on Linux, ifconfig
on macOS):
❯ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether 4e:54:52:3a:2d:d7
inet 192.168.84.54 netmask 0xfffffc00 broadcast 192.168.87.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
Jesus Christ, Scarlett. How the hell am I supposed to memorize all this?
You don't. For now, follow me blindly because this is just theory. Nothing here is going to cause any issues even if you mess up. What I want you to understand is this:
You access the remote computers we will talk about via ssh
. Using ssh
to access the remote computers we will talk about is not different from actually sitting in front of said computer and logging in with your username and password. Using ssh
is cool. I don't think it's even possible to accidentally use telnet
these days, but be advised: don't use telnet
unless you absolutely know what you're doing. Or any other remote shell mechanism. Not even mosh
.
Back to where we were! For the sake of argument, let's say we have a brand new Linux virtual machine running somewhere. For now, it doesn't matter where. Let's say this virtual machine has an IP address of 192.168.1.10. From the computer you are physically in front of, you ssh
into the remote computer by opening a terminal emulator (Terminal app, Ghostty, xterm, Powershell, whatever) and typing ssh username@192.168.1.10
and hitting enter. You should be prompted for your password. Type that great password you have, hit enter, and voilà.
Obviously, you do need to have an account on the remote computer you're accessing via ssh
. Like I said, it's no different from sitting in front of a physical computer and using the keyboard attached to that machine to enter your username and password. We'll cover the installation and username creation in part IV. What you need to know now is this:
ssh username@192.168.1.10
username
being the username you chose for your account when you installed the operating system on the remote computer. If your username is scarv
, your command would be: ssh scarv@192.168.1.10
.
Here's a very detailed and high-fidelity diagram:
+---------+ +----------+
| | | |
| You | -----------> | Remote |
| | ssh | |
+---------+ +----------+
This assumes that your remote computer accepts password logins. Which it shouldn't. For various reasons. So, what I want you to do right now is create a key pair for ssh
by typing the following on your local computer's terminal emulator:
ssh-keygen -t ed25519 -f ~/.ssh/my_ed25519_key
If you're using Windows Terminal or Powershell:
ssh-keygen.exe -t ed25519 -f $HOME\my_ed25519_key
Hit enter a couple of times to leave the passphrase empty. This will generate an Ed25519 key pair that we'll use to access our remote computers without having to type a password every time. What's Ed25519? It doesn't matter. Don't do anything with this for now, and go read a book. Next: we install some operating system!
Stuck? Lost? Befuddled? Come over to our Discord and ask for help. I'm also on Mastodon and Bluesky if you want to talk to me directly.