<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Guy Friley</title>
    <description>The latest articles on DEV Community by Guy Friley (@dragooner4788).</description>
    <link>https://dev.to/dragooner4788</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3838686%2F443ab97e-2f04-4c01-9d54-118d357ae262.jpeg</url>
      <title>DEV Community: Guy Friley</title>
      <link>https://dev.to/dragooner4788</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dragooner4788"/>
    <language>en</language>
    <item>
      <title>Hardening Linux on Raspberry Pi 5</title>
      <dc:creator>Guy Friley</dc:creator>
      <pubDate>Sun, 12 Apr 2026 03:19:37 +0000</pubDate>
      <link>https://dev.to/dragooner4788/hardening-linux-on-raspberry-pi-5-52k4</link>
      <guid>https://dev.to/dragooner4788/hardening-linux-on-raspberry-pi-5-52k4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial we will go over how to &lt;em&gt;harden&lt;/em&gt; a Linux system. In this tutorial I will be going over hardening Raspbian OS on a Raspberry Pi 5, but this tutorial should work across all distributions of Linux.&lt;/p&gt;

&lt;p&gt;I will go over: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enabling the &lt;strong&gt;SSH Server&lt;/strong&gt; on &lt;a href="https://www.raspberrypi.com/documentation/computers/os.html" rel="noopener noreferrer"&gt;Rasbian OS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Generating &lt;em&gt;asymmetric encryption&lt;/em&gt; key pair:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Key&lt;/strong&gt;: Goes onto the Raspberry Pi 5 - think of the &lt;em&gt;public key&lt;/em&gt; as the &lt;em&gt;lock&lt;/em&gt; which locks down the Raspberry Pi or remote device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Key&lt;/strong&gt;: Stays on the client device - think of the &lt;em&gt;private key&lt;/em&gt; as the &lt;em&gt;key&lt;/em&gt; to unlock the lock once a device has a lock put on it. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Copying the &lt;em&gt;public key&lt;/em&gt; to the Raspberry Pi 5&lt;/li&gt;
&lt;li&gt;Configuring the &lt;strong&gt;SSH&lt;/strong&gt; configuration file on Raspbian OS

&lt;ul&gt;
&lt;li&gt;Disable &lt;em&gt;Password Authentication&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Disable &lt;em&gt;X11&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Disable &lt;em&gt;Root Login&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Change the maximum amount of tries to authenticate to the remote device&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;System Hardening&lt;/strong&gt; is a good practice especially if we are going to be remoting into the devices, and we are going to be running services, or building projects with the devices. &lt;em&gt;System Hardening&lt;/em&gt; is that act of what we will be doing in this tutorial of ensuring we reduce the &lt;em&gt;attack surface&lt;/em&gt; of our system so it makes it more difficult for a &lt;em&gt;bad actor&lt;/em&gt; to gain access into our system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Enabling SSH on the Raspberry Pi
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Raspbian OS&lt;/em&gt; has the &lt;strong&gt;SSH Server&lt;/strong&gt; disabled by default, so we will need to ensure that we enable this service. &lt;em&gt;SSH&lt;/em&gt; stands for &lt;em&gt;Secure Shell&lt;/em&gt; and is the application that we use within the &lt;em&gt;terminal&lt;/em&gt; to initiate a &lt;em&gt;remote session&lt;/em&gt; to a &lt;em&gt;remote host&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;The reason we are enabling &lt;em&gt;SSH&lt;/em&gt; is so that we can login to the Raspberry Pi without needing to have it connected to a mouse, keyboard and monitor. The Raspberry Pi may not necessarily be a &lt;em&gt;remote host&lt;/em&gt; as in it is in some space which is inaccessible to you, but the benefits would include that you can use the system while you are in one part of your house, and the Raspberry Pi is in another. &lt;/p&gt;

&lt;p&gt;Note that without &lt;em&gt;port forwarding&lt;/em&gt; you will not be able to login to the Raspberry Pi if you are trying to access the device outside of the &lt;em&gt;Local Area Network (LAN)&lt;/em&gt;. Instead of taking the time to assign the device a &lt;em&gt;static IP address&lt;/em&gt; and enabling &lt;em&gt;port forwarding&lt;/em&gt; you can use a service like &lt;em&gt;&lt;a href="https://tailscale.com/" rel="noopener noreferrer"&gt;Tailscale&lt;/a&gt;&lt;/em&gt; to ensure that you can access your device outside of the LAN. &lt;/p&gt;

