Host your stuff - Part III

Today we ssh!

Host your stuff - Part III
Photo by Mandy Henry / Unsplash

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.

💡
Before you cry foul and call me a liar: I know. Those BSDs are weird and use things like 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?

T'Challa says "We don't do that here"

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.

💡
There's a bajillion terminal emulators for macOS, Linux, and BSDs out there. iTerm2. Wezterm. Alacritty. Kitty. Ghostty. foot. konsole. gnome-terminal. Terminator. xterm. st. Tabby. Warp. Use what you like. Don't know anything about terminal emulators? Go with Ghostty because it's available for macOS and Linux, and it has very sensible defaults out of the box, so you don't have to futz with config files. Want to futz with config files? Ghostty's got you covered, too.

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...

💡
Whoa, whoa, whoa. Wait. An IP what now?

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.