Files
blog-ahmza-com/public/posts/securing-ssh/index.html
T
2023-11-10 23:24:28 +00:00

245 lines
52 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html><html lang=en dir=auto><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=robots content="index, follow"><title>Securing SSH 🤖 | ahmza's ramblings</title>
<meta name=keywords content="HomeLab,SSH,RemoteAccess"><meta name=description content="Ever wanted to make your SSH connections more secure. Read this"><meta name=author content="ahmza"><link rel=canonical href=https://blog.ahmza.com/Page%28/posts/securing-ssh.md%29><link crossorigin=anonymous href=/assets/css/stylesheet.49e35863ac4b53ab71c7e3249dd5e722c701ee07f8d0cb006a4f4e954364b6fe.css integrity="sha256-SeNYY6xLU6txx+MkndXnIscB7gf40MsAak9OlUNktv4=" rel="preload stylesheet" as=style><script defer crossorigin=anonymous src=/assets/js/highlight.f413e19d0714851f6474e7ee9632408e58ac146fbdbe62747134bea2fa3415e0.js integrity="sha256-9BPhnQcUhR9kdOfuljJAjlisFG+9vmJ0cTS+ovo0FeA=" onload=hljs.initHighlightingOnLoad()></script><link rel=icon href=https://blog.ahmza.com/img/favicon.png><link rel=icon type=image/png sizes=16x16 href=https://blog.ahmza.com/img/favicon.png><link rel=icon type=image/png sizes=32x32 href=https://blog.ahmza.com/img/favicon.png><link rel=apple-touch-icon href=https://blog.ahmza.com/img/favicon.png><link rel=mask-icon href=https://blog.ahmza.com/img/favicon.png><meta name=theme-color content="#2e2e33"><meta name=msapplication-TileColor content="#2e2e33"><noscript><style>#theme-toggle,.top-link{display:none}</style></noscript><script async src="https://www.googletagmanager.com/gtag/js?id=G-HSJHLHP8FZ"></script><script>var doNotTrack=!1;if(!doNotTrack){window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date),gtag("config","G-HSJHLHP8FZ",{anonymize_ip:!1})}</script><meta property="og:title" content="Securing SSH 🤖"><meta property="og:description" content="Ever wanted to make your SSH connections more secure. Read this"><meta property="og:type" content="article"><meta property="og:url" content="https://blog.ahmza.com/posts/securing-ssh/"><meta property="og:image" content="https://blog.ahmza.com/webp/posts/secure-ssh/feature-anim.webp"><meta property="article:section" content="posts"><meta property="article:published_time" content="2021-12-07T22:41:02+00:00"><meta property="article:modified_time" content="2021-12-07T22:41:02+00:00"><meta property="og:site_name" content="ahmza's ramblings"><meta name=twitter:card content="summary_large_image"><meta name=twitter:image content="https://blog.ahmza.com/webp/posts/secure-ssh/feature-anim.webp"><meta name=twitter:title content="Securing SSH 🤖"><meta name=twitter:description content="Ever wanted to make your SSH connections more secure. Read this"><script type=application/ld+json>{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":2,"name":"Posts","item":"https://blog.ahmza.com/posts/"},{"@type":"ListItem","position":3,"name":"Securing SSH 🤖","item":"https://blog.ahmza.com/posts/securing-ssh/"}]}</script><script type=application/ld+json>{"@context":"https://schema.org","@type":"BlogPosting","headline":"Securing SSH 🤖","name":"Securing SSH 🤖","description":"Ever wanted to make your SSH connections more secure. Read this","keywords":["HomeLab","SSH","RemoteAccess"],"articleBody":"Introduction SSH is a widely used protocol to access remote devices. The problem with SSH is at the authentication stage, Brute force attacks are one of the ways an SSH connection can be compromised. A malicious actor will constantly hammer the remote host with different passwords until it can gain access. With further configuration of SSH we can make the service a lot more secure.\nConfigure SSH Famous last words: Configuring SSH like many things in Linux is as simple as editing a few config files\nAlways be sure to create a backup file it’s very easy to end up locking yourself out of a device.\nI would recommend practising on a machine that is not critical.\nCreate SSH Keys SSH keys use public and private key encryption for authentication.\nTo create a set of keys, on the client do:\nssh-keygen You will be asked where you want to save the keys, I recommend the default location for less hair pulling later.\nEnter file in which to save the key (/home/user/.ssh/id_rsa): You will be asked to enter a password for the ssh keys, be sure to use a strong password.\nEnter passphrase (empty for no passphrase): Once that is done you will see a confirmation screen like the one below\nOutput Your identification has been saved in /home/user/.ssh/id_rsa Your public key has been saved in /home/user/.ssh/id_rsa.pub The key fingerprint is: SHA256:tIurljnWJRBc1RnHUJQ5GtND7p9HWKnjV6zjE9AFR1Y user@host The key's randomart image is: +---[RSA 3072]----+ | . .....oX=o.oE| | o =oB oo| | . . +.+ o.| | . . .... o+ | | . S .+. +| | .... ..o+.| | +.o. .=o.| | * .. .oo | | o.o. .. | +----[SHA256]-----+ Copy SSH Keys Quick note: user@host is the username on the remeote host you would like to copy your public key to.\nssh-copy-id user@host If asked to confirm the connection to the remote host answer yes, this happens when a new machine with an unknown identity wants to connect to the client.\nOutput The authenticity of host 'host(host)' can't be established. ECDSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx. Are you sure you want to continue connecting (yes/no)? yes You will then be asked to enter a password for the user on the remote host\nOutput /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys user@host's password: If successful you should be able to access the device using the SSH key\nTo verify this, SSH to the device and it should ask for the Keys’s password not the users\nEnter passphrase for key '/home/user/.ssh/id_rsa': Modify SSH Config create a backup\nsudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak open the original file in a text editor\nsudo vim /etc/ssh/sshd_config For a new user this might be daunting. Take your time and you will be fine 😊\nLines we want to modify\nQuick note: you may need to uncomment some lines as well as add a few\nProtocol 2 - add to line 15 Port 2222 - modify line 17 PermitRootLogin no - modify line 36 Max Auth Tries 5 - modify line 38 PasswordAuthentication no - modify line 60 PermitEmptyPasswords no -modify line 61 AllowUsers ahmza - add line 67 ClientAliveInterval 180 - modify line 104 # $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin # The strategy used for options in the default sshd_config shipped with # OpenSSH is to specify options with their default value where # possible, but leave them commented. Uncommented options override the # default value. Include /etc/ssh/sshd_config.d/*.conf Protocol 2 Port 2222 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key #HostKey /etc/ssh/ssh_host_ed25519_key # Ciphers and keying #RekeyLimit default none # Logging #SyslogFacility AUTH #LogLevel INFO # Authentication: #LoginGraceTime 2m PermitRootLogin no #StrictModes yes MaxAuthTries 5 #MaxSessions 10 #PubkeyAuthentication yes # Expect .ssh/authorized_keys2 to be disregarded by default in future. #AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 #AuthorizedPrincipalsFile none #AuthorizedKeysCommand none #AuthorizedKeysCommandUser nobody # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts #HostbasedAuthentication no # Change to yes if you don't trust ~/.ssh/known_hosts for # HostbasedAuthentication #IgnoreUserKnownHosts no # Don't read the user's ~/.rhosts and ~/.shosts files #IgnoreRhosts yes # To disable tunneled clear text passwords, change to no here! PasswordAuthentication no PermitEmptyPasswords no AllowUsers ahmza # Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) ChallengeResponseAuthentication no # Kerberos options #KerberosAuthentication no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes #KerberosGetAFSToken no # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes #GSSAPIStrictAcceptorCheck yes #GSSAPIKeyExchange no # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the ChallengeResponseAuthentication and # PasswordAuthentication. Depending on your PAM configuration, # PAM authentication via ChallengeResponseAuthentication may bypass # the setting of \"PermitRootLogin without-password\". # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and ChallengeResponseAuthentication to 'no'. UsePAM yes #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no X11Forwarding yes #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes PrintMotd no #PrintLastLog yes #TCPKeepAlive yes #PermitUserEnvironment no #Compression delayed ClientAliveInterval 180 #ClientAliveCountMax 3 #UseDNS no #PidFile /var/run/sshd.pid #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none #VersionAddendum none # no default banner path #Banner none # Allow client to pass locale environment variables AcceptEnv LANG LC_* # override default of no subsystems Subsystem sftp /usr/lib/openssh/sftp-server # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server Now lets explain what we just did\nProtocol 2 - released in 2006, SSH2 introduced improved encryption algorithms. Port 2222 - The port number can be whatever number you want. Choose something other than 22 this will help hide your device from malicious actors PermitRootLogin no - If the root account were to be compromised then the attacker has full control of the system so we stop it from being able to log in. MaxAuthTries 5 - After 5 failed attempts the remote host blocks requests from that IP for a period of time. PasswordAuthentication no - We have the SSH key installed so we no longer need to have password authentication. PermitEmptyPasswords no - We don’t want to allow empty passwords to be used as authentication for obvious reasons. AllowUsers username - Add the usernames of users you want to be able to connect to the remote host and other users trying to connect will be dropped. Client Alive Interval 180 - Drop the connection after a certain period of inactivity Check were able to connect restart sshd service\nsudo systemctl restart sshd Keep the current SSH connection open and create a new session.\nIf you are able to connect to the remote hosts then you are all set. If not then you still have the initial connection to the remote host to roll back the changes and troubleshoot.\nSuccess Setting up Fail2Ban Fail2Ban is an intrusion prevention tool. Although we are slowing bots down with MaxAuthTries the attacker is still able to carry on brute forcing. Which is what Fail2Ban is for, it actually blocks the connections from that IP.\nInstall Fail2Ban We will install Fail2Ban on the remote host First upgrade any packages, then install Fail2Ban\nsudo apt update \u0026\u0026 sudo apt upgrade sudo apt install fail2ban Now we need to enable the service so it starts when the remote host starts\nsudo systemctl enable --now fail2ban Configure Fail2Ban The Fail2Ban config file we want to edit is called jail.local located in /etc/fail2ban/ open jail.local in your editor of choice\nsudo vim /etc/fail2ban/jail.local The config for Fail2Ban is a lot shorter than sshd so this should be quick\n[DEFAULT] bantime = 8h ignoreip = 127.0.0.1 \u003cip addresses to be ignored\u003e ignoreself = true [sshd] enabled = true port = 2222 filter = sshd logpath = /var/log/auth.log maxretry = 3 findtime = 10m [Default] - Settings in here apply to all jails\nbantime - how long the ban will last ignoreip - IP addresses to ignore ignoreself - stops from locking itself out [sshd] - this is the jail for sshd\nenabled - decides weather the jail is active or not port - the port number the service filter - tells the jail which filter to use from /etc/fail2ban/filter.d logpath - where the log you want fail2ban to read is maxretry - Times the client can attempt a login before being banned findtime - An amount of time which maxretry must occur to trigger a ban for example in 10 minutes if 3 failed login attempts are made the ban the IP Restart Fail2Ban to load the configuration\nsudo systemctl restart fail2ban Testing Fail2Ban To test Fail2Ban lets create a test user and set a password for the user\nsudo useradd test sudo passwd test open the sshd config\nsudo vim /etc/ssh/sshd_config modify the line PasswordAuthentication to say yes and add the test user to AllowUsers\nPasswordAuthentication yes AllowUsers user test restart the sshd service\nsudo systemctl restart sshd Attempt to login to the remote host using the test account using an incorrect password. After 3 failed attempts it should say connection refused.\nssh test@host -p 2222 Fail2Ban should do something along the lines of … log back in as your normal user, remove the test user and restore the sshd config.\nTo remove the user\nsudo userdel test restore the /etc/ssh/sshd_config file\nsudo vim /etc/ssh/sshd_config Set PasswordAuthentication back to no and remove test from AllowUsers\nPasswordAuthentication no AllowUsers user Conclusion well done, you managed to make it through all that !! At least now you can be reassured that if them pesky brute-force attackers decide to target your machine they wont have a fun time being in Jail 🤣 sorry bad joke.\nBy now you have managed to setup an ssh key for a client and copy it to a remote host, re-configure the sshd config to lockdown authentication and last but not least install and configure Fail2Ban to block pesky attackers.\n","wordCount":"1702","inLanguage":"en","image":"https://blog.ahmza.com/webp/posts/secure-ssh/feature-anim.webp","datePublished":"2021-12-07T22:41:02Z","dateModified":"2021-12-07T22:41:02Z","author":{"@type":"Person","name":"ahmza"},"mainEntityOfPage":{"@type":"WebPage","@id":"https://blog.ahmza.com/posts/securing-ssh/"},"publisher":{"@type":"Organization","name":"ahmza's ramblings","logo":{"@type":"ImageObject","url":"https://blog.ahmza.com/img/favicon.png"}}}</script></head><body class=dark id=top><script>localStorage.getItem("pref-theme")==="light"&&document.body.classList.remove("dark")</script><header class=header><nav class=nav><div class=logo><a href=https://blog.ahmza.com accesskey=h title="ahmza's ramblings (Alt + H)">ahmza's ramblings</a><div class=logo-switches><button id=theme-toggle accesskey=t title="(Alt + T)"><svg id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg><svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></button></div></div><ul id=menu><li><a href=https://blog.ahmza.com/posts/ title=posts><span>posts</span></a></li><li><a href=https://blog.ahmza.com/archives/ title=archive><span>archive</span></a></li><li><a href=https://blog.ahmza.com/tags/ title=tags><span>tags</span></a></li><li><a href=https://blog.ahmza.com/contact title=contact><span>contact</span></a></li><li><a href=https://blog.ahmza.com/search/ title="search (Alt + /)" accesskey=/><span>search</span></a></li></ul></nav></header><main class=main><article class=post-single><header class=post-header><div class=breadcrumbs><a href=https://blog.ahmza.com>Home</a>&nbsp;»&nbsp;<a href=https://blog.ahmza.com/posts/>Posts</a></div><h1 class=post-title>Securing SSH 🤖</h1><div class=post-description>Ever wanted to make your SSH connections more secure. Read this</div><div class=post-meta>&lt;span title='2021-12-07 22:41:02 +0000 UTC'>December 7, 2021&lt;/span>&amp;nbsp;·&amp;nbsp;8 min&amp;nbsp;·&amp;nbsp;1702 words&amp;nbsp;·&amp;nbsp;ahmza&nbsp;|&nbsp;<a href=https://gitlab.com/AHMZA/blog/-/blob/main/content/posts/securing-ssh.md rel="noopener noreferrer" target=_blank>Suggest Changes</a></div></header><figure class=entry-cover><img loading=lazy src=https://blog.ahmza.com/webp/posts/secure-ssh/feature-anim.webp alt="ssh-alt image"><p></p></figure><div class=toc><details><summary accesskey=c title="(Alt + C)"><span class=details>Table of Contents</span></summary><div class=inner><ul><li><a href=#introduction aria-label=Introduction><strong>Introduction</strong></a></li><li><a href=#configure-ssh aria-label="Configure SSH"><strong>Configure SSH</strong></a><ul><li><a href=#create-ssh-keys aria-label="Create SSH Keys"><strong>Create SSH Keys</strong></a></li><li><a href=#copy-ssh-keys aria-label="Copy SSH Keys"><strong>Copy SSH Keys</strong></a></li><li><a href=#modify-ssh-config aria-label="Modify SSH Config"><strong>Modify SSH Config</strong></a></li><li><a href=#check-were-able-to-connect aria-label="Check were able to connect"><strong>Check were able to connect</strong></a></li></ul></li><li><a href=#success aria-label=Success><strong>Success</strong></a></li><li><a href=#setting-up-fail2ban aria-label="Setting up Fail2Ban"><strong>Setting up</strong> <em><strong>Fail2Ban</strong></em></a><ul><li><a href=#install-fail2ban aria-label="Install Fail2Ban"><strong>Install</strong> <em><strong>Fail2Ban</strong></em></a></li><li><a href=#configure-fail2ban aria-label="Configure Fail2Ban"><strong>Configure</strong> <em><strong>Fail2Ban</strong></em></a></li><li><a href=#testing-fail2ban aria-label="Testing Fail2Ban"><strong>Testing</strong> <em><strong>Fail2Ban</strong></em></a></li></ul></li><li><a href=#conclusion aria-label=Conclusion><strong>Conclusion</strong></a></li></ul></div></details></div><div class=post-content><h1 id=introduction><strong>Introduction</strong><a hidden class=anchor aria-hidden=true href=#introduction>#</a></h1><p>SSH is a widely used protocol to access remote devices. The problem
with SSH is at the authentication stage, Brute force attacks are one of
the ways an SSH connection can be compromised. A malicious actor will
constantly hammer the remote host with different passwords until it can
gain access. With further configuration of SSH we can make the service
a lot more secure.</p><h1 id=configure-ssh><strong>Configure SSH</strong><a hidden class=anchor aria-hidden=true href=#configure-ssh>#</a></h1><video autoplay loop muted playsinline aria-label='this is fine' style=display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px>
<source src=/webm/this-is-fine.webm type=video/webm></video><blockquote><p><strong>Famous last words:</strong> Configuring SSH like many things in Linux is
as simple as editing a few config files</p></blockquote><p>Always be sure to <strong>create a backup file</strong> it&rsquo;s very easy to end up
locking yourself out of a device.</p><p>I would recommend practising on a machine that is not critical.</p><h2 id=create-ssh-keys><strong>Create SSH Keys</strong><a hidden class=anchor aria-hidden=true href=#create-ssh-keys>#</a></h2><p>SSH keys use public and private key encryption for authentication.</p><p>To create a set of keys, <strong>on the client do:</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>ssh-keygen
</span></span></code></pre></div><p>You will be asked where you want to save the keys, <strong>I recommend the<br>default location</strong> for less hair pulling later.</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>Enter file in which to save the key <span class=o>(</span>/home/user/.ssh/id_rsa<span class=o>)</span>:
</span></span></code></pre></div><p>You will be asked to enter a password for the ssh keys, be sure to use
a strong password.</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>Enter passphrase <span class=o>(</span>empty <span class=k>for</span> no passphrase<span class=o>)</span>:
</span></span></code></pre></div><p>Once that is done you will see a confirmation screen like the one below</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-fallback data-lang=fallback><span class=line><span class=cl>Output
</span></span><span class=line><span class=cl>Your identification has been saved in /home/user/.ssh/id_rsa
</span></span><span class=line><span class=cl>Your public key has been saved in /home/user/.ssh/id_rsa.pub
</span></span><span class=line><span class=cl>The key fingerprint is:
</span></span><span class=line><span class=cl>SHA256:tIurljnWJRBc1RnHUJQ5GtND7p9HWKnjV6zjE9AFR1Y user@host
</span></span><span class=line><span class=cl>The key&#39;s randomart image is:
</span></span><span class=line><span class=cl>+---[RSA 3072]----+
</span></span><span class=line><span class=cl>| . .....oX=o.oE|
</span></span><span class=line><span class=cl>| o =oB oo|
</span></span><span class=line><span class=cl>| . . +.+ o.|
</span></span><span class=line><span class=cl>| . . .... o+ |
</span></span><span class=line><span class=cl>| . S .+. +|
</span></span><span class=line><span class=cl>| .... ..o+.|
</span></span><span class=line><span class=cl>| +.o. .=o.|
</span></span><span class=line><span class=cl>| * .. .oo |
</span></span><span class=line><span class=cl>| o.o. .. |
</span></span><span class=line><span class=cl>+----[SHA256]-----+
</span></span></code></pre></div><h2 id=copy-ssh-keys><strong>Copy SSH Keys</strong><a hidden class=anchor aria-hidden=true href=#copy-ssh-keys>#</a></h2><blockquote><p><strong>Quick note:</strong> user@host is the <strong>username</strong> on the <strong>remeote host</strong>
you would like to copy your public key to.</p></blockquote><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>ssh-copy-id user@host
</span></span></code></pre></div><p><strong>If asked to confirm the connection to the remote host answer yes</strong>, this
happens when a new machine with an unknown identity wants to connect to
the client.</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-fallback data-lang=fallback><span class=line><span class=cl>Output
</span></span><span class=line><span class=cl>The authenticity of host &#39;host(host)&#39; can&#39;t be established.
</span></span><span class=line><span class=cl>ECDSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx.
</span></span><span class=line><span class=cl>Are you sure you want to continue connecting (yes/no)? yes
</span></span></code></pre></div><p>You will then be asked to <strong>enter a password</strong> for the user on the remote
host</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-fallback data-lang=fallback><span class=line><span class=cl>Output
</span></span><span class=line><span class=cl>/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
</span></span><span class=line><span class=cl>/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
</span></span><span class=line><span class=cl>user@host&#39;s password:
</span></span></code></pre></div><p>If successful you should be able to access the device using the SSH key</p><p>To verify this, SSH to the device and <strong>it should ask for the Keys&rsquo;s
password not the users</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>Enter passphrase <span class=k>for</span> key <span class=s1>&#39;/home/user/.ssh/id_rsa&#39;</span>:
</span></span></code></pre></div><h2 id=modify-ssh-config><strong>Modify SSH Config</strong><a hidden class=anchor aria-hidden=true href=#modify-ssh-config>#</a></h2><p>create a backup</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
</span></span></code></pre></div><p>open the original file in a text editor</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo vim /etc/ssh/sshd_config
</span></span></code></pre></div><p>For a new user this might be daunting. Take your time and you will be
fine 😊</p><video autoplay loop muted playsinline aria-label='thats a big one' style=display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px>
<source src=/webm/thats-a-big-one.webm type=video/webm></video><p><strong>Lines we want to modify</strong></p><blockquote><p><strong>Quick note:</strong> you may need to uncomment some lines as well as add a
few</p></blockquote><ul><li>Protocol 2 - add to line 15</li><li>Port 2222 - modify line 17</li><li>PermitRootLogin no - modify line 36</li><li>Max Auth Tries 5 - modify line 38</li><li>PasswordAuthentication no - modify line 60</li><li>PermitEmptyPasswords no -modify line 61</li><li>AllowUsers ahmza - add line 67</li><li>ClientAliveInterval 180 - modify line 104</li></ul><div class=highlight><pre tabindex=0 class=chroma><code class=language-gdscript3 data-lang=gdscript3><span class=line><span class=cl><span class=c1># $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># This is the sshd server system-wide configuration file. See</span>
</span></span><span class=line><span class=cl><span class=c1># sshd_config(5) for more information.</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># The strategy used for options in the default sshd_config shipped with</span>
</span></span><span class=line><span class=cl><span class=c1># OpenSSH is to specify options with their default value where</span>
</span></span><span class=line><span class=cl><span class=c1># possible, but leave them commented. Uncommented options override the</span>
</span></span><span class=line><span class=cl><span class=c1># default value.</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=n>Include</span> <span class=o>/</span><span class=n>etc</span><span class=o>/</span><span class=n>ssh</span><span class=o>/</span><span class=n>sshd_config</span><span class=o>.</span><span class=n>d</span><span class=o>/*.</span><span class=n>conf</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=n>Protocol</span> <span class=mi>2</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=n>Port</span> <span class=mi>2222</span>
</span></span><span class=line><span class=cl><span class=c1>#AddressFamily any</span>
</span></span><span class=line><span class=cl><span class=c1>#ListenAddress 0.0.0.0</span>
</span></span><span class=line><span class=cl><span class=c1>#ListenAddress ::</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1>#HostKey /etc/ssh/ssh_host_rsa_key</span>
</span></span><span class=line><span class=cl><span class=c1>#HostKey /etc/ssh/ssh_host_ecdsa_key</span>
</span></span><span class=line><span class=cl><span class=c1>#HostKey /etc/ssh/ssh_host_ed25519_key</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Ciphers and keying</span>
</span></span><span class=line><span class=cl><span class=c1>#RekeyLimit default none</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Logging</span>
</span></span><span class=line><span class=cl><span class=c1>#SyslogFacility AUTH</span>
</span></span><span class=line><span class=cl><span class=c1>#LogLevel INFO</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Authentication:</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1>#LoginGraceTime 2m</span>
</span></span><span class=line><span class=cl><span class=n>PermitRootLogin</span> <span class=n>no</span>
</span></span><span class=line><span class=cl><span class=c1>#StrictModes yes</span>
</span></span><span class=line><span class=cl><span class=n>MaxAuthTries</span> <span class=mi>5</span>
</span></span><span class=line><span class=cl><span class=c1>#MaxSessions 10</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1>#PubkeyAuthentication yes</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Expect .ssh/authorized_keys2 to be disregarded by default in future.</span>
</span></span><span class=line><span class=cl><span class=c1>#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1>#AuthorizedPrincipalsFile none</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1>#AuthorizedKeysCommand none</span>
</span></span><span class=line><span class=cl><span class=c1>#AuthorizedKeysCommandUser nobody</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># For this to work you will also need host keys in /etc/ssh/ssh_known_hosts</span>
</span></span><span class=line><span class=cl><span class=c1>#HostbasedAuthentication no</span>
</span></span><span class=line><span class=cl><span class=c1># Change to yes if you don&#39;t trust ~/.ssh/known_hosts for</span>
</span></span><span class=line><span class=cl><span class=c1># HostbasedAuthentication</span>
</span></span><span class=line><span class=cl><span class=c1>#IgnoreUserKnownHosts no</span>
</span></span><span class=line><span class=cl><span class=c1># Don&#39;t read the user&#39;s ~/.rhosts and ~/.shosts files</span>
</span></span><span class=line><span class=cl><span class=c1>#IgnoreRhosts yes</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># To disable tunneled clear text passwords, change to no here!</span>
</span></span><span class=line><span class=cl><span class=n>PasswordAuthentication</span> <span class=n>no</span>
</span></span><span class=line><span class=cl><span class=n>PermitEmptyPasswords</span> <span class=n>no</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=n>AllowUsers</span> <span class=n>ahmza</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Change to yes to enable challenge-response passwords (beware issues with</span>
</span></span><span class=line><span class=cl><span class=c1># some PAM modules and threads)</span>
</span></span><span class=line><span class=cl><span class=n>ChallengeResponseAuthentication</span> <span class=n>no</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Kerberos options</span>
</span></span><span class=line><span class=cl><span class=c1>#KerberosAuthentication no</span>
</span></span><span class=line><span class=cl><span class=c1>#KerberosOrLocalPasswd yes</span>
</span></span><span class=line><span class=cl><span class=c1>#KerberosTicketCleanup yes</span>
</span></span><span class=line><span class=cl><span class=c1>#KerberosGetAFSToken no</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># GSSAPI options</span>
</span></span><span class=line><span class=cl><span class=c1>#GSSAPIAuthentication no</span>
</span></span><span class=line><span class=cl><span class=c1>#GSSAPICleanupCredentials yes</span>
</span></span><span class=line><span class=cl><span class=c1>#GSSAPIStrictAcceptorCheck yes</span>
</span></span><span class=line><span class=cl><span class=c1>#GSSAPIKeyExchange no</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Set this to &#39;yes&#39; to enable PAM authentication, account processing,</span>
</span></span><span class=line><span class=cl><span class=c1># and session processing. If this is enabled, PAM authentication will</span>
</span></span><span class=line><span class=cl><span class=c1># be allowed through the ChallengeResponseAuthentication and</span>
</span></span><span class=line><span class=cl><span class=c1># PasswordAuthentication. Depending on your PAM configuration,</span>
</span></span><span class=line><span class=cl><span class=c1># PAM authentication via ChallengeResponseAuthentication may bypass</span>
</span></span><span class=line><span class=cl><span class=c1># the setting of &#34;PermitRootLogin without-password&#34;.</span>
</span></span><span class=line><span class=cl><span class=c1># If you just want the PAM account and session checks to run without</span>
</span></span><span class=line><span class=cl><span class=c1># PAM authentication, then enable this but set PasswordAuthentication</span>
</span></span><span class=line><span class=cl><span class=c1># and ChallengeResponseAuthentication to &#39;no&#39;.</span>
</span></span><span class=line><span class=cl><span class=n>UsePAM</span> <span class=n>yes</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1>#AllowAgentForwarding yes</span>
</span></span><span class=line><span class=cl><span class=c1>#AllowTcpForwarding yes</span>
</span></span><span class=line><span class=cl><span class=c1>#GatewayPorts no</span>
</span></span><span class=line><span class=cl><span class=n>X11Forwarding</span> <span class=n>yes</span>
</span></span><span class=line><span class=cl><span class=c1>#X11DisplayOffset 10</span>
</span></span><span class=line><span class=cl><span class=c1>#X11UseLocalhost yes</span>
</span></span><span class=line><span class=cl><span class=c1>#PermitTTY yes</span>
</span></span><span class=line><span class=cl><span class=n>PrintMotd</span> <span class=n>no</span>
</span></span><span class=line><span class=cl><span class=c1>#PrintLastLog yes</span>
</span></span><span class=line><span class=cl><span class=c1>#TCPKeepAlive yes</span>
</span></span><span class=line><span class=cl><span class=c1>#PermitUserEnvironment no</span>
</span></span><span class=line><span class=cl><span class=c1>#Compression delayed</span>
</span></span><span class=line><span class=cl><span class=n>ClientAliveInterval</span> <span class=mi>180</span>
</span></span><span class=line><span class=cl><span class=c1>#ClientAliveCountMax 3</span>
</span></span><span class=line><span class=cl><span class=c1>#UseDNS no</span>
</span></span><span class=line><span class=cl><span class=c1>#PidFile /var/run/sshd.pid</span>
</span></span><span class=line><span class=cl><span class=c1>#MaxStartups 10:30:100</span>
</span></span><span class=line><span class=cl><span class=c1>#PermitTunnel no</span>
</span></span><span class=line><span class=cl><span class=c1>#ChrootDirectory none</span>
</span></span><span class=line><span class=cl><span class=c1>#VersionAddendum none</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># no default banner path</span>
</span></span><span class=line><span class=cl><span class=c1>#Banner none</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Allow client to pass locale environment variables</span>
</span></span><span class=line><span class=cl><span class=n>AcceptEnv</span> <span class=n>LANG</span> <span class=n>LC_</span><span class=o>*</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># override default of no subsystems</span>
</span></span><span class=line><span class=cl><span class=n>Subsystem</span> <span class=n>sftp</span> <span class=o>/</span><span class=n>usr</span><span class=o>/</span><span class=n>lib</span><span class=o>/</span><span class=n>openssh</span><span class=o>/</span><span class=n>sftp</span><span class=o>-</span><span class=n>server</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=c1># Example of overriding settings on a per-user basis</span>
</span></span><span class=line><span class=cl><span class=c1>#Match User anoncvs</span>
</span></span><span class=line><span class=cl><span class=c1># X11Forwarding no</span>
</span></span><span class=line><span class=cl><span class=c1># AllowTcpForwarding no</span>
</span></span><span class=line><span class=cl><span class=c1># PermitTTY no</span>
</span></span><span class=line><span class=cl><span class=c1># ForceCommand cvs server</span>
</span></span></code></pre></div><video autoplay loop muted playsinline aria-label='not so bad' style=display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px>
<source src=/webm/wasnt-so-bad.webm type=video/webm></video><p><strong>Now lets explain what we just did</strong></p><ul><li><strong>Protocol 2</strong> - released in 2006, SSH2 introduced improved
encryption algorithms.</li><li><strong>Port 2222</strong> - The port number can be whatever number you want.
Choose something other than 22 this will help hide your device from malicious actors</li><li><strong>PermitRootLogin no</strong> - If the root account were to be compromised
then the attacker has full control of the system so we stop it from being able to log in.</li><li><strong>MaxAuthTries 5</strong> - After 5 failed attempts the remote host blocks
requests from that IP for a period of time.</li><li><strong>PasswordAuthentication no</strong> - We have the SSH key installed so we
no longer need to have password authentication.</li><li><strong>PermitEmptyPasswords no</strong> - We don&rsquo;t want to allow empty passwords
to be used as authentication for obvious reasons.</li><li><strong>AllowUsers username</strong> - Add the usernames of users you want to be
able to connect to the remote host and other users trying to connect
will be dropped.</li><li><strong>Client Alive Interval 180</strong> - Drop the connection after a certain
period of inactivity</li></ul><h2 id=check-were-able-to-connect><strong>Check were able to connect</strong><a hidden class=anchor aria-hidden=true href=#check-were-able-to-connect>#</a></h2><p>restart sshd service</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo systemctl restart sshd
</span></span></code></pre></div><p><strong>Keep the current SSH connection open</strong> and create a new session.</p><p>If you are able to connect to the remote hosts then you are all set. If
not then you still have the initial connection to the remote host to
roll back the changes and troubleshoot.</p><h1 id=success><strong>Success</strong><a hidden class=anchor aria-hidden=true href=#success>#</a></h1><video autoplay loop muted playsinline aria-label=clap style=display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px>
<source src=/webm/clap.webm type=video/webm></video><h1 id=setting-up-fail2ban><strong>Setting up</strong> <em><strong>Fail2Ban</strong></em><a hidden class=anchor aria-hidden=true href=#setting-up-fail2ban>#</a></h1><p><em>Fail2Ban</em> is an intrusion prevention tool. Although we are slowing
bots down with MaxAuthTries the attacker is still able to carry on
brute forcing. Which is what Fail2Ban is for, it actually blocks the
connections from that IP.</p><h2 id=install-fail2ban><strong>Install</strong> <em><strong>Fail2Ban</strong></em><a hidden class=anchor aria-hidden=true href=#install-fail2ban>#</a></h2><p><strong>We will install Fail2Ban on the remote host</strong>
First upgrade any packages, then <strong>install</strong> <em><strong>Fail2Ban</strong></em></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo apt update <span class=o>&amp;&amp;</span> sudo apt upgrade
</span></span><span class=line><span class=cl>sudo apt install fail2ban
</span></span></code></pre></div><p>Now we need to enable the service so it starts when the remote host
starts</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo systemctl <span class=nb>enable</span> --now fail2ban
</span></span></code></pre></div><h2 id=configure-fail2ban><strong>Configure</strong> <em><strong>Fail2Ban</strong></em><a hidden class=anchor aria-hidden=true href=#configure-fail2ban>#</a></h2><p>The Fail2Ban config file we want to edit is called <strong>jail.local</strong> located in <strong>/etc/fail2ban/</strong>
open jail.local in your editor of choice</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo vim /etc/fail2ban/jail.local
</span></span></code></pre></div><p>The config for <em>Fail2Ban</em> is a lot shorter than sshd so this should be
quick</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-gdscript3 data-lang=gdscript3><span class=line><span class=cl><span class=p>[</span><span class=n>DEFAULT</span><span class=p>]</span>
</span></span><span class=line><span class=cl> <span class=n>bantime</span> <span class=o>=</span> <span class=mi>8</span><span class=n>h</span>
</span></span><span class=line><span class=cl> <span class=n>ignoreip</span> <span class=o>=</span> <span class=mf>127.0</span><span class=o>.</span><span class=mf>0.1</span> <span class=o>&lt;</span><span class=n>ip</span> <span class=n>addresses</span> <span class=n>to</span> <span class=n>be</span> <span class=n>ignored</span><span class=o>&gt;</span>
</span></span><span class=line><span class=cl> <span class=n>ignoreself</span> <span class=o>=</span> <span class=bp>true</span>
</span></span><span class=line><span class=cl>
</span></span><span class=line><span class=cl><span class=p>[</span><span class=n>sshd</span><span class=p>]</span>
</span></span><span class=line><span class=cl> <span class=n>enabled</span> <span class=o>=</span> <span class=bp>true</span>
</span></span><span class=line><span class=cl> <span class=n>port</span> <span class=o>=</span> <span class=mi>2222</span>
</span></span><span class=line><span class=cl> <span class=n>filter</span> <span class=o>=</span> <span class=n>sshd</span>
</span></span><span class=line><span class=cl> <span class=n>logpath</span> <span class=o>=</span> <span class=o>/</span><span class=k>var</span><span class=o>/</span><span class=nb>log</span><span class=o>/</span><span class=n>auth</span><span class=o>.</span><span class=n>log</span>
</span></span><span class=line><span class=cl> <span class=n>maxretry</span> <span class=o>=</span> <span class=mi>3</span>
</span></span><span class=line><span class=cl> <span class=n>findtime</span> <span class=o>=</span> <span class=mi>10</span><span class=n>m</span>
</span></span></code></pre></div><p><strong>[Default]</strong> - Settings in here apply to all jails</p><ul><li><strong>bantime</strong> - how long the ban will last</li><li><strong>ignoreip</strong> - IP addresses to ignore</li><li><strong>ignoreself</strong> - stops from locking itself out</li></ul><p><strong>[sshd]</strong> - this is the jail for sshd</p><ul><li><strong>enabled</strong> - decides weather the jail is active or not</li><li><strong>port</strong> - the port number the service</li><li><strong>filter</strong> - tells the jail which filter to use from /etc/fail2ban/filter.d</li><li><strong>logpath</strong> - where the log you want fail2ban to read is</li><li><strong>maxretry</strong> - Times the client can attempt a login before being banned</li><li><strong>findtime</strong> - An amount of time which maxretry must occur to trigger a
ban for example in 10 minutes if 3 failed login attempts are made the
ban the IP</li></ul><p><strong>Restart</strong> <em><strong>Fail2Ban</strong></em> to load the configuration</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo systemctl restart fail2ban
</span></span></code></pre></div><h2 id=testing-fail2ban><strong>Testing</strong> <em><strong>Fail2Ban</strong></em><a hidden class=anchor aria-hidden=true href=#testing-fail2ban>#</a></h2><p>To test Fail2Ban lets create a test user and set a password for the
user</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo useradd <span class=nb>test</span>
</span></span><span class=line><span class=cl>sudo passwd <span class=nb>test</span>
</span></span></code></pre></div><p><strong>open the sshd config</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo vim /etc/ssh/sshd_config
</span></span></code></pre></div><p>modify the line <strong>PasswordAuthentication</strong> to say <strong>yes</strong> and add the test user to <strong>AllowUsers</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>PasswordAuthentication yes
</span></span><span class=line><span class=cl>AllowUsers user <span class=nb>test</span>
</span></span></code></pre></div><p><strong>restart the sshd service</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo systemctl restart sshd
</span></span></code></pre></div><p>Attempt to login to the remote host using the test account using an
incorrect password. After 3 failed attempts it should say connection
refused.</p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>ssh test@host -p <span class=m>2222</span>
</span></span></code></pre></div><p><em>Fail2Ban</em> should do something along the lines of &mldr;
<video autoplay loop muted playsinline aria-label='you shall not pass' style=display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px>
<source src=/webm/you-shall-not-pass.webm type=video/webm></video></p><p>log back in as your normal user, remove the test user and restore the
sshd config.</p><p><strong>To remove the user</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo userdel <span class=nb>test</span>
</span></span></code></pre></div><p><strong>restore the /etc/ssh/sshd_config file</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>sudo vim /etc/ssh/sshd_config
</span></span></code></pre></div><p>Set <strong>PasswordAuthentication</strong> back to <strong>no</strong> and remove test from <strong>AllowUsers</strong></p><div class=highlight><pre tabindex=0 class=chroma><code class=language-bash data-lang=bash><span class=line><span class=cl>PasswordAuthentication no
</span></span><span class=line><span class=cl>AllowUsers user
</span></span></code></pre></div><h1 id=conclusion><strong>Conclusion</strong><a hidden class=anchor aria-hidden=true href=#conclusion>#</a></h1><p>well done, you managed to make it through all that !! At least now you
can be reassured that if them pesky brute-force attackers decide to
target your machine they wont have a fun time being in Jail 🤣 sorry
bad joke.</p><p>By now you have managed to setup an ssh key for a client and copy it to
a remote host, re-configure the sshd config to lockdown authentication
and last but not least install and configure Fail2Ban to block pesky
attackers.</p><video autoplay loop muted playsinline aria-label=proud style=display:block;margin-left:auto;margin-right:auto;width:50%;height:auto;padding:10px>
<source src=/webm/proud.webm type=video/webm></video></div><footer class=post-footer><ul class=post-tags><li><a href=https://blog.ahmza.com/tags/homelab/>Homelab</a></li><li><a href=https://blog.ahmza.com/tags/ssh/>SSH</a></li><li><a href=https://blog.ahmza.com/tags/remoteaccess/>RemoteAccess</a></li></ul></footer></article></main><footer class=footer><span>&copy; 2023 <a href=https://blog.ahmza.com>ahmza's ramblings</a></span>
<span>Powered by
<a href=https://gohugo.io/ rel="noopener noreferrer" target=_blank>Hugo</a> &
<a href=https://github.com/adityatelange/hugo-PaperMod/ rel=noopener target=_blank>PaperMod</a></span></footer><a href=#top aria-label="go to top" title="Go to Top (Alt + G)" class=top-link id=top-link accesskey=g><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentcolor"><path d="M12 6H0l6-6z"/></svg></a><script src=https://storage.ko-fi.com/cdn/scripts/overlay-widget.js></script><script>kofiWidgetOverlay.draw("ahmza",{type:"floating-chat","floating-chat.donateButton.text":"Tip","floating-chat.donateButton.background-color":"rgb(145, 70, 255)","floating-chat.donateButton.text-color":"#fff"})</script><script>let menu=document.getElementById("menu");menu&&(menu.scrollLeft=localStorage.getItem("menu-scroll-position"),menu.onscroll=function(){localStorage.setItem("menu-scroll-position",menu.scrollLeft)}),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();var t=this.getAttribute("href").substr(1);window.matchMedia("(prefers-reduced-motion: reduce)").matches?document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView():document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView({behavior:"smooth"}),t==="top"?history.replaceState(null,null," "):history.pushState(null,null,`#${t}`)})})</script><script>var mybutton=document.getElementById("top-link");window.onscroll=function(){document.body.scrollTop>800||document.documentElement.scrollTop>800?(mybutton.style.visibility="visible",mybutton.style.opacity="1"):(mybutton.style.visibility="hidden",mybutton.style.opacity="0")}</script><script>document.getElementById("theme-toggle").addEventListener("click",()=>{document.body.className.includes("dark")?(document.body.classList.remove("dark"),localStorage.setItem("pref-theme","light")):(document.body.classList.add("dark"),localStorage.setItem("pref-theme","dark"))})</script><script>document.querySelectorAll("pre > code").forEach(e=>{const n=e.parentNode.parentNode,t=document.createElement("button");t.classList.add("copy-code"),t.innerHTML="copy";function s(){t.innerHTML="copied!",setTimeout(()=>{t.innerHTML="copy"},2e3)}t.addEventListener("click",t=>{if("clipboard"in navigator){navigator.clipboard.writeText(e.textContent),s();return}const n=document.createRange();n.selectNodeContents(e);const o=window.getSelection();o.removeAllRanges(),o.addRange(n);try{document.execCommand("copy"),s()}catch{}o.removeRange(n)}),n.classList.contains("highlight")?n.appendChild(t):n.parentNode.firstChild==n||(e.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="TABLE"?e.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(t):e.parentNode.appendChild(t))})</script></body></html>