&lt;p&gt;I find Tailscale to be more secure, and easier to set up on my devices which I am using as part of my home lab than to configure port forwarding. Tailscale is a &lt;em&gt;virtual private network (VPN)&lt;/em&gt; mesh which you can configure on your devices, and this &lt;em&gt;will&lt;/em&gt; allow you to access your devices which are not on the same LAN and it will be more secure to boot. &lt;/p&gt;

&lt;p&gt;Enough lecture, let's get to enabling SSH: &lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Heads Up&lt;/strong&gt;: Ensure for this portion, you have a &lt;em&gt;keyboard&lt;/em&gt;, &lt;em&gt;mouse&lt;/em&gt;, and &lt;em&gt;monitor&lt;/em&gt; connected to the Raspberry Pi.&lt;br&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Open &lt;em&gt;terminal&lt;/em&gt; (CTRL + CMD (WIN) + T) -or- clicking on the &lt;em&gt;terminal&lt;/em&gt; icon.&lt;/li&gt;
&lt;li&gt;Type in &lt;code&gt;sudo raspi-config&lt;/code&gt; into the terminal. This will open up the &lt;strong&gt;Raspberry Pi Software Configuration Tool&lt;/strong&gt;. We will select &lt;strong&gt;Interface Options&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foszdpminj4oheovvtexl.png" alt="raspi-config Interface Config Menu" width="800" height="505"&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;SSH&lt;/strong&gt; from the menu.

&lt;ul&gt;
&lt;li&gt;The tool will prompt you to confirm whether you want to enable &lt;strong&gt;SSH Server&lt;/strong&gt;, select &lt;strong&gt;Yes&lt;/strong&gt;. 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8ifir236qf4bw8dll4z.png" alt="raspi-config Enable SSH" width="800" height="502"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This should enable the &lt;strong&gt;SSH Server&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To confirm that &lt;em&gt;SSH&lt;/em&gt; is enabled, you can type in the following command into the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enabling SSH Through the Terminal (without Raspberry Pi Configuration Tool)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the command &lt;code&gt;sudo systemctl enable ssh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Restart &lt;strong&gt;SSH&lt;/strong&gt; for good measure, &lt;code&gt;sudo systemctl restart ssh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verify &lt;strong&gt;SSH&lt;/strong&gt; is running, &lt;code&gt;sudo systemctl status ssh&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Either method gets us to the same place. RaspbianOS just has a cool tool to do it for you. &lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;whoami&lt;/code&gt; in the terminal to get your username, and run &lt;code&gt;hostname&lt;/code&gt; to get the name of the device. You can run &lt;code&gt;hostname -i&lt;/code&gt; to get the IP Address of the host. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IP Address&lt;/strong&gt;: This is your &lt;em&gt;Internet Protocol Address&lt;/em&gt; and it gets assigned to a host (computer) via &lt;strong&gt;DHCP (Dynamic Host Configuration Protocol)&lt;/strong&gt; which assigns IP Addresses to computers (called hosts) automatically for some length of time, where the length of time is called a &lt;strong&gt;lease&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In a &lt;em&gt;local area network&lt;/em&gt; IP Addresses are private, and use &lt;em&gt;Network Address Translation&lt;/em&gt; when reaching the &lt;em&gt;Gateway (Router)&lt;/em&gt; to reach out to the &lt;em&gt;Internet&lt;/em&gt;. So when a host is on a home local area network, it is utilizing &lt;em&gt;private IP Addresses&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;This is the reason why you cannot reach a host outside of the local area network is because the IP Addresses assigned are private, and need to reach the gateway in order to reach out to the Internet using Network Address Translation, where it will assume the public IP Address provided to the router given by the &lt;strong&gt;ISP (Internet Service Provider)&lt;/strong&gt;. You can ensure that a host is publicly accessible like I stated previously by using &lt;strong&gt;Port Forwarding&lt;/strong&gt; but this is risky, and it's better to just use Tailscale which sits on top of your devices, and you can use the VPN to create a 'local network' for all of the devices which will be a part of the home lab. &lt;/p&gt;

&lt;h3&gt;
  
  
  Verify SSH Works
&lt;/h3&gt;

&lt;p&gt;Before removing the keyboard, mouse and monitor (or old TV you're using as a makeshift monitor), check to ensure that you can actually access the Raspberry Pi remotely: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On the client device (the device you will be using to SSH into the Raspberry Pi) type in &lt;code&gt;ssh &amp;lt;username&amp;gt;@&amp;lt;hostname&amp;gt;&lt;/code&gt; or &lt;code&gt;ssh &amp;lt;username&amp;gt;@&amp;lt;ip-address&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you are able to login, then we can disconnect the peripherals. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When connecting to a host using &lt;strong&gt;SSH&lt;/strong&gt; one thing to keep in mind is that because a device will be using &lt;strong&gt;DHCP&lt;/strong&gt; unless you have configured it with an IP Address from the network which is outside the range of use for the DHCP service, the IP Address is likely to change, but if you reference a host by its  &lt;em&gt;Domain Name&lt;/em&gt; or &lt;em&gt;hostname&lt;/em&gt; you should be good to go. A &lt;strong&gt;Domain Name&lt;/strong&gt; is a label given to an IP Address to make it easier to reference a host, or a website by the domain name instead of trying to remember its IP Address. &lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Generating Encryption Keys
&lt;/h2&gt;

&lt;p&gt;In this section we will generate &lt;em&gt;asymmetric encryption keys&lt;/em&gt; from our &lt;em&gt;client device&lt;/em&gt; (the device we will use to login remotely to the Raspberry Pi). &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the terminal.&lt;/li&gt;
&lt;li&gt;Enter in &lt;code&gt;ssh-keygen -t ed25519 -C "&amp;lt;username&amp;gt;@&amp;lt;client-machine/hostname&amp;gt;&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ssh-keygen&lt;/code&gt;: We are telling our machine to create a pair of keys.

&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;private key&lt;/em&gt; which we keep on the &lt;em&gt;client machine&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;public key&lt;/em&gt; which we will share to the &lt;em&gt;remote host&lt;/em&gt; (Raspberry Pi 5)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-t ed25519&lt;/code&gt;: We are telling the command what kind of encryption to use.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-C "&amp;lt;username&amp;gt;@&amp;lt;hostname&amp;gt;"&lt;/code&gt;: This is the &lt;em&gt;label&lt;/em&gt; we are going to provide the key. 

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;jsmith@macbook-pro&lt;/code&gt; for example is what the label would look like.&lt;/li&gt;
&lt;li&gt;We want to ensure we create a &lt;em&gt;meaningful&lt;/em&gt; label. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The program will prompt you for a &lt;em&gt;passphrase&lt;/em&gt; and this is essentially the password you will now use to login remotely to this Raspberry Pi when using encryption. 

&lt;ul&gt;
&lt;li&gt;The reason we create the passphrase is to ensure we make the private key really secure. This way, even if the private key is compromised (stolen), if they don't know the passphrase, they won't be able to login. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Verify the keys were created: &lt;code&gt;ls -la ~/.ssh&lt;/code&gt;. You should see:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id_ed25519&lt;/code&gt; which is the &lt;em&gt;private key&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id_ed25519.pub&lt;/code&gt; which is the &lt;em&gt;public key&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Note&lt;/strong&gt;: This is if you left the default label, or did not specify a label. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you specified a label for the keys, then they will follow the pattern which you used in the &lt;code&gt;-C&lt;/code&gt; portion of the command above. You can and &lt;em&gt;should&lt;/em&gt; ensure you label these keys in a way that makes sense to you. The &lt;code&gt;-C&lt;/code&gt; is a comment about the key. To name the key, you would use the &lt;code&gt;-f&lt;/code&gt; command. &lt;/p&gt;

&lt;p&gt;You should also rename the actual key &lt;code&gt;id_ed25519&lt;/code&gt; to something like &lt;code&gt;id_ed25519_homelab&lt;/code&gt; or some other naming convention which makes sense to you so you don't accidentally overwrite your keys. You can do this by using the command &lt;code&gt;mv id_ed25519 id_ed25519_&amp;lt;label&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now that the key pair was generated, we have the &lt;em&gt;lock (public key)&lt;/em&gt; which we will copy over to the Raspberry Pi, and we have the &lt;em&gt;key (private key)&lt;/em&gt; which we will use to &lt;em&gt;unlock&lt;/em&gt; the lock when we login to the remote client. Instead of using &lt;em&gt;Password Authentication&lt;/em&gt; we will now be authenticating with our keys instead. &lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Copying the Public Key to the Raspberry Pi
&lt;/h2&gt;

&lt;p&gt;In this section, we will be copying our public key over to the Raspberry Pi so that we can login with our key instead of password authentication, and continue along with hardening our system. We want to ensure we get the public key copied over to the remote client before we continue to harden the system or we may lock ourselves out of our machine. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open up terminal if it's not up already. &lt;/li&gt;
&lt;li&gt;Enter in &lt;code&gt;ssh-copy-id username@server-hostname&lt;/code&gt; or &lt;code&gt;ssh-copy-id username@host-ip&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;You are copying this to whatever username and hostname you created for your Raspberry Pi 5, or remote client (if you are doing this on another device). &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Verify Key-based Authentication Works - &lt;code&gt;ssh username@hostname&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;It will ask for your &lt;em&gt;passphrase&lt;/em&gt; - this means that &lt;em&gt;key-based authentication&lt;/em&gt; works. &lt;/li&gt;
&lt;li&gt;It should log you into the remote client. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We tested &lt;em&gt;key-based authentication&lt;/em&gt; first before disabling &lt;em&gt;password authentication&lt;/em&gt; to ensure we are able to login this way. This prevents us from being &lt;em&gt;locked out&lt;/em&gt; of our system. &lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Configuring the SSH Configuration File
&lt;/h2&gt;

&lt;p&gt;Now that we have &lt;strong&gt;SSH&lt;/strong&gt; and &lt;strong&gt;Key-Based Authentication&lt;/strong&gt; enabled we can go ahead and configure the &lt;strong&gt;SSH Configuration&lt;/strong&gt; file. &lt;/p&gt;

&lt;p&gt;These are the settings we need to configure: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PermitRootlogin&lt;/code&gt;: We want to ensure we prevent direct SSH Login as root. 

&lt;ul&gt;
&lt;li&gt;Value: &lt;code&gt;no&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Root can do anything, so we want to ensure we disable this and use &lt;code&gt;sudo&lt;/code&gt; when we need to do something. &lt;/li&gt;
&lt;li&gt;Disabling Root Login reduces an attack surface. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;PasswordAuthentication&lt;/code&gt;: We want to ensure we use keys only.

&lt;ul&gt;
&lt;li&gt;Value: &lt;code&gt;no&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Since we have keys, we don't need to SSH in with our password. &lt;/li&gt;
&lt;li&gt;Disabling Password Authentication reduces an attack surface. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;X11Forwarding&lt;/code&gt;: We don't need to see the GUI for applications, since we will be using the command-line. You can leave this enabled if you need GUI access to the machine. 

&lt;ul&gt;
&lt;li&gt;Value: &lt;code&gt;no&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reduces an attack surface.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;MaxAuthTries&lt;/code&gt;: We want to limit this from 6 to 3. 

&lt;ul&gt;
&lt;li&gt;Value: &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;This is minor security hygiene but we don't want to give an attacker a lot of tries. &lt;/li&gt;
&lt;li&gt;Reduces an attack surface. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For all of the above settings, you want to ensure you remove the comment in front of them (#) so they will be recognized. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the terminal.&lt;/li&gt;
&lt;li&gt;Go to /etc/ssh&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;nano&lt;/code&gt; to open sshd_config: &lt;code&gt;sudo nano sshd_config&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Find the above settings, and set the values to the specified value. &lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;crtl-o&lt;/code&gt; and then &lt;code&gt;ctrl-x&lt;/code&gt; in &lt;code&gt;nano&lt;/code&gt; to close the file. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before closing out of the session here, open a new terminal window, and try to login now. We want to just test once more before we close of out the session to ensure that we can still login before losing access entirely. &lt;/p&gt;

&lt;p&gt;If you are able to login, then we have successfully hardened out system. &lt;/p&gt;

&lt;h3&gt;
  
  
  Protecting Your Key
&lt;/h3&gt;

&lt;p&gt;If your private key is lost (laptop dies, drive wiped) and password auth is disabled, you're locked out over the network. On a homelab machine, you can recover by plugging in a keyboard and monitor and logging in locally to either re-enable password auth or add a new public key.&lt;/p&gt;

&lt;p&gt;Precautions against lockout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Back up your private key&lt;/strong&gt; to an encrypted USB drive or a password manager that supports file attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate keys from multiple devices&lt;/strong&gt; and add all public keys to &lt;code&gt;authorized_keys&lt;/code&gt; — it supports multiple entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Physical access is your safety net&lt;/strong&gt; — this is a major advantage of a homelab over a cloud VPS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other Hardening Steps
&lt;/h2&gt;

&lt;p&gt;Another hardening step to take would be to set up your &lt;strong&gt;iptables&lt;/strong&gt; using &lt;em&gt;ufw (uncomplicated firewall)&lt;/em&gt; to ensure we are only allowing the ports we need open to stay open. &lt;/p&gt;

&lt;p&gt;I won't go through &lt;code&gt;iptables&lt;/code&gt; or &lt;code&gt;ufw&lt;/code&gt; in this tutorial because I have not enabled them yet myself on my Raspberry Pi's due to the fact that I am using &lt;em&gt;Tailscale&lt;/em&gt; and I have created a &lt;em&gt;Tailnet&lt;/em&gt; although this will be one of my next steps, as well as using &lt;em&gt;Fail2Ban&lt;/em&gt; which I have not setup fully just yet. &lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://man.openbsd.org/sshd_config" rel="noopener noreferrer"&gt;OpenSSH Manual — sshd_config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://infosec.mozilla.org/guidelines/openssh" rel="noopener noreferrer"&gt;Mozilla SSH Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>raspberrypi</category>
      <category>security</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Understanding Local and Remote Hosts Using SSH + SCP + Python HTTP Server</title>
      <dc:creator>Guy Friley</dc:creator>
      <pubDate>Wed, 01 Apr 2026 19:51:29 +0000</pubDate>
      <link>https://dev.to/dragooner4788/understanding-local-and-remote-hosts-using-ssh-scp-python-http-server-a90</link>
      <guid>https://dev.to/dragooner4788/understanding-local-and-remote-hosts-using-ssh-scp-python-http-server-a90</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Today I've been learning more about &lt;em&gt;Linux&lt;/em&gt;, and more specifically the &lt;strong&gt;Linux Command Line&lt;/strong&gt;. I have been learning Linux through a combination of reading &lt;em&gt;The Linux Command Line: A Complete Introduction&lt;/em&gt; by &lt;strong&gt;William Shotts&lt;/strong&gt; and using online resources such as &lt;strong&gt;KodeKloud&lt;/strong&gt; and &lt;strong&gt;TryHackMe&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;I want to share today what I have learned about &lt;strong&gt;Secure Shell&lt;/strong&gt;, &lt;strong&gt;Secure Copy&lt;/strong&gt;, and &lt;strong&gt;HTTP Server&lt;/strong&gt; using &lt;strong&gt;Python&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Login to a remote host using SSH.&lt;/li&gt;
&lt;li&gt;Transfer a file using SCP&lt;/li&gt;
&lt;li&gt;Host a file in a directory being used as a Web Server using Python's HTTP module. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Login to a Remote Host
&lt;/h2&gt;

&lt;p&gt;At some point while using Linux, and managing a system(s), there will be a need to remote into another machine using the command line. In order to achieve this, we will need to use Secure Shell (&lt;code&gt;ssh&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Before being able to login to a remote host, we need to ensure we have credentials for that remote machine. If we do not, we won't be able to login. &lt;/p&gt;

&lt;p&gt;We also need to know the &lt;code&gt;ip&lt;/code&gt; address of the remote host.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh &amp;lt;remote_host_username&amp;gt;@&amp;lt;ip-address&amp;gt;&lt;/code&gt; - This will then prompt us for our password. &lt;/p&gt;

&lt;p&gt;Once we have those items, we can login, and it's a simple process. We can do all of the things (as long as we have permissions with the credentials we logged in as) that we can do on our local host. &lt;/p&gt;

&lt;h2&gt;
  
  
  Transfer a fil using scp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secure Copy&lt;/strong&gt; or &lt;code&gt;scp&lt;/code&gt; is a way to transfer files/directories from our local host to our remote host and vice versa. It is secure because &lt;code&gt;scp&lt;/code&gt; uses the &lt;code&gt;ssh&lt;/code&gt; protocol to transfer the files/directory by ensuring that we use authentication, and encryption to send and receive the files. &lt;/p&gt;

&lt;p&gt;To send from local host to remote: &lt;br&gt;
&lt;code&gt;scp &amp;lt;file_to_transfer&amp;gt; &amp;lt;username&amp;gt;@&amp;lt;remote_host_ip&amp;gt;:&amp;lt;path&amp;gt;&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;To receive from remote host to local: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;scp &amp;lt;username&amp;gt;@&amp;lt;remote_host_ip&amp;gt;:&amp;lt;path&amp;gt; &amp;lt;path_to_put_file_on_local_host&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Server with Python HTTP Server
&lt;/h2&gt;

&lt;p&gt;We can serve files from a host by using the HTTP module from Python. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select a directory we want to serve files from: 
&lt;code&gt;cd &amp;lt;path_to_webserver_directory&amp;gt;&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;python3 -m http.server&lt;/code&gt; and this will start running our service. Once we do this, it will run in that terminal, so we will need to run a different terminal. &lt;/li&gt;
&lt;li&gt;We can then use &lt;code&gt;wget&lt;/code&gt; to retrieve files from the remote host. http will run on port 8000, so we need to remember to add the port to the end of our ip address so the command knows what port the http service is running on. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;wget &amp;lt;http://ip-address:8000/my_file&amp;gt;&lt;/code&gt; and this will retrieve the file and put it in your working directory. &lt;/p&gt;

&lt;p&gt;This is just a simple post to update what I have been learning today. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>cli</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating a Guessing Game with Python</title>
      <dc:creator>Guy Friley</dc:creator>
      <pubDate>Sun, 22 Mar 2026 17:19:30 +0000</pubDate>
      <link>https://dev.to/dragooner4788/creating-a-guessing-game-with-python-gn7</link>
      <guid>https://dev.to/dragooner4788/creating-a-guessing-game-with-python-gn7</guid>
      <description>&lt;h2&gt;
  
  
  Hello World!
&lt;/h2&gt;

&lt;p&gt;I decided that I would try putting my learning journey out there by creating a Github Repository and focusing on building and iterating over a &lt;strong&gt;Guessing Game&lt;/strong&gt; developed with &lt;strong&gt;Python&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The reason for doing this is to reinforce my Python learning journey, and to starting building things (however small) instead of getting stuck in Tutorial Hell. &lt;/p&gt;

&lt;p&gt;One thing I couldn't grasp, is how to capture errors, such as ValueError. Today, I did some reading, and decided to implement it into my simple game using &lt;em&gt;Try-Except&lt;/em&gt; and &lt;em&gt;ValueError&lt;/em&gt; as e. I did this so I could output the error in a print() statement. &lt;/p&gt;

&lt;h2&gt;
  
  
  Generate Random Number for Number to Guess:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Generates a number from 1 - 10 inclusive
&lt;/span&gt;&lt;span class="n"&gt;my_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;generates&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="n"&gt;being&lt;/span&gt; &lt;span class="n"&gt;inclusive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set Number of Guesses User has to guess the number:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Set variable num_guesses to 3
&lt;/span&gt;&lt;span class="n"&gt;num_guesses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;Currently&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;hard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;coded&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;guesses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;later&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;editable&lt;/span&gt; &lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Definition for Guessing the Number and Handling Errors:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# I put the guess number functionality inside of a function so we can reuse it.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;guess_input&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;guess_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Guess my Number (1 - 10): &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="c1"&gt;# We are checking to see if the number input by the user is within range. If it is not, we are providing them with the error message below.
&lt;/span&gt;        &lt;span class="c1"&gt;# I think there is an official way to do this, but for oour purposes, this is good enough.
&lt;/span&gt;
        &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guess_number&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guess_number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid Input: Provided number is out of range. Please enter a number from 1 - 10&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Except is catching all input which is not an Integer. Even a float.
&lt;/span&gt;    &lt;span class="c1"&gt;# This is happening because we wrapped the input with int() to ensure that our input is an Integer.
&lt;/span&gt;    &lt;span class="c1"&gt;# If it is anything other than an Integer, we are catching it with `ValueError`
&lt;/span&gt;    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ivalid Input: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Please enter a number.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;guess_number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested this out using characters other than an Integer such as a Float, 'A', '!', etc to ensure it works. I also just pressed enter to see how it handles not being given any sort of character. &lt;/p&gt;

&lt;p&gt;I also wanted to ensure that a user can only enter in a value from 1 to 10. &lt;/p&gt;

&lt;h2&gt;
  
  
  The While Loop for the Game
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;num_guesses&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user_guess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;guess_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_guess&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;my_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You guessed my number! It was &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;my_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;num_guesses&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# This needs to go BEFORE the PRINT statement I do believe.
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;That guess, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_guess&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is not my number.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Remaining Guesses:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num_guesses&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Try again!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
