{"id":13432604,"url":"https://github.com/imthenachoman/How-To-Secure-A-Linux-Server","last_synced_at":"2025-03-17T10:32:20.141Z","repository":{"id":37381813,"uuid":"169839893","full_name":"imthenachoman/How-To-Secure-A-Linux-Server","owner":"imthenachoman","description":"An evolving how-to guide for securing a Linux server.","archived":false,"fork":false,"pushed_at":"2024-10-19T20:10:33.000Z","size":661,"stargazers_count":17898,"open_issues_count":34,"forks_count":1144,"subscribers_count":328,"default_branch":"master","last_synced_at":"2025-03-11T14:06:04.760Z","etag":null,"topics":["cc-by-sa","hardening","hardening-steps","linux","linux-server","security","security-hardening","server"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc-by-sa-4.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imthenachoman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-09T06:44:37.000Z","updated_at":"2025-03-11T14:04:08.000Z","dependencies_parsed_at":"2023-10-02T03:23:24.868Z","dependency_job_id":"f0c0fd42-668a-4177-99e7-0d40657b33ca","html_url":"https://github.com/imthenachoman/How-To-Secure-A-Linux-Server","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imthenachoman%2FHow-To-Secure-A-Linux-Server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imthenachoman%2FHow-To-Secure-A-Linux-Server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imthenachoman%2FHow-To-Secure-A-Linux-Server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imthenachoman%2FHow-To-Secure-A-Linux-Server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imthenachoman","download_url":"https://codeload.github.com/imthenachoman/How-To-Secure-A-Linux-Server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244016780,"owners_count":20384203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cc-by-sa","hardening","hardening-steps","linux","linux-server","security","security-hardening","server"],"created_at":"2024-07-31T02:01:14.063Z","updated_at":"2025-03-17T10:32:20.118Z","avatar_url":"https://github.com/imthenachoman.png","language":null,"funding_links":[],"categories":["Others","miscellaneous","Operating System","Misc","GNU/Linux","Wikis/Guides:","Security","Additional and similar resources","Tools","Others (1002)","Entries","其他_安全与渗透","server","Web Servers","System","Don't forget to give a :star: to make the project popular","linux","Operating Systems","Hardening","Defensive Security"],"sub_categories":["Sensor and Acuator Interfaces","Hardening","Training","网络服务_其他","GIT","Security","Linux","Ghidra","Secure Development"],"readme":"# How To Secure A Linux Server\n\nAn evolving how-to guide for securing a Linux server that, hopefully, also teaches you a little about security and why it matters.\n\n[![CC-BY-SA](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)](#license)\n\n## Table of Contents\n\n- [Introduction](#introduction)\n  - [Guide Objective](#guide-objective)\n  - [Why Secure Your Server](#why-secure-your-server)\n  - [Why Yet Another Guide](#why-yet-another-guide)\n  - [Other Guides](#other-guides)\n  - [To Do / To Add](#to-do--to-add)\n- [Guide Overview](#guide-overview)\n  - [About This Guide](#about-this-guide)\n  - [My Use-Case](#my-use-case)\n  - [Editing Configuration Files - For The Lazy](#editing-configuration-files---for-the-lazy)\n  - [Contributing](#contributing)\n- [Before You Start](#before-you-start)\n  - [Identify Your Principles](#identify-your-principles)\n  - [Picking A Linux Distribution](#picking-a-linux-distribution)\n  - [Installing Linux](#installing-linux)\n  - [Pre/Post Installation Requirements](#prepost-installation-requirements)\n  - [Other Important Notes](#other-important-notes)\n  - [Using Ansible Playbooks to secure your Linux Server](#using-ansible-playbooks-to-secure-your-linux-server)\n- [The SSH Server](#the-ssh-server)\n  - [Important Note Before You Make SSH Changes](#important-note-before-you-make-ssh-changes)\n  - [SSH Public/Private Keys](#ssh-publicprivate-keys)\n  - [Create SSH Group For AllowGroups](#create-ssh-group-for-allowgroups)\n  - [Secure `/etc/ssh/sshd_config`](#secure-etcsshsshd_config)\n  - [Remove Short Diffie-Hellman Keys](#remove-short-diffie-hellman-keys)\n  - [2FA/MFA for SSH](#2famfa-for-ssh)\n- [The Basics](#the-basics)\n  - [Limit Who Can Use sudo](#limit-who-can-use-sudo)\n  - [Limit Who Can Use su](#limit-who-can-use-su)\n  - [Run applications in a sandbox with FireJail](#run-applications-in-a-sandbox-with-firejail)\n  - [NTP Client](#ntp-client)\n  - [Securing /proc](#securing-proc)\n  - [Force Accounts To Use Secure Passwords](#force-accounts-to-use-secure-passwords)\n  - [Automatic Security Updates and Alerts](#automatic-security-updates-and-alerts)\n  - [More Secure Random Entropy Pool (WIP)](#more-secure-random-entropy-pool-wip)\n  - [Add Panic/Secondary/Fake password Login Security System](#add-panic-secondary-fake-password-login-security-system)\n- [The Network](#the-network)\n  - [Firewall With UFW (Uncomplicated Firewall)](#firewall-with-ufw-uncomplicated-firewall)\n  - [iptables Intrusion Detection And Prevention with PSAD](#iptables-intrusion-detection-and-prevention-with-psad)\n  - [Application Intrusion Detection And Prevention With Fail2Ban](#application-intrusion-detection-and-prevention-with-fail2ban) \n  - [Application Intrusion Detection And Prevention With CrowdSec](#application-intrusion-detection-and-prevention-with-crowdsec)\n- [The Auditing](#the-auditing)\n  - [File/Folder Integrity Monitoring With AIDE (WIP)](#filefolder-integrity-monitoring-with-aide-wip)\n  - [Anti-Virus Scanning With ClamAV (WIP)](#anti-virus-scanning-with-clamav-wip)\n  - [Rootkit Detection With Rkhunter (WIP)](#rootkit-detection-with-rkhunter-wip)\n  - [Rootkit Detection With chrootkit (WIP)](#rootkit-detection-with-chrootkit-wip)\n  - [logwatch - system log analyzer and reporter](#logwatch---system-log-analyzer-and-reporter)\n  - [ss - Seeing Ports Your Server Is Listening On](#ss---seeing-ports-your-server-is-listening-on)\n  - [Lynis - Linux Security Auditing](#lynis---linux-security-auditing)\n  - [OSSEC - Host Intrusion Detection](#ossec---host-intrusion-detection)\n- [The Danger Zone](#the-danger-zone)\n- [The Miscellaneous](#the-miscellaneous)\n  - [MSMTP (Simple Sendmail) with Google](#msmtp-alternative)\n  - [Gmail and Exim4 As MTA With Implicit TLS](#gmail-and-exim4-as-mta-with-implicit-tls)\n  - [Separate iptables Log File](#separate-iptables-log-file)\n- [Left Over](#left-over)\n  - [Contacting Me](#contacting-me)\n  - [Helpful Links](#helpful-links)\n  - [Acknowledgments](#acknowledgments)\n  - [License and Copyright](#license-and-copyright)\n\n(TOC made with [nGitHubTOC](https://imthenachoman.github.io/nGitHubTOC/))\n\n## Introduction\n\n### Guide Objective\n\nThis guides purpose is to teach you how to secure a Linux server.\n\nThere are a lot of things you can do to secure a Linux server and this guide will attempt to cover as many of them as possible. More topics/material will be added as I learn, or as folks [contribute](#contributing).\n\nAnsible playbooks of this guide are available at [How To Secure A Linux Server With Ansible](https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible) by [moltenbit](https://github.com/moltenbit).\n\n([Table of Contents](#table-of-contents))\n\n### Why Secure Your Server\n\nI assume you're using this guide because you, hopefully, already understand why good security is important. That is a heavy topic onto itself and breaking it down is out-of-scope for this guide. If you don't know the answer to that question, I advise you research it first.\n\nAt a high level, the second a  device, like a server, is in the public domain -- i.e. visible to the outside world -- it becomes a target for bad-actors. An unsecured device is a playground for bad-actors who want access to your data, or to use your server as another node for their large-scale DDOS attacks.\n\nWhat's worse is, without good security, you may never know if your server has been compromised. A bad-actor may have gained unauthorized access to your server and copied your data without changing anything, so you'd never know. Or your server may have been part of a DDOS attack, and you wouldn't know. Look at many of the large scale data breaches in the news -- the companies often did not discover the data leak or intrusion until long after the bad-actors were gone.\n\nContrary to popular belief, bad-actors don't always want to change something or [lock you out of your data for money](https://en.wikipedia.org/wiki/Ransomware). Sometimes they just want the data on your server for their data warehouses (there is big money in big data) or to covertly use your server for their nefarious purposes.\n\n([Table of Contents](#table-of-contents))\n\n### Why Yet Another Guide\n\nThis guide may appear duplicative/unnecessary because there are countless articles online that tell you [how to secure Linux](https://duckduckgo.com/?q=how+to+secure+linux\u0026t=ffab\u0026atb=v151-7\u0026ia=web), but the information is spread across different articles, that cover different things, and in different ways. Who has time to scour through hundreds of articles?\n\nAs I was going through research for my Debian build, I kept notes. At the end I realized that, along with what I already knew, and what I was learning, I had the makings of a how-to guide. I figured I'd put it online to hopefully help others **learn**, and **save time**.\n\nI've never found one guide that covers everything -- this guide is my attempt.\n\nMany of the things covered in this guide may be rather basic/trivial, but most of us do not install Linux every day, and it is easy to forget those basic things.\n\n([Table of Contents](#table-of-contents))\n\n### Other Guides\n\nThere are many guides provided by experts, industry leaders, and the distributions themselves. It is not practical, and sometimes against copyright, to include everything from those guides. I recommend you check them out before starting with this guide.\n\n- The [Center for Internet Security (CIS)](https://www.cisecurity.org/) provides [benchmarks](https://www.cisecurity.org/cis-benchmarks/) that are exhaustive, industry trusted, step-by-step instructions for securing many flavors of Linux. Check their [About Us](https://www.cisecurity.org/about-us/) page for details. My recommendation is to go through this guide (the one you're reading here) first and THEN CIS's guide. That way their recommendations will trump anything in this guide.\n- For distribution specific hardening/security guides, check your distributions documentation.\n- https://security.utexas.edu/os-hardening-checklist/linux-7 - Red Hat Enterprise Linux 7 Hardening Checklist\n- https://cloudpro.zone/index.php/2018/01/18/debian-9-3-server-setup-guide-part-1/ - # Debian 9.3 server setup guide\n- https://blog.vigilcode.com/2011/04/ubuntu-server-initial-security-quick-secure-setup-part-i/ - Ubuntu Server Initial Security guide\n- https://www.tldp.org/LDP/sag/html/index.html\n- https://seifried.org/lasg/\n- https://news.ycombinator.com/item?id=19178964\n- https://wiki.archlinux.org/index.php/Security - many folks have also recommended this one\n- https://securecompliance.co/linux-server-hardening-checklist/\n\n([Table of Contents](#table-of-contents))\n\n### To Do / To Add\n\n- [ ] [Custom Jails for Fail2ban](#custom-jails)\n- [ ] MAC (Mandatory Access Control) and Linux Security Modules (LSMs)\n   - https://wiki.archlinux.org/index.php/security#Mandatory_access_control\n   - Security-Enhanced Linux / SELinux\n       - https://en.wikipedia.org/wiki/Security-Enhanced_Linux\n       - https://linuxtechlab.com/beginners-guide-to-selinux/\n       - https://linuxtechlab.com/replicate-selinux-policies-among-linux-machines/\n       - https://teamignition.us/how-to-stop-being-a-scrub-and-learn-to-use-selinux.html\n   - AppArmor\n       - https://wiki.archlinux.org/index.php/AppArmor\n       - https://security.stackexchange.com/questions/29378/comparison-between-apparmor-and-selinux\n        - http://www.insanitybit.com/2012/06/01/why-i-like-apparmor-more-than-selinux-5/\n- [ ] disk encryption\n- [ ] Rkhunter and chrootkit\n    - http://www.chkrootkit.org/\n    - http://rkhunter.sourceforge.net/\n    - https://www.cyberciti.biz/faq/howto-check-linux-rootkist-with-detectors-software/\n    - https://www.tecmint.com/install-rootkit-hunter-scan-for-rootkits-backdoors-in-linux/\n- [ ] shipping/backing up logs - https://news.ycombinator.com/item?id=19178681\n- [ ] CIS-CAT - https://learn.cisecurity.org/cis-cat-landing-page\n- [ ] debsums - https://blog.sleeplessbeastie.eu/2015/03/02/how-to-verify-installed-packages/\n\n([Table of Contents](#table-of-contents))\n\n## Guide Overview\n\n### About This Guide\n\nThis guide...\n\n- ...**is** a work in progress.\n- ...**is** focused on **at-home** Linux servers. All of the concepts/recommendations here apply to larger/professional environments but those use-cases call for more advanced and specialized configurations that are out-of-scope for this guide.\n- ...**does not** teach you about Linux, how to [install Linux](#installing-linux), or how to use it. Check https://linuxjourney.com/ if you're new to Linux.\n- ...**is** meant to be [Linux distribution agnostic](#picking-a-linux-distribution).\n- ...**does not** teach you everything you need to know about security nor does it get into all aspects of system/server security. For example, physical security is out of scope for this guide.\n- ...**does not** talk about how programs/tools work, nor does it delve into their nook and crannies. Most of the programs/tools this guide references are very powerful and highly configurable. The goal is to cover the bare necessities -- enough to whet your appetite and make you hungry enough to want to go and learn more.\n- ...**aims** to make it easy by providing code you can copy-and-paste. You might need to modify the commands before you paste so keep your favorite [text editor](https://notepad-plus-plus.org/) handy.\n- ...**is** organized in an order that makes logical sense to me -- i.e. securing SSH before installing a firewall. As such, this guide is intended to be followed in the order it is presented, but it is not necessary to do so. Just be careful if you do things in a different order -- some sections require previous sections to be completed.\n\n([Table of Contents](#table-of-contents))\n\n### My Use-Case\n\nThere are many types of servers and different use-cases. While I want this guide to be as generic as possible, there will be some things that may not apply to all/other use-cases. Use your best judgement when going through this guide.\n\nTo help put context to many of the topics covered in this guide, my use-case/configuration is:\n\n- A desktop class computer...\n- With a single NIC...\n- Connected to a consumer grade router...\n- Getting a dynamic WAN IP provided by the ISP...\n- With WAN+LAN on IPV4...\n- And LAN using [NAT](https://en.wikipedia.org/wiki/Network_address_translation)...\n- That I want to be able to SSH to remotely from unknown computers and unknown locations (i.e. a friend's house).\n\n([Table of Contents](#table-of-contents))\n\n### Editing Configuration Files - For The Lazy\n\nI am very lazy and do not like to edit files by hand if I don't need to. I also assume everyone else is just like me. :)\n\nSo, when and where possible, I have provided `code` snippets to quickly do what is needed, like add or change a line in a configuration file.\n\nThe `code` snippets use basic commands like `echo`, `cat`, `sed`, `awk`, and `grep`. How the `code` snippets work, like what each command/part does, is out of scope for this guide -- the `man` pages are your friend.\n\n**Note**: The `code` snippets do not validate/verify the change went through -- i.e. the line was actually added or changed. I'll leave the verifying part in your capable hands. The steps in this guide do include taking backups of all files that will be changed.\n\nNot all changes can be automated with `code` snippets. Those changes need good, old-fashioned, manual editing. For example, you can't just append a line to an [INI](https://en.wikipedia.org/wiki/INI_file) type file. Use your [favorite](https://en.wikipedia.org/wiki/Vi) Linux text editor.\n\n([Table of Contents](#table-of-contents))\n\n### Contributing\n\nI wanted to put this guide on [GitHub](http://www.github.com) to make it easy to collaborate. The more folks that contribute, the better and more complete this guide will become.\n\nTo contribute you can fork and submit a pull request or submit a [new issue](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/new).\n\n([Table of Contents](#table-of-contents))\n\n## Before You Start\n\n### Identify Your Principles\n\nBefore you start you will want to identify what your Principles are. What is your [threat model](https://en.wikipedia.org/wiki/Threat_model)? Some things to think about:\n\n- Why do you want to secure your server?\n- How much security do you want or not want?\n- How much convenience are you willing to compromise for security and vice-versa?\n- What are the threats you want to protect against? What are the specifics to your situation? For example:\n  - Is physical access to your server/network a possible attack vector?\n  - Will you be opening ports on your router so you can access your server from outside your home?\n  - Will you be hosting a file share on your server that will be mounted on a desktop class machine? What is the possibility of the desktop machine getting infected and, in turn, infecting the server?\n - Do you have a means of recovering if your security implementation locks you out of your own server? For example, you [disabled root login](#disable-root-login) or [password protected GRUB](#password-protect-grub).\n\nThese are just **a few things** to think about. Before you start securing your server you will want to understand what you're trying to protect against and why so you know what you need to do.\n\n([Table of Contents](#table-of-contents))\n\n### Picking A Linux Distribution\n\nThis guide is intended to be distribution agnostic so users can use [any distribution](https://distrowatch.com/) they want. With that said, there are a few things to keep in mind:\n\nYou want a distribution that...\n\n- ...**is stable**. Unless you like debugging issues at 2 AM, you don't want an [unattended upgrade](#automatic-security-updates-and-alerts), or a manual package/system update, to render your server inoperable. But this also means you're okay with not running the latest, greatest, bleeding edge software.\n- ...**stays up-to-date with security patches**. You can secure everything on your server, but if the core OS or applications you're running have known vulnerabilities, you'll never be safe.\n- ...**you're familiar with.** If you don't know Linux, I would advise you play around with one before you try to secure it. You should be comfortable with it and know your way around, like how to install software, where configuration files are, etc...\n- ...**is well-supported.** Even the most seasoned admin needs help every now and then. Having a place to go for help will save your sanity.\n\n([Table of Contents](#table-of-contents))\n\n### Installing Linux\n\nInstalling Linux is out-of-scope for this guide because each distribution does it differently and the installation instructions are usually well documented. If you need help, start with your distribution's documentation. Regardless of the distribution, the high-level process usually goes like so:\n\n1. download the ISO\n1. burn/copy/transfer it to your install medium (e.g. a CD or USB stick)\n1. boot your server from your install medium\n1. follow the prompts to install\n\nWhere applicable, use the expert install option so you have tighter control of what is running on your server. **Only install what you absolutely need.** I, personally, do not install anything other than SSH. Also, tick the Disk Encryption option.\n\n([Table of Contents](#table-of-contents))\n\n### Pre/Post Installation Requirements\n\n- If you're opening ports on your router so you can access your server from the outside, disable the port forwarding until your system is up and secured.\n- Unless you're doing everything physically connected to your server, you'll need remote access so be sure SSH works.\n- Keep your system up-to-date (i.e. `sudo apt update \u0026\u0026 sudo apt upgrade` on Debian based systems).\n- Make sure you perform any tasks specific to your setup like:\n  - Configuring network\n  - Configuring mount points in `/etc/fstab`\n  - Creating the initial user accounts\n  - Installing core software you'll want like `man`\n  - Etc...\n- Your server will need to be able to send e-mails so you can get important security alerts. If you're not setting up a mail server check [Gmail and Exim4 As MTA With Implicit TLS](#gmail-and-exim4-as-mta-with-implicit-tls).\n- I would also recommend you **read** through the [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks/) before you start with this guide just to digest/understand what they have to say. My recommendation is to go through this guide (the one you're reading here) first and THEN CIS's guide. That way their recommendations will trump anything in this guide.\n\n([Table of Contents](#table-of-contents))\n\n### Other Important Notes\n\n- This guide is being written and tested on Debian. Most things below should work on other distributions. If you find something that does not, please [contact me](#contacting-me). The main thing that separates each distribution will be its package management system. Since I use Debian, I will provide the appropriate `apt` commands that should work on all [Debian based distributions](https://www.debian.org/derivatives/). If someone is willing to [provide](#contributing) the respective commands for other distributions, I will add them.\n- File paths and settings also may differ slightly -- check with your distribution's documentation if you have issues.\n- Read the whole guide before you start. Your use-case and/or principals may call for not doing something or for changing the order.\n- Do not **blindly** copy-and-paste without understanding what you're pasting. Some commands will need to be modified for your needs before they'll work -- usernames for example.\n\n([Table of Contents](#table-of-contents))\n\n### Using Ansible playbooks to secure your Linux Server\nAnsible playbooks of this guide are available at [How To Secure A Linux Server With Ansible](https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible).\n\nMake sure to edit the variables according to your needs and read all tasks beforehand to confirm it does not break your system. After running the playbooks ensure that all settings are configured to your needs!\n\n1. Install [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)\n2. git clone [How To Secure A Linux Server With Ansible](https://github.com/moltenbit/How-To-Secure-A-Linux-Server-With-Ansible)\n3. [Create SSH-Public/Private-Keys](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#ssh-publicprivate-keys)\n  ```\n  ssh-keygen -t ed25519\n  ```\n   \n5. Change all variables in *group_vars/variables.yml* according to your needs.\n6. Enable SSH root access before running the playbooks:\n   \n  ```\n  nano /etc/ssh/sshd_config\n  [...]\n  PermitRootLogin yes\n  [...]\n  ```\n\n7. Recommended: configure static IP address on your system.\n8. Add your systems IP address to *hosts.yml*.\n\n\u0026nbsp;\n\nRun the requirements playbook using the root password you specified while installing the server:\n\n    ansible-playbook --inventory hosts.yml --ask-pass requirements-playbook.yml\n\n\u0026nbsp;\n\nRun the main playbook with the new users password you specified in the *variables.yml* file:\n\n    ansible-playbook --inventory hosts.yml --ask-pass main-playbook.yml\n\n\u0026nbsp;\n\nIf you need to run the playbooks multiple times remember to use the SSH key and the new SSH port:\n\n    ansible-playbook --inventory hosts.yml -e ansible_ssh_port=SSH_PORT --key-file /PATH/TO/SSH/KEY main-playbook.yml\n\n\n([Table of Contents](#table-of-contents))\n\n## The SSH Server\n\n### Important Note Before You Make SSH Changes\n\nIt is highly advised you keep a 2nd terminal open to your server **before you make and apply SSH configuration changes**. This way if you lock yourself out of your 1st terminal session, you still have one session connected so you can fix it.\n\nThank you to [Sonnenbrand](https://github.com/Sonnenbrand) for this [idea](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/56).\n\n### SSH Public/Private Keys\n\n#### Why\n\nUsing SSH public/private keys is more secure than using a password. It also makes it easier and faster, to connect to our server because you don't have to enter a password.\n\n#### How It Works\n\nCheck the references below for more details but, at a high level, public/private keys work by using a pair of keys to verify identity.\n\n1. One key, the **public** key, **can only encrypt data**, not decrypt it\n1. The other key, the **private** key, can decrypt the data\n\nFor SSH, a public and private key is created on the client. You want to keep both keys secure, especially the private key. Even though the public key is meant to be public, it is wise to make sure neither keys fall in the wrong hands.\n\nWhen you connect to an SSH server, SSH will look for a public key that matches the client you're connecting from in the file `~/.ssh/authorized_keys` on the server you're connecting to. Notice the file is in the **home folder** of the ID you're trying to connect to. So, after creating the public key, you need to append it to `~/.ssh/authorized_keys`. One approach is to copy it to a USB stick and physically transfer it to the server. Another approach is to use [`ssh-copy-id`](https://www.ssh.com/ssh/copy-id) to transfer and append the public key.\n\nAfter the keys have been created and the public key has been appended to `~/.ssh/authorized_keys` on the host, SSH uses the public and private keys to verify identity and then establish a secure connection. How identity is verified is a complicated process but [Digital Ocean](https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process) has a very nice write-up of how it works. At a high level, identity is verified by the server encrypting a challenge message with the public key, then sending it to the client. If the client cannot decrypt the challenge message with the private key, the identity can't be verified and a connection will not be established.\n\nThey are considered more secure because you need the private key to establish an SSH connection. If you set [`PasswordAuthentication no` in `/etc/ssh/sshd_config`](#PasswordAuthentication), then SSH won't let you connect without the private key.\n\nYou can also set a pass-phrase for the keys which would require you to enter the key pass-phrase when connecting using public/private keys. Keep in mind doing this means you can't use the key for automation because you'll have no way to send the passphrase in your scripts. `ssh-agent` is a program that is shipped in many Linux distros (and usually already running) that will allow you to hold your unencrypted private key in memory for a configurable duration. Simply run `ssh-add` and it will prompt you for your passphrase. You will not be prompted for your passphrase again until the configurable duration has passed.\n\nWe will be using Ed25519 keys which, according to [https://linux-audit.com/](https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/):\n\n\u003e It is using an elliptic curve signature scheme, which offers better security than ECDSA and DSA. At the same time, it also has good performance.\n\n#### Goals\n\n- Ed25519 public/private SSH keys:\n  - private key on your client\n  - public key on your server\n\n#### Notes\n\n- You'll need to do this step for every computer and account you'll be connecting to your server from/as.\n\n#### References\n\n- https://www.ssh.com/ssh/public-key-authentication\n- https://help.ubuntu.com/community/SSH/OpenSSH/Keys\n- https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/\n- https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process\n- https://wiki.archlinux.org/index.php/SSH_Keys\n- https://www.ssh.com/ssh/copy-id\n- `man ssh-keygen`\n- `man ssh-copy-id`\n- `man ssh-add`\n\n#### Steps\n\n1. From the computer you're going to use to connect to your server, **the client**, not the server itself, create an [Ed25519](https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/) key with `ssh-keygen`:\n\n    ``` bash\n    ssh-keygen -t ed25519\n    ```\n\n    \u003e ```\n    \u003e Generating public/private ed25519 key pair.\n    \u003e Enter file in which to save the key (/home/user/.ssh/id_ed25519):\n    \u003e Created directory '/home/user/.ssh'.\n    \u003e Enter passphrase (empty for no passphrase):\n    \u003e Enter same passphrase again:\n    \u003e Your identification has been saved in /home/user/.ssh/id_ed25519.\n    \u003e Your public key has been saved in /home/user/.ssh/id_ed25519.pub.\n    \u003e The key fingerprint is:\n    \u003e SHA256:F44D4dr2zoHqgj0i2iVIHQ32uk/Lx4P+raayEAQjlcs user@client\n    \u003e The key's randomart image is:\n    \u003e +--[ED25519 256]--+\n    \u003e |xxxx  x          |\n    \u003e |o.o +. .         |\n    \u003e | o o oo   .      |\n    \u003e |. E oo . o .     |\n    \u003e | o o. o S o      |\n    \u003e |... .. o o       |\n    \u003e |.+....+ o        |\n    \u003e |+.=++o.B..       |\n    \u003e |+..=**=o=.       |\n    \u003e +----[SHA256]-----+\n    \u003e ```\n\n    **Note**: If you set a passphrase, you'll need to enter it every time you connect to your server using this key, unless you're using `ssh-agent`.\n\n1. Now you need to **append** the public key `~/.ssh/id_ed25519.pub` from your client to the `~/.ssh/authorized_keys` file on your server. Since we're presumable still at home on the LAN, we're probably safe from [MIM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks, so we will use `ssh-copy-id` to transfer and append the public key:\n\n    ``` bash\n    ssh-copy-id user@server\n    ```\n\n    \u003e ```\n    \u003e /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: \"/home/user/.ssh/id_ed25519.pub\"\n    \u003e The authenticity of host 'host (192.168.1.96)' can't be established.\n    \u003e ECDSA key fingerprint is SHA256:QaDQb/X0XyVlogh87sDXE7MR8YIK7ko4wS5hXjRySJE.\n    \u003e Are you sure you want to continue connecting (yes/no)? yes\n    \u003e /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed\n    \u003e /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\n    \u003e user@host's password:\n    \u003e \n    \u003e Number of key(s) added: 1\n    \u003e \n    \u003e Now try logging into the machine, with:   \"ssh 'user@host'\"\n    \u003e and check to make sure that only the key(s) you wanted were added.\n    \u003e ```\n\nNow would be a good time to [perform any tasks specific to your setup](#prepost-installation-requirements).\n\n([Table of Contents](#table-of-contents))\n\n### Create SSH Group For AllowGroups\n\n#### Why\n\nTo make it easy to control who can SSH to the server. By using a group, we can quickly add/remove accounts to the group to quickly allow or not allow SSH access to the server.\n\n#### How It Works\n\nWe will use the [AllowGroups option](#AllowGroups) in SSH's configuration file [`/etc/ssh/sshd_config`](#secure-etcsshsshd_config) to tell the SSH server to only allow users to SSH in if they are a member of a certain UNIX group. Anyone not in the group will not be able to SSH in.\n\n#### Goals\n\n- a UNIX group that we'll use in [Secure `/etc/ssh/sshd_config`](#secure-etcsshsshd_config) to limit who can SSH to the server\n\n#### Notes\n\n- This is a prerequisite step to support the `AllowGroup` setting set in [Secure `/etc/ssh/sshd_config`](#secure-etcsshsshd_config).\n\n#### References\n\n- `man groupadd`\n- `man usermod`\n\n#### Steps\n\n1. Create a group:\n\n    ``` bash\n    sudo groupadd sshusers\n    ```\n\n1. Add account(s) to the group:\n\n    ``` bash\n    sudo usermod -a -G sshusers user1\n    sudo usermod -a -G sshusers user2\n    sudo usermod -a -G sshusers ...\n    ```\n\n    You'll need to do this for every account on your server that needs SSH access.\n\n([Table of Contents](#table-of-contents))\n\n### Secure `/etc/ssh/sshd_config`\n\n#### Why\n\nSSH is a door into your server. This is especially true if you are opening ports on your router so you can SSH to your server from outside your home network. If it is not secured properly, a bad-actor could use it to gain unauthorized access to your system.\n\n#### How It Works\n\n`/etc/ssh/sshd_config` is the default configuration file that the SSH server uses. We will use this file to tell what options the SSH server should use.\n\n#### Goals\n\n- a secure SSH configuration\n\n#### Notes\n\n- Make sure you've completed [Create SSH Group For AllowGroups](#create-ssh-group-for-allowgroups) first.\n\n#### References\n\n- Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67\n- https://linux-audit.com/audit-and-harden-your-ssh-configuration/\n- https://www.ssh.com/ssh/sshd_config/\n- https://www.techbrown.com/harden-ssh-secure-linux-vps-server/ (broken; try http://web.archive.org/web/20200413100933/https://www.techbrown.com/harden-ssh-secure-linux-vps-server/)\n- https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server/660325\n- `man sshd_config`\n- Thanks to [than0s](https://github.com/than0s) for [how to find duplicate settings](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/38).\n\n#### Steps\n\n1. Make a backup of OpenSSH server's configuration file `/etc/ssh/sshd_config` and remove comments to make it easier to read:\n\n    ``` bash\n    sudo cp --archive /etc/ssh/sshd_config /etc/ssh/sshd_config-COPY-$(date +\"%Y%m%d%H%M%S\")\n    sudo sed -i -r -e '/^#|^$/ d' /etc/ssh/sshd_config\n    ```\n\n1. Edit `/etc/ssh/sshd_config` then find and edit or add these settings that should be applied regardless of your configuration/setup:\n\n    **Note**: SSH does not like duplicate contradicting settings. For example, if you have `ChallengeResponseAuthentication no` and then `ChallengeResponseAuthentication yes`, SSH will respect the first one and ignore the second. Your `/etc/ssh/sshd_config` file may already have some of the settings/lines below. To avoid issues you will need to manually go through your `/etc/ssh/sshd_config` file and address any duplicate contradicting settings. \n\n    ```\n    ########################################################################################################\n    # start settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01\n    ########################################################################################################\n\n    # Supported HostKey algorithms by order of preference.\n    HostKey /etc/ssh/ssh_host_ed25519_key\n    HostKey /etc/ssh/ssh_host_rsa_key\n    HostKey /etc/ssh/ssh_host_ecdsa_key\n\n    KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256\n\n    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\n\n    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com\n\n    # LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a clear audit track of which key was using to log in.\n    LogLevel VERBOSE\n\n    # Use kernel sandbox mechanisms where possible in unprivileged processes\n    # Systrace on OpenBSD, Seccomp on Linux, seatbelt on MacOSX/Darwin, rlimit elsewhere.\n    # Note: This setting is deprecated in OpenSSH 7.5 (https://www.openssh.com/txt/release-7.5)\n    # UsePrivilegeSeparation sandbox\n\n    ########################################################################################################\n    # end settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01\n    ########################################################################################################\n\n    # don't let users set environment variables\n    PermitUserEnvironment no\n\n    # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise.\n    Subsystem sftp  internal-sftp -f AUTHPRIV -l INFO\n\n    # only use the newer, more secure protocol\n    Protocol 2\n\n    # disable X11 forwarding as X11 is very insecure\n    # you really shouldn't be running X on a server anyway\n    X11Forwarding no\n\n    # disable port forwarding\n    AllowTcpForwarding no\n    AllowStreamLocalForwarding no\n    GatewayPorts no\n    PermitTunnel no\n\n    # don't allow login if the account has an empty password\n    PermitEmptyPasswords no\n\n    # ignore .rhosts and .shosts\n    IgnoreRhosts yes\n\n    # verify hostname matches IP\n    UseDNS yes\n\n    Compression no\n    TCPKeepAlive no\n    AllowAgentForwarding no\n    PermitRootLogin no\n\n    # don't allow .rhosts or /etc/hosts.equiv\n    HostbasedAuthentication no\n\n    # https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/115\n    HashKnownHosts yes\n    ```\n\n1. Then **find and edit or add** these settings, and set values as per your requirements:\n\n    |Setting|Valid Values|Example|Description|Notes|\n    |--|--|--|--|--|\n    |\u003ca name=\"AllowGroups\"\u003e\u003c/a\u003e**AllowGroups**|local UNIX group name|`AllowGroups sshusers`|group to allow SSH access to||\n    |**ClientAliveCountMax**|number|`ClientAliveCountMax 0`|maximum number of client alive messages sent without response||\n    |**ClientAliveInterval**|number of seconds|`ClientAliveInterval 300`|timeout in seconds before a response request||\n    |**ListenAddress**|space separated list of local addresses|\u003cul\u003e\u003cli\u003e`ListenAddress 0.0.0.0`\u003c/li\u003e\u003cli\u003e`ListenAddress 192.168.1.100`\u003c/li\u003e\u003c/ul\u003e|local addresses `sshd` should listen on|See [Issue #1](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/1) for important details.|\n    |**LoginGraceTime**|number of seconds|`LoginGraceTime 30`|time in seconds before login times-out||\n    |**MaxAuthTries**|number|`MaxAuthTries 2`|maximum allowed attempts to login||\n    |**MaxSessions**|number|`MaxSessions 2`|maximum number of open sessions||\n    |**MaxStartups**|number|`MaxStartups 2`|maximum number of login sessions||\n    |\u003ca name=\"PasswordAuthentication\"\u003e\u003c/a\u003e**PasswordAuthentication**|`yes` or `no`|`PasswordAuthentication no`|if login with a password is allowed||\n    |**Port**|any open/available port number|`Port 22`|port that `sshd` should listen on||\n\n    Check `man sshd_config` for more details what these settings mean.\n\n1. Make sure there are no duplicate settings that contradict each other. The below command should not have any output.\n\n    ```bash\n    awk 'NF \u0026\u0026 $1!~/^(#|HostKey)/{print $1}' /etc/ssh/sshd_config | sort | uniq -c | grep -v ' 1 '\n    ```\n\n1. Restart ssh:\n\n    ``` bash\n    sudo service sshd restart\n    ```\n\n1. You can check verify the configurations worked with `sshd -T` and verify the output:\n\n    ``` bash\n    sudo sshd -T\n    ```\n\n    \u003e ```\n    \u003e port 22\n    \u003e addressfamily any\n    \u003e listenaddress [::]:22\n    \u003e listenaddress 0.0.0.0:22\n    \u003e usepam yes\n    \u003e logingracetime 30\n    \u003e x11displayoffset 10\n    \u003e maxauthtries 2\n    \u003e maxsessions 2\n    \u003e clientaliveinterval 300\n    \u003e clientalivecountmax 0\n    \u003e streamlocalbindmask 0177\n    \u003e permitrootlogin no\n    \u003e ignorerhosts yes\n    \u003e ignoreuserknownhosts no\n    \u003e hostbasedauthentication no\n    \u003e ...\n    \u003e subsystem sftp internal-sftp -f AUTHPRIV -l INFO\n    \u003e maxstartups 2:30:2\n    \u003e permittunnel no\n    \u003e ipqos lowdelay throughput\n    \u003e rekeylimit 0 0\n    \u003e permitopen any\n    \u003e ```\n\n([Table of Contents](#table-of-contents))\n\n### Remove Short Diffie-Hellman Keys\n\n#### Why\n\nPer [Mozilla's OpenSSH guidelines for OpenSSH 6.7+](https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67), \"all Diffie-Hellman moduli in use should be at least 3072-bit-long\".\n\nThe Diffie-Hellman algorithm is used by SSH to establish a secure connection. The larger the moduli (key size) the stronger the encryption.\n\n#### Goals\n\n- remove all Diffie-Hellman keys that are less than 3072 bits long\n\n#### References\n\n- Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67\n- https://infosec.mozilla.org/guidelines/key_management\n- `man moduli`\n\n#### Steps\n\n1. Make a backup of SSH's moduli file `/etc/ssh/moduli`:\n\n    ``` bash\n    sudo cp --archive /etc/ssh/moduli /etc/ssh/moduli-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. Remove short moduli:\n\n    ``` bash\n    sudo awk '$5 \u003e= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.tmp\n    sudo mv /etc/ssh/moduli.tmp /etc/ssh/moduli\n    ````\n\n([Table of Contents](#table-of-contents))\n\n### 2FA/MFA for SSH\n\n#### Why\n\nEven though SSH is a pretty good security guard for your doors and windows, it is still a visible door that bad-actors can see and try to brute-force in. [Fail2ban](#fail2ban-application-intrusion-detection-and-prevention) will monitor for these brute-force attempts but there is no such thing as being too secure. Requiring two factors adds an extra layer of security.\n\nUsing Two-Factor Authentication (2FA) / Multi-Factor Authentication (MFA) requires anyone entering to have **two** keys to enter which makes it harder for bad actors. The two keys are:\n\n1. Their password\n1. A 6 digit token that changes every 30 seconds\n\nWithout both keys, they won't be able to get in.\n\n#### Why Not\n\nMany folks might find the experience cumbersome or annoying. And, access to your system is dependent on the accompanying authenticator app that generates the code.\n\n#### How It Works\n\nOn Linux, PAM is responsible for authentication. There are four tasks to PAM that you can read about at https://en.wikipedia.org/wiki/Linux_PAM. This section talks about the authentication task.\n\nWhen you log into a server, be it directly from the console or via SSH, the door you came through will send the request to the authentication task of PAM and PAM will ask for and verify your password. You can customize the rules each doors use. For example, you could have one set of rules when logging in directly from the console and another set of rules for when logging in via SSH.\n\nThis section will alter the authentication rules for when logging in via SSH to require both a password and a 6 digit code.\n\nWe will use Google's libpam-google-authenticator PAM module to create and verify a [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm) key. https://fastmail.blog/2016/07/22/how-totp-authenticator-apps-work/ and https://jemurai.com/2018/10/11/how-it-works-totp-based-mfa/ have very good writeups of how TOTP works.\n\nWhat we will do is tell the server's SSH PAM configuration to ask the user for their password and then their numeric token. PAM will then verify the user's password and, if it is correct, then it will route the authentication request to libpam-google-authenticator which will ask for and verify your 6 digit token. If, and only if, everything is good will the authentication succeed and user be allowed to log in.\n\n#### Goals\n\n- 2FA/MFA enabled for all SSH connections\n\n#### Notes\n\n- Before you do this, you should have an idea of how 2FA/MFA works and you'll need an authenticator app on your phone to continue.\n- We'll use [google-authenticator-libpam](https://github.com/google/google-authenticator-libpam).\n- With the below configuration, a user will only need to enter their 2FA/MFA code if they are logging on with their password but **not** if they are using [SSH public/private keys](#ssh-publicprivate-keys). Check the documentation on how to change this behavior to suite your requirements.\n\n#### References\n\n- https://github.com/google/google-authenticator-libpam\n- https://en.wikipedia.org/wiki/Linux_PAM\n- https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm\n- https://fastmail.blog/2016/07/22/how-totp-authenticator-apps-work/\n- https://jemurai.com/2018/10/11/how-it-works-totp-based-mfa/\n\n#### Steps\n\n1. Install it libpam-google-authenticator.\n\n    On Debian based systems:\n\n    ``` bash\n    sudo apt install libpam-google-authenticator\n    ```\n\n1. **Make sure you're logged in as the ID you want to enable 2FA/MFA for** and **execute** `google-authenticator` to create the necessary token data:\n\n    ``` bash\n    google-authenticator\n    ```\n\n    \u003e ```\n    \u003e Do you want authentication tokens to be time-based (y/n) y\n    \u003e https://www.google.com/chart?chs=200x200\u0026chld=M|0\u0026cht=qr\u0026chl=otpauth://totp/user@host%3Fsecret%3DR4ZWX34FQKZROVX7AGLJ64684Y%26issuer%3Dhost\n    \u003e \n    \u003e ...\n    \u003e \n    \u003e Your new secret key is: R3NVX3FFQKZROVX7AGLJUGGESY\n    \u003e Your verification code is 751419\n    \u003e Your emergency scratch codes are:\n    \u003e   12345678\n    \u003e   90123456\n    \u003e   78901234\n    \u003e   56789012\n    \u003e   34567890\n    \u003e \n    \u003e Do you want me to update your \"/home/user/.google_authenticator\" file (y/n) y\n    \u003e \n    \u003e Do you want to disallow multiple uses of the same authentication\n    \u003e token? This restricts you to one login about every 30s, but it increases\n    \u003e your chances to notice or even prevent man-in-the-middle attacks (y/n) Do you want to disallow multiple uses of the same authentication\n    \u003e token? This restricts you to one login about every 30s, but it increases\n    \u003e your chances to notice or even prevent man-in-the-middle attacks (y/n) y\n    \u003e \n    \u003e By default, tokens are good for 30 seconds. In order to compensate for\n    \u003e possible time-skew between the client and the server, we allow an extra\n    \u003e token before and after the current time. If you experience problems with\n    \u003e poor time synchronization, you can increase the window from its default\n    \u003e size of +-1min (window size of 3) to about +-4min (window size of\n    \u003e 17 acceptable tokens).\n    \u003e Do you want to do so? (y/n) y\n    \u003e \n    \u003e If the computer that you are logging into isn't hardened against brute-force\n    \u003e login attempts, you can enable rate-limiting for the authentication module.\n    \u003e By default, this limits attackers to no more than 3 login attempts every 30s.\n    \u003e Do you want to enable rate-limiting (y/n) y\n    \u003e ```\n\n    Notice this is **not run as root**.\n\n    Select default option (y in most cases) for all the questions it asks and remember to save the emergency scratch codes.\n\n1. Make a backup of PAM's SSH configuration file `/etc/pam.d/sshd`:\n\n    ``` bash\n    sudo cp --archive /etc/pam.d/sshd /etc/pam.d/sshd-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. Now we need to enable it as an authentication method for SSH by adding this line to `/etc/pam.d/sshd`:\n\n    ```\n    auth       required     pam_google_authenticator.so nullok\n    ```\n\n    **Note**: Check [here](https://github.com/google/google-authenticator-libpam/blob/master/README.md#nullok) for what `nullok` means.\n\n    [For the lazy](#editing-configuration-files---for-the-lazy):\n\n    ``` bash\n    echo -e \"\\nauth       required     pam_google_authenticator.so nullok         # added by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")\" | sudo tee -a /etc/pam.d/sshd\n    ```\n\n1. Tell SSH to leverage it by adding or editing this line in `/etc/ssh/sshd_config`:\n\n    ```\n    ChallengeResponseAuthentication yes\n    ```\n\n    [For the lazy](#editing-configuration-files---for-the-lazy):\n\n    ``` bash\n    sudo sed -i -r -e \"s/^(challengeresponseauthentication .*)$/# \\1         # commented by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")/I\" /etc/ssh/sshd_config\n    echo -e \"\\nChallengeResponseAuthentication yes         # added by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")\" | sudo tee -a /etc/ssh/sshd_config\n    ```\n\n1. Restart ssh:\n\n    ``` bash\n    sudo service sshd restart\n    ```\n\n([Table of Contents](#table-of-contents))\n\n## The Basics\n\n### Limit Who Can Use sudo\n\n#### Why\n\nsudo lets accounts run commands as other accounts, including **root**. We want to make sure that only the accounts we want can use sudo.\n\n#### Goals\n\n- sudo privileges limited to those who are in a group we specify\n\n#### Notes\n\n- Your installation may have already done this, or may already have a special group intended for this purpose so check first.\n  - Debian creates the sudo group. To view users that are part of this group (thus have sudo privileges):\n\t  \n\t  ```\n\t  cat /etc/group | grep \"sudo\"\n\t  ```\n  - RedHat creates the wheel group\n- See [https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/39](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/39) for a note on some distributions making it so `sudo` does not require a password. Thanks to [sbrl](https://github.com/sbrl) for sharing.\n\n#### Steps\n\n1. Create a group:\n\n    ``` bash\n    sudo groupadd sudousers\n    ```\n\n1. Add account(s) to the group:\n\n    ``` bash\n    sudo usermod -a -G sudousers user1\n    sudo usermod -a -G sudousers user2\n    sudo usermod -a -G sudousers  ...\n    ```\n\n    You'll need to do this for every account on your server that needs sudo privileges.\n\n1. Make a backup of the sudo's configuration file `/etc/sudoers`:\n\n    ``` bash\n    sudo cp --archive /etc/sudoers /etc/sudoers-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. Edit sudo's configuration file `/etc/sudoers`:\n\n    ``` bash\n    sudo visudo\n    ```\n\n1. Tell sudo to only allow users in the `sudousers` group to use sudo by adding this line if it is not already there:\n\n    ```\n    %sudousers   ALL=(ALL:ALL) ALL\n    ```\n\n([Table of Contents](#table-of-contents))\n\n### Limit Who Can Use su\n\n#### Why\n\nsu also lets accounts run commands as other accounts, including **root**. We want to make sure that only the accounts we want can use su.\n\n#### Goals\n\n- su privileges limited to those who are in a group we specify\n\n#### References\n\n- Thanks to [olavim](https://github.com/olavim) for sharing [this idea](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/41)\n\n#### Steps\n\n1. Create a group:\n\n    ``` bash\n    sudo groupadd suusers\n    ```\n\n1. Add account(s) to the group:\n\n    ``` bash\n    sudo usermod -a -G suusers user1\n    sudo usermod -a -G suusers user2\n    sudo usermod -a -G suusers  ...\n    ```\n\n    You'll need to do this for every account on your server that needs sudo privileges.\n\n1. Make it so only users in this group can execute `/bin/su`:\n\n    ``` bash\n    sudo dpkg-statoverride --update --add root suusers 4750 /bin/su\n    ```\n\n([Table of Contents](#table-of-contents))\n\n### Run applications in a sandbox with FireJail\n\n#### Why\n\nIt's absolutely better, for many applications, to run in a sandbox.\n\nBrowsers (even more the Closed Source ones) and eMail Clients are highly suggested.\n\n#### Goals\n\n- confine applications in a jail (few safe directories) and block access to the rest of the system\n\n#### References\n\n- Thanks to [FireJail](https://firejail.wordpress.com/)\n\n#### Steps\n\n1. Install the software:\n\n    ``` bash\n    sudo apt install firejail firejail-profiles\n    ```\n    \n    Note: for Debian 10 Stable, official Backport is suggested:\n\n    ``` bash\n    sudo apt install -t buster-backports firejail firejail-profiles\n    ```\n\n2. Allow an application (installed in `/usr/bin` or `/bin`) to run only in a sandbox (see few examples below here):\n\n    ``` bash\n    sudo ln -s /usr/bin/firejail /usr/local/bin/google-chrome-stable\n    sudo ln -s /usr/bin/firejail /usr/local/bin/firefox\n    sudo ln -s /usr/bin/firejail /usr/local/bin/chromium\n    sudo ln -s /usr/bin/firejail /usr/local/bin/evolution\n    sudo ln -s /usr/bin/firejail /usr/local/bin/thunderbird\n    ```\n\n3. Run the application as usual (via terminal or launcher) and check if it's running in a jail:\n\n    ``` bash\n    firejail --list\n    ```\n\n4. Allow a sandboxed app to run again as it was before (example: firefox)\n\n    ``` bash\n    sudo rm /usr/local/bin/firefox\n    ```\n\n([Table of Contents](#table-of-contents))\n\n### NTP Client\n\n#### Why\n\nMany security protocols leverage the time. If your system time is incorrect, it could have negative impacts to your server. An NTP client can solve that problem by keeping your system time in-sync with [global NTP servers](https://en.wikipedia.org/wiki/Network_Time_Protocol)\n\n#### How It Works\n\nNTP stands for Network Time Protocol. In the context of this guide, an NTP client on the server is used to update the server time with the official time pulled from official servers. Check https://www.pool.ntp.org/en/ for all of the public NTP servers.\n\n#### Goals\n\n- NTP client installed and keeping server time in-sync\n\n#### References\n\n- https://cloudpro.zone/index.php/2018/01/27/debian-9-3-server-setup-guide-part-4/\n- https://en.wikipedia.org/wiki/Network_Time_Protocol\n- https://www.pool.ntp.org/en/\n- https://serverfault.com/questions/957302/securing-hardening-ntp-client-on-linux-servers-config-file/957450#957450\n- https://tf.nist.gov/tf-cgi/servers.cgi\n\n#### Steps\n\n1. Install ntp.\n\n    On Debian based systems:\n\n    ``` bash\n    sudo apt install ntp\n    ```\n    \n1. Make a backup of the NTP client's configuration file `/etc/ntp.conf`:\n\n    ``` bash\n    sudo cp --archive /etc/ntpsec/ntp.conf /etc/ntpsec/ntp.conf-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. The default configuration, at least on Debian, is already pretty secure. The only thing we'll want to make sure is we're the `pool` directive and not any `server` directives. The `pool` directive allows the NTP client to stop using a server if it is unresponsive or serving bad time. Do this by commenting out all `server` directives and adding the below to `/etc/ntp.conf`.\n\t\n    ```\n    pool pool.ntp.org iburst\n    ```\n    \n    [For the lazy](#editing-configuration-files---for-the-lazy):\n    \n    ``` bash\n    sudo sed -i -r -e \"s/^((server|pool).*)/# \\1         # commented by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")/\" /etc/ntp.conf\n    echo -e \"\\npool pool.ntp.org iburst         # added by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")\" | sudo tee -a /etc/ntp.conf\n    ```\n\n    **Example `/etc/ntp.conf`**:\n    \n    \u003e ```\n    \u003e driftfile /var/lib/ntp/ntp.drift\n    \u003e statistics loopstats peerstats clockstats\n    \u003e filegen loopstats file loopstats type day enable\n    \u003e filegen peerstats file peerstats type day enable\n    \u003e filegen clockstats file clockstats type day enable\n    \u003e restrict -4 default kod notrap nomodify nopeer noquery limited\n    \u003e restrict -6 default kod notrap nomodify nopeer noquery limited\n    \u003e restrict 127.0.0.1\n    \u003e restrict ::1\n    \u003e restrict source notrap nomodify noquery\n    \u003e pool pool.ntp.org iburst         # added by user on 2019-03-09 @ 10:23:35\n    \u003e ```\n    \n1. Restart ntp:\n\n    ``` bash\n    sudo service ntp restart\n    ```\n\n1. Check the status of the ntp service:\n\n    ``` bash\n    sudo systemctl status ntp\n    ```\n\n    \u003e ```\n    \u003e ● ntp.service - LSB: Start NTP daemon\n    \u003e    Loaded: loaded (/etc/init.d/ntp; generated; vendor preset: enabled)\n    \u003e    Active: active (running) since Sat 2019-03-09 15:19:46 EST; 4s ago\n    \u003e      Docs: man:systemd-sysv-generator(8)\n    \u003e   Process: 1016 ExecStop=/etc/init.d/ntp stop (code=exited, status=0/SUCCESS)\n    \u003e   Process: 1028 ExecStart=/etc/init.d/ntp start (code=exited, status=0/SUCCESS)\n    \u003e     Tasks: 2 (limit: 4915)\n    \u003e    CGroup: /system.slice/ntp.service\n    \u003e            └─1038 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 108:113\n    \u003e \n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listen and drop on 0 v6wildcard [::]:123\n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listen and drop on 1 v4wildcard 0.0.0.0:123\n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listen normally on 2 lo 127.0.0.1:123\n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listen normally on 3 enp0s3 10.10.20.96:123\n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listen normally on 4 lo [::1]:123\n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listen normally on 5 enp0s3 [fe80::a00:27ff:feb6:ed8e%2]:123\n    \u003e Mar 09 15:19:46 host ntpd[1038]: Listening on routing socket on fd #22 for interface updates\n    \u003e Mar 09 15:19:47 host ntpd[1038]: Soliciting pool server 108.61.56.35\n    \u003e Mar 09 15:19:48 host ntpd[1038]: Soliciting pool server 69.89.207.199\n    \u003e Mar 09 15:19:49 host ntpd[1038]: Soliciting pool server 45.79.111.114\n    \u003e ```\n\n1. Check ntp's status:\n\n    ``` bash\n    sudo ntpq -p\n    ```\n\n    \u003e ```\n    \u003e      remote           refid      st t when poll reach   delay   offset  jitter\n    \u003e ==============================================================================\n    \u003e  pool.ntp.org    .POOL.          16 p    -   64    0    0.000    0.000   0.000\n    \u003e *lithium.constan 198.30.92.2      2 u    -   64    1   19.900    4.894   3.951\n    \u003e  ntp2.wiktel.com 212.215.1.157    2 u    2   64    1   48.061   -0.431   0.104\n    \u003e ```\n\n([Table of Contents](#table-of-contents))\n\n### Securing /proc\n\n#### Why\n\nTo quote https://linux-audit.com/linux-system-hardening-adding-hidepid-to-proc/:\n\n\u003e When looking in `/proc` you will discover a lot of files and directories. Many of them are just numbers, which represent the information about a particular process ID (PID). By default, Linux systems are deployed to allow all local users to see this all information. This includes process information from other users. This could include sensitive details that you may not want to share with other users. By applying some filesystem configuration tweaks, we can change this behavior and improve the security of the system.\n\n**Note**: This may break on some `systemd` systems. Please see [https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/37](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/37) for more information. Thanks to [nlgranger](https://github.com/nlgranger) for sharing.\n\n#### Goals\n\n- `/proc` mounted with `hidepid=2` so users can only see information about their processes\n\n#### References\n\n- https://linux-audit.com/linux-system-hardening-adding-hidepid-to-proc/\n- https://likegeeks.com/secure-linux-server-hardening-best-practices/#Hardening-proc-Directory\n- https://www.cyberciti.biz/faq/linux-hide-processes-from-other-users/\n\n#### Steps\n\n1. Make a backup of `/etc/fstab`:\n\n    ``` bash\n    sudo cp --archive /etc/fstab /etc/fstab-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. Add this line to `/etc/fstab` to have `/proc` mounted with `hidepid=2`:\n\n    ```\n    proc     /proc     proc     defaults,hidepid=2     0     0\n    ```\n    \n    [For the lazy](#editing-configuration-files---for-the-lazy):\n    \n    ``` bash\n    echo -e \"\\nproc     /proc     proc     defaults,hidepid=2     0     0         # added by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")\" | sudo tee -a /etc/fstab\n    ```\n\n1. Reboot the system:\n\n    ``` bash\n    sudo reboot now\n    ```\n    \n    **Note**: Alternatively, you can remount `/proc` without rebooting with `sudo mount -o remount,hidepid=2 /proc`\n\n([Table of Contents](#table-of-contents))\n\n### Force Accounts To Use Secure Passwords\n\n#### Why\n\nBy default, accounts can use any password they want, including bad ones. [pwquality](https://linux.die.net/man/5/pwquality.conf)/[pam_pwquality](https://linux.die.net/man/8/pam_pwquality) addresses this security gap by providing \"a way to configure the default password quality requirements for the system passwords\" and checking \"its strength against a system dictionary and a set of rules for identifying poor choices.\"\n\n#### How It Works\n\nOn Linux, PAM is responsible for authentication. There are four tasks to PAM that you can read about at https://en.wikipedia.org/wiki/Linux_PAM. This section talks about the password task.\n\nWhen there is a need to set or change an account password, the password task of PAM handles the request. In this section we will tell PAM's password task to pass the requested new password to libpam-pwquality to make sure it meets our requirements. If the requirements are met it is used/set; if it does not meet the requirements it errors and lets the user know.\n\n#### Goals\n\n- enforced strong passwords\n\n#### Steps\n\n1. Install libpam-pwquality.\n\n    On Debian based systems:\n\n    ``` bash\n    sudo apt install libpam-pwquality\n    ```\n\n1. Make a backup of PAM's password configuration file `/etc/pam.d/common-password`:\n\n    ``` bash\n    sudo cp --archive /etc/pam.d/common-password /etc/pam.d/common-password-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. Tell PAM to use libpam-pwquality to enforce strong passwords by editing the file `/etc/pam.d/common-password` and change the line that starts like this:\n\n    ```\n    password        requisite                       pam_pwquality.so\n    ```\n\n    to this:\n\n    ```\n    password        requisite                       pam_pwquality.so retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec\n    ```\n\n   The above options are:\n\n     - `retry=3` = prompt user 3 times before returning with error.\n     - `minlen=10` = the minimum length of the password, factoring in any credits (or debits) from these:\n       - `dcredit=-1` = must have at least **one digit**\n       - `ucredit=-1` = must have at least **one upper case letter**\n       - `lcredit=-1` = must have at least **one lower case letter**\n       - `ocredit=-1` = must have at least **one non-alphanumeric character**\n     - `difok=3` = at least 3 characters from the new password cannot have been in the old password\n     - `maxrepeat=3` = allow a maximum of 3 repeated characters\n     - `gecoschec` = do not allow passwords with the account's name\n\n\n    [For the lazy](#editing-configuration-files---for-the-lazy):\n    \n    ``` bash\n    sudo sed -i -r -e \"s/^(password\\s+requisite\\s+pam_pwquality.so)(.*)$/# \\1\\2         # commented by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")\\n\\1 retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec         # added by $(whoami) on $(date +\"%Y-%m-%d @ %H:%M:%S\")/\" /etc/pam.d/common-password\n    ```\n\n([Table of Contents](#table-of-contents))\n\n### Automatic Security Updates and Alerts\n\n#### Why\n\nIt is important to keep a server updated with the latest **critical security patches and updates**. Otherwise you're at risk of known security vulnerabilities that bad-actors could use to gain unauthorized access to your server.\n\nUnless you plan on checking your server every day, you'll want a way to automatically update the system and/or get emails about available updates.\n\nYou don't want to do all updates because with every update there is a risk of something breaking. It is important to do the critical updates but everything else can wait until you have time to do it manually.\n\n#### Why Not\n\nAutomatic and unattended updates may break your system and you may not be near your server to fix it. This would be especially problematic if it broke your SSH access.\n\n#### Notes\n\n- Each distribution manages packages and updates differently. So far I only have steps for Debian based systems.\n- Your server will need a way to send e-mails for this to work\n\n#### Goals\n\n- Automatic, unattended, updates of critical security patches\n- Automatic emails of remaining pending updates\n\n#### Debian Based Systems\n\n##### How It Works\n\nOn Debian based systems you can use:\n\n- unattended-upgrades to automatically do system updates you want (i.e. critical security updates)\n- apt-listchanges to get details about package changes before they are installed/upgraded\n- apticron to get emails for pending package updates\n\nWe will use unattended-upgrades to apply **critical security patches**. We can also apply stable updates since they've already been thoroughly tested by the Debian community.\n\n##### References\n\n- https://wiki.debian.org/UnattendedUpgrades\n- https://debian-handbook.info/browse/stable/sect.regular-upgrades.html\n- https://blog.sleeplessbeastie.eu/2015/01/02/how-to-perform-unattended-upgrades/\n- https://www.vultr.com/docs/how-to-set-up-unattended-upgrades-on-debian-9-stretch\n- https://github.com/mvo5/unattended-upgrades\n- https://wiki.debian.org/UnattendedUpgrades#apt-listchanges\n- https://www.cyberciti.biz/faq/apt-get-apticron-send-email-upgrades-available/\n- https://www.unixmen.com/how-to-get-email-notifications-for-new-updates-on-debianubuntu/\n- `/etc/apt/apt.conf.d/50unattended-upgrades`\n\n##### Steps\n\n1. Install unattended-upgrades, apt-listchanges, and apticron:\n\n    ``` bash\n    sudo apt install unattended-upgrades apt-listchanges apticron\n    ```\n\n1. Now we need to configure unattended-upgrades to automatically apply the updates. This is typically done by editing the files `/etc/apt/apt.conf.d/20auto-upgrades` and `/etc/apt/apt.conf.d/50unattended-upgrades` that were created by the packages. However, because these file may get overwritten with a future update, we'll create a new file instead. Create the file `/etc/apt/apt.conf.d/51myunattended-upgrades` and add this:\n\n    ```\n    // Enable the update/upgrade script (0=disable)\n    APT::Periodic::Enable \"1\";\n\n    // Do \"apt-get update\" automatically every n-days (0=disable)\n    APT::Periodic::Update-Package-Lists \"1\";\n\n    // Do \"apt-get upgrade --download-only\" every n-days (0=disable)\n    APT::Periodic::Download-Upgradeable-Packages \"1\";\n\n    // Do \"apt-get autoclean\" every n-days (0=disable)\n    APT::Periodic::AutocleanInterval \"7\";\n\n    // Send report mail to root\n    //     0:  no report             (or null string)\n    //     1:  progress report       (actually any string)\n    //     2:  + command outputs     (remove -qq, remove 2\u003e/dev/null, add -d)\n    //     3:  + trace on    APT::Periodic::Verbose \"2\";\n    APT::Periodic::Unattended-Upgrade \"1\";\n\n    // Automatically upgrade packages from these\n    Unattended-Upgrade::Origins-Pattern {\n          \"o=Debian,a=stable\";\n          \"o=Debian,a=stable-updates\";\n          \"origin=Debian,codename=${distro_codename},label=Debian-Security\";\n    };\n\n    // You can specify your own packages to NOT automatically upgrade here\n    Unattended-Upgrade::Package-Blacklist {\n    };\n\n    // Run dpkg --force-confold --configure -a if a unclean dpkg state is detected to true to ensure that updates get installed even when the system got interrupted during a previous run\n    Unattended-Upgrade::AutoFixInterruptedDpkg \"true\";\n\n    //Perform the upgrade when the machine is running because we wont be shutting our server down often\n    Unattended-Upgrade::InstallOnShutdown \"false\";\n\n    // Send an email to this address with information about the packages upgraded.\n    Unattended-Upgrade::Mail \"root\";\n\n    // Always send an e-mail\n    Unattended-Upgrade::MailOnlyOnError \"false\";\n\n    // Remove all unused dependencies after the upgrade has finished\n    Unattended-Upgrade::Remove-Unused-Dependencies \"true\";\n\n    // Remove any new unused dependencies after the upgrade has finished\n    Unattended-Upgrade::Remove-New-Unused-Dependencies \"true\";\n\n    // Automatically reboot WITHOUT CONFIRMATION if the file /var/run/reboot-required is found after the upgrade.\n    Unattended-Upgrade::Automatic-Reboot \"true\";\n\n    // Automatically reboot even if users are logged in.\n    Unattended-Upgrade::Automatic-Reboot-WithUsers \"true\";\n    ```\n\n    **Notes**:\n    - Check `/usr/lib/apt/apt.systemd.daily` for details on the `APT::Periodic` options\n    - Check https://github.com/mvo5/unattended-upgrades for details on the `Unattended-Upgrade` options\n\n1. Run a dry-run of unattended-upgrades to make sure your configuration file is okay:\n\n    ``` bash\n    sudo unattended-upgrade -d --dry-run\n    ```\n\n    If everything is okay, you can let it run whenever it's scheduled to or force a run with `unattended-upgrade -d`.\n\n1. Configure apt-listchanges to your liking:\n\n    ``` bash\n    sudo dpkg-reconfigure apt-listchanges\n    ```\n\n1. For apticron, the default settings are good enough but you can check them in `/etc/apticron/apticron.conf` if you want to change them. For example, my configuration looks like this:\n\n    \u003e ```\n    \u003e EMAIL=\"root\"\n    \u003e NOTIFY_NO_UPDATES=\"1\"\n    \u003e ```\n\n([Table of Contents](#table-of-contents))\n\n### More Secure Random Entropy Pool (WIP)\n\n#### Why\n\nWIP\n\n#### How It Works\n\nWIP\n\n#### Goals\n\nWIP\n\n#### References\n\n- Thanks to [branneman](https://github.com/branneman) for this idea as submitted in [issue #33](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/33).\n- https://hackaday.com/2017/11/02/what-is-entropy-and-how-do-i-get-more-of-it/\n- https://www.2uo.de/myths-about-urandom\n- https://www.gnu.org/software/hurd/user/tlecarrour/rng-tools.html\n- https://wiki.archlinux.org/index.php/Rng-tools\n- https://www.howtoforge.com/helping-the-random-number-generator-to-gain-enough-entropy-with-rng-tools-debian-lenny\n- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generator\n\n#### Steps\n\n1. Install rng-tools.\n   \n    On Debian based systems:\n\n    ``` bash\n    sudo apt-get install rng-tools\n    ```\n\n1. Now we need to set the hardware device used to generate random numbers by adding this to `/etc/default/rng-tools`:\n\n    ```\n    HRNGDEVICE=/dev/urandom\n    ```\n    \n    [For the lazy](#editing-configuration-files---for-the-lazy):\n    \n    ``` bash\n    echo \"HRNGDEVICE=/dev/urandom\" | sudo tee -a /etc/default/rng-tools\n    ```\n\n1. Restart the service:\n\n    ``` bash\n    sudo systemctl stop rng-tools.service\n    sudo systemctl start rng-tools.service\n    ```\n\n1. Test randomness:\n    - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generator\n    - https://wiki.archlinux.org/index.php/Rng-tools\n\n([Table of Contents](#table-of-contents))\n\n### Add Panic/Secondary/Fake password Login Security System\n\n#### Why\n\nA nice tool to add extra password security, against physical attack (In-Person) Ramson/Rob/assault methods.\n\n#### How It Works\n\nThe pamduress will add to the X user a secondary password (Panic password), when this password match will start run a script (this script do what you what the user do, when he logins with THESE panic password.\n\nPractical \u0026 real Example:\n\"Some Robber invade a home, and steal the server (containing IMPORTANT business backups, and ownlife memories and blablabla). Not exist any disk/boot encryption. Robber have start the server on their 'safe zone' and start an bruteforce attack. He have cracked the local password by SSH with from sudoer user 'admin' success, yeah a dummy password, not THE Strong one/primary. He starts SSH session/or physical session with that cracked dummy/panic password with 'admin' sudoer. He starts feeling the server seems too much busy in less than 2 minutes until to freeze.. 'wtf!?! lets reboot and continue steal info..'.. sorry friend. all data and system was destroyed.\".\n    Conclusion, the robber cracked the dummy/panic/secondary password, and with this password its associated a script will do delete all files, config, system, boot and after than start charge the RAM and CPU to force robber reboot system.  \n\n#### Goals\n\nPrevent access to malicious person to access server information when get an a password in force way (assault, gun, ransom, ...). Of course this is helpfull in other situations.\n\n#### References\n\n- Thanks to [nuvious](https://github.com/nuvious/pam-duress) for this tool\n- Thanks to [hellresistor](https://gist.github.com/hellresistor/a4c542415a2d437e21afc235260d2366) for this Lazy-Tool-Script\n\n#### Steps\n\n1. Run this (hellresistor Lazy-Tool-Script).\n\n ```` bash\n#!/bin/bash\nmyownscript(){\n#######################################################\n## ***** EDIT THIS SCRIPT TO YOUR PROPOSES *****#\n\ncat \u003e \"$ScriptFile\" \u003c\u003c-EOF\n#!/bin/bash\nsudo rm -rf /home\n#### FINISHED OWN SCRIPT ####\nEOF\n#######################################################\n}\necho \"Lets Config a PANIC PASSWORD ;)\" \u0026\u0026 sleep 1\nread -r -p \"Want you REALLY configure A PANIC PASSWORD?? Write [ OK ] : \" PAMDUR\nif [[ \"$PAMDUR\" = \"OK\" ]]; then\n echo \"Lets Config a PANIC USER, PASSWORD and SCRIPT ;)\" \u0026\u0026 sleep 1\n while [ -z \"$PANICUSR\" ]\n do\n  read -r -p \"WRITE a Panic User to your pam-duress user [ root ]: \" PANICUSR\n  PANICUSR=${PANICUSR:=root}\n done\n if [ -z \"$ScriptLoc\" ]; then\n  read -r -p \"SET Script Directory with FULL PATH [ /root/.duress ]: \" ScriptLoc\n  ScriptLoc=${ScriptLoc:=/root/.duress}\n  ScriptFile=\"$ScriptLoc/PanicScript.sh\"\n fi\nelse\n echo \"NOT Use PAM DURESS aKa Panic Password!!! Bye\"\n exit 1\nfi\n\nsudo apt install -y git build-essential libpam0g-dev libssl-dev\n\ncd \"$HOME\" || exit 1\ngit clone https://github.com/nuvious/pam-duress.git\ncd pam-duress || exit 1\nmake \nsudo make install\nmake clean\n#make uninstall\n\nmkdir -p $ScriptLoc\nsudo mkdir -p /etc/duress.d\nmyownscript\nduress_sign $ScriptFile\nchmod -R 500 $ScriptLoc\nchmod 400 $ScriptLoc/*.sha256\nchown -R $PANICUSR $ScriptLoc\n\nsudo cp --preserve /etc/pam.d/common-auth /etc/pam.d/common-auth.bck\n\necho \"\nauth   \t[success=2 default=ignore]\t     pam_unix.so nullok_secure\nauth    [success=1 default=ignore]      pam_duress.so\nauth\t   requisite\t                    \t\tpam_deny.so\nauth\t   required\t                     \t\tpam_permit.so\n\" | sudo tee /etc/pam.d/common-auth\n\nread -r -p \"Press \u003cEnter\u003e Key to Finish PAM DURESS Script!\"\nexit 0\n ````\n\n([Table of Contents](#table-of-contents))\n\n## The Network\n\n### Firewall With UFW (Uncomplicated Firewall)\n\n#### Why\n\nCall me paranoid, and you don't have to agree, but I want to deny all traffic in and out of my server except what I explicitly allow. Why would my server be sending traffic out that I don't know about? And why would external traffic be trying to access my server if I don't know who or what it is? When it comes to good security, my opinion is to reject/deny by default, and allow by exception.\n\nOf course, if you disagree, that is totally fine and can configure UFW to suit your needs.\n\nEither way, ensuring that only traffic we explicitly allow is the job of a firewall.\n\n#### How It Works\n\nThe Linux kernel provides capabilities to monitor and control network traffic. These capabilities are exposed to the end-user through firewall utilities. On Linux, the most common firewall is [iptables](https://en.wikipedia.org/wiki/Iptables). However, iptables is rather complicated and confusing (IMHO). This is where UFW comes in. Think of UFW as a front-end to iptables. It simplifies the process of managing the iptables rules that tell the Linux kernel what to do with network traffic.\n\n**UFW** works by letting you configure rules that:\n\n- **allow** or **deny**\n- **input** or **output** traffic\n- **to** or **from** ports\n\nYou can create rules by explicitly specifying the ports or with application configurations that specify the ports.\n\n#### Goals\n\n - all network traffic, input and output, blocked except those we explicitly allow\n\n#### Notes\n\n- As you install other programs, you'll need to enable the necessary ports/applications.\n\n#### References\n\n- https://launchpad.net/ufw\n\n#### Steps\n\n1. Install ufw.\n\n    On Debian based systems:\n\n    ``` bash\n    sudo apt install ufw\n    ```\n\n1. Deny all outgoing traffic:\n\n    ``` bash\n    sudo ufw default deny outgoing comment 'deny all outgoing traffic'\n    ```\n\n    \u003e ```\n    \u003e Default outgoing policy changed to 'deny'\n    \u003e (be sure to update your rules accordingly)\n    \u003e ```\n\n    If you are not as paranoid as me, and don't want to deny all outgoing traffic, you can allow it instead:\n\n    ``` bash\n    sudo ufw default allow outgoing comment 'allow all outgoing traffic'\n    ```\n\n1. Deny all incoming traffic:\n\n    ``` bash\n    sudo ufw default deny incoming comment 'deny all incoming traffic'\n    ```\n\n1. Obviously we want SSH connections in:\n\n    ``` bash\n    sudo ufw limit in ssh comment 'allow SSH connections in'\n    ```\n\n    \u003e ```\n    \u003e Rules updated\n    \u003e Rules updated (v6)\n    \u003e ```\n\n1. Allow additional traffic as per your needs. Some common use-cases:\n\n    ``` bash\n    # allow traffic out to port 53 -- DNS\n    sudo ufw allow out 53 comment 'allow DNS calls out'\n\t\n\t# allow traffic out to port 123 -- NTP\n    sudo ufw allow out 123 comment 'allow NTP out'\n\n    # allow traffic out for HTTP, HTTPS, or FTP\n    # apt might needs these depending on which sources you're using\n    sudo ufw allow out http comment 'allow HTTP traffic out'\n    sudo ufw allow out https comment 'allow HTTPS traffic out'\n    sudo ufw allow out ftp comment 'allow FTP traffic out'\n\n    # allow whois\n    sudo ufw allow out whois comment 'allow whois'\n    \n    # allow mails for status notifications -- choose port according to your provider\n    sudo ufw allow out 25 comment 'allow SMTP out'\n    sudo ufw allow out 587 comment 'allow SMTP out'\n\n    # allow traffic out to port 68 -- the DHCP client\n    # you only need this if you're using DHCP\n    sudo ufw allow out 67 comment 'allow the DHCP client to update'\n    sudo ufw allow out 68 comment 'allow the DHCP client to update'\n    ```\n    \n    **Note**: You'll need to allow HTTP/HTTPS for installing packages and many other things.\n\n1. Start ufw:\n\n    ``` bash\n    sudo ufw enable\n    ```\n\n    \u003e ```\n    \u003e Command may disrupt existing ssh connections. Proceed with operation (y|n)? y\n    \u003e Firewall is active and enabled on system startup\n    \u003e ```\n\n1. If you want to see a status:\n\n    ``` bash\n    sudo ufw status\n    ```\n\n    \u003e ```\n    \u003e Status: active\n    \u003e \n    \u003e To                         Action      From\n    \u003e --                         ------      ----\n    \u003e 22/tcp                     LIMIT       Anywhere                   # allow SSH connections in\n    \u003e 22/tcp (v6)                LIMIT       Anywhere (v6)              # allow SSH connections in\n    \u003e \n    \u003e 53                         ALLOW OUT   Anywhere                   # allow DNS calls out\n    \u003e 123                        ALLOW OUT   Anywhere                   # allow NTP out\n    \u003e 80/tcp                     ALLOW OUT   Anywhere                   # allow HTTP traffic out\n    \u003e 443/tcp                    ALLOW OUT   Anywhere                   # allow HTTPS traffic out\n    \u003e 21/tcp                     ALLOW OUT   Anywhere                   # allow FTP traffic out\n    \u003e Mail submission            ALLOW OUT   Anywhere                   # allow mail out\n    \u003e 43/tcp                     ALLOW OUT   Anywhere                   # allow whois\n    \u003e 53 (v6)                    ALLOW OUT   Anywhere (v6)              # allow DNS calls out\n    \u003e 123 (v6)                   ALLOW OUT   Anywhere (v6)              # allow NTP out\n    \u003e 80/tcp (v6)                ALLOW OUT   Anywhere (v6)              # allow HTTP traffic out\n    \u003e 443/tcp (v6)               ALLOW OUT   Anywhere (v6)              # allow HTTPS traffic out\n    \u003e 21/tcp (v6)                ALLOW OUT   Anywhere (v6)              # allow FTP traffic out\n    \u003e Mail submission (v6)       ALLOW OUT   Anywhere (v6)              # allow mail out\n    \u003e 43/tcp (v6)                ALLOW OUT   Anywhere (v6)              # allow whois\n    \u003e ```\n\n    or\n\n    ``` bash\n    sudo ufw status verbose\n    ```\n\n    \u003e ```\n    \u003e Status: active\n    \u003e Logging: on (low)\n    \u003e Default: deny (incoming), deny (outgoing), disabled (routed)\n    \u003e New profiles: skip\n    \u003e \n    \u003e To                         Action      From\n    \u003e --                         ------      ----\n    \u003e 22/tcp                     LIMIT IN    Anywhere                   # allow SSH connections in\n    \u003e 22/tcp (v6)                LIMIT IN    Anywhere (v6)              # allow SSH connections in\n    \u003e \n    \u003e 53                         ALLOW OUT   Anywhere                   # allow DNS calls out\n    \u003e 123                        ALLOW OUT   Anywhere                   # allow NTP out\n    \u003e 80/tcp                     ALLOW OUT   Anywhere                   # allow HTTP traffic out\n    \u003e 443/tcp                    ALLOW OUT   Anywhere                   # allow HTTPS traffic out\n    \u003e 21/tcp                     ALLOW OUT   Anywhere                   # allow FTP traffic out\n    \u003e 587/tcp (Mail submission)  ALLOW OUT   Anywhere                   # allow mail out\n    \u003e 43/tcp                     ALLOW OUT   Anywhere                   # allow whois\n    \u003e 53 (v6)                    ALLOW OUT   Anywhere (v6)              # allow DNS calls out\n    \u003e 123 (v6)                   ALLOW OUT   Anywhere (v6)              # allow NTP out\n    \u003e 80/tcp (v6)                ALLOW OUT   Anywhere (v6)              # allow HTTP traffic out\n    \u003e 443/tcp (v6)               ALLOW OUT   Anywhere (v6)              # allow HTTPS traffic out\n    \u003e 21/tcp (v6)                ALLOW OUT   Anywhere (v6)              # allow FTP traffic out\n    \u003e 587/tcp (Mail submission (v6)) ALLOW OUT   Anywhere (v6)              # allow mail out\n    \u003e 43/tcp (v6)                ALLOW OUT   Anywhere (v6)              # allow whois\n    \u003e ```\n\n7. If you need to delete a rule\n    \n    ``` bash\n    sudo ufw status numbered\n    [...]\n    sudo ufw delete 3 #line number of the rule you want to delete\n    ```\n\n#### Default Applications\n\nufw ships with some default applications. You can see them with:\n\n``` bash\nsudo ufw app list\n```\n\n\u003e ```\n\u003e Available applications:\n\u003e   AIM\n\u003e   Bonjour\n\u003e   CIFS\n\u003e   DNS\n\u003e   Deluge\n\u003e   IMAP\n\u003e   IMAPS\n\u003e   IPP\n\u003e   KTorrent\n\u003e   Kerberos Admin\n\u003e   Kerberos Full\n\u003e   Kerberos KDC\n\u003e   Kerberos Password\n\u003e   LDAP\n\u003e   LDAPS\n\u003e   LPD\n\u003e   MSN\n\u003e   MSN SSL\n\u003e   Mail submission\n\u003e   NFS\n\u003e   OpenSSH\n\u003e   POP3\n\u003e   POP3S\n\u003e   PeopleNearby\n\u003e   SMTP\n\u003e   SSH\n\u003e   Socks\n\u003e   Telnet\n\u003e   Transmission\n\u003e   Transparent Proxy\n\u003e   VNC\n\u003e   WWW\n\u003e   WWW Cache\n\u003e   WWW Full\n\u003e   WWW Secure\n\u003e   XMPP\n\u003e   Yahoo\n\u003e   qBittorrent\n\u003e   svnserve\n\u003e ```\n\nTo get details about the app, like which ports it includes, type:\n\n``` bash\nsudo ufw app info [app name]\n```\n\n\u003e ``` bash\n\u003e sudo ufw app info DNS\n\u003e ```\n\u003e \n\u003e ```\n\u003e Profile: DNS\n\u003e Title: Internet Domain Name Server\n\u003e Description: Internet Domain Name Server\n\u003e \n\u003e Port:\n\u003e   53\n\u003e ```\n\n#### Custom Application\n\nIf you don't want to create rules by explicitly providing the port number(s), you can create your own application configurations. To do this, create a file in `/etc/ufw/applications.d`.\n\nFor example, here is what you would use for [Plex](https://support.plex.tv/articles/201543147-what-network-ports-do-i-need-to-allow-through-my-firewall/):\n\n``` bash\ncat /etc/ufw/applications.d/plexmediaserver\n```\n\n\u003e ```\n\u003e [PlexMediaServer]\n\u003e title=Plex Media Server\n\u003e description=This opens up PlexMediaServer for http (32400), upnp, and autodiscovery.\n\u003e ports=32469/tcp|32413/udp|1900/udp|32400/tcp|32412/udp|32410/udp|32414/udp|32400/udp\n\u003e ```\n\nThen you can enable it like any other app:\n\n```bash\nsudo ufw allow plexmediaserver\n```\n\n([Table of Contents](#table-of-contents))\n\n### iptables Intrusion Detection And Prevention with PSAD\n\n#### Why\n\nEven if you have a firewall to guard your doors, it is possible to try brute-forcing your way in any of the guarded doors. We want to monitor all network activity to detect potential intrusion attempts, such has repeated attempts to get in, and block them.\n\n#### How It Works\n\nI can't explain it any better than user [FINESEC](https://serverfault.com/users/143961/finesec) from https://serverfault.com/ did at: https://serverfault.com/a/447604/289829.\n\n\u003e Fail2BAN scans log files of various applications such as apache, ssh or ftp and automatically bans IPs that show the malicious signs such as automated login attempts. PSAD on the other hand scans iptables and ip6tables log messages (typically /var/log/messages) to detect and optionally block scans and other types of suspect traffic such as DDoS or OS fingerprinting attempts. It's ok to use both programs at the same time because they operate on different level.\n\nAnd, since we're already using [UFW](#ufw-uncomplicated-firewall) so we'll follow the awesome instructions by [netson](https://gist.github.com/netson) at https://gist.github.com/netson/c45b2dc4e835761fbccc to make PSAD work with UFW.\n\n#### References\n\n- http://www.cipherdyne.org/psad/\n- http://www.cipherdyne.org/psad/docs/config.html\n- https://www.thefanclub.co.za/how-to/how-install-psad-intrusion-detection-ubuntu-1204-lts-server\n- https://serverfault.com/a/447604/289829\n- https://serverfault.com/a/770424/289829\n- https://gist.github.com/netson/c45b2dc4e835761fbccc\n- Thanks to [moltenbit](https://github.com/moltenbit) for catching the issue ([#61](https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/61)) with `psadwatchd`.\n\n#### Steps\n\n1. Install psad.\n\n    On Debian based systems:\n\n    ``` bash\n    sudo apt install psad\n    ```\n\n1. Make a backup of psad's configuration file `/etc/psad/psad.conf`:\n\n    ``` bash\n    sudo cp --archive /etc/psad/psad.conf /etc/psad/psad.conf-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n1. Review and update configuration options in `/etc/psad/psad.conf`. Pay special attention to these:\n\n   |Setting|Set To\n   |--|--|\n   |[`EMAIL_ADDRESSES`](http://www.cipherdyne.org/psad/docs/config.html#EMAIL_ADDRESSES)|your email address(s)|\n   |`HOSTNAME`|your server's hostname|\n   |`EXPECT_TCP_OPTIONS`|`EXPECT_TCP_OPTIONS Y;`|\n   |`ENABLE_PSADWATCHD`|`ENABLE_PSADWATCHD Y;`|\n   |[`ENABLE_AUTO_IDS`](http://www.cipherdyne.org/psad/docs/config.html#ENABLE_AUTO_IDS)|`ENABLE_AUTO_IDS Y;`|\n   |`ENABLE_AUTO_IDS_EMAILS`|`ENABLE_AUTO_IDS_EMAILS Y;`|\n\n   Check the configuration file psad's documentation at http://www.cipherdyne.org/psad/docs/config.html for more details.\n\n1. \u003ca name=\"psad_step4\"\u003e\u003c/a\u003eNow we need to make some changes to ufw so it works with psad by telling ufw to log all traffic so psad can analyze it. Do this by editing **two files** and adding these lines **at the end but before the COMMIT line**.\n\n    Make backups:\n\n    ``` bash\n    sudo cp --archive /etc/ufw/before.rules /etc/ufw/before.rules-COPY-$(date +\"%Y%m%d%H%M%S\")\n    sudo cp --archive /etc/ufw/before6.rules /etc/ufw/before6.rules-COPY-$(date +\"%Y%m%d%H%M%S\")\n    ```\n\n    Edit the files:\n\n    - `/etc/ufw/before.rules`\n    - `/etc/ufw/before6.rules`\n\n    And add add this **at the end but before the COMMIT line**:\n\n    ```\n    # log all traffic so psad can analyze\n    -A INPUT -j LOG --log-tcp-options --log-prefix \"[IPTABLES] \"\n    -A FORWARD -j LOG --log-tcp-options --log-prefix \"[IPTABLES] \"\n    ```\n\n    **Note**: We're adding a log prefix to all the iptables logs. We'll need this for [seperating iptables logs to their own file](#ns-separate-iptables-log-file).\n\n    For example:\n\n    \u003e ```\n    \u003e ...\n    \u003e \n    \u003e # log all traffic so psad can analyze\n    \u003e -A INPUT -j LOG --log-tcp-options --log-prefix \"[IPTABLES] \"\n    \u003e -A FORWARD -j LOG --log-tcp-options --log-prefix \"[IPTABLES] \"\n    \u003e \n    \u003e # don't delete the 'COMMIT' line or these rules won't be processed\n    \u003e COMMIT\n    \u003e ```\n\n1. Now we need to reload/restart ufw and psad for the changes to take effect:\n\n    ``` bash\n    sudo ufw reload\n\n    sudo psad -R\n    sudo psad --sig-update\n    sudo psad -H\n    ```\n\n1. Analyze iptables rules for errors:\n\n    ``` bash\n    sudo psad --fw-analyze\n    ```\n\n    \u003e ```\n    \u003e [+] Parsing INPUT chain rules.\n    \u003e [+] Parsing INPUT chain rules.\n    \u003e [+] Firewall config looks good.\n    \u003e [+] Completed check of firewall ruleset.\n    \u003e [+] Results in /var/log/psad/fw_check\n    \u003e [+] Exiting.\n    \u003e ```\n\n    **Note**: If there were any issues you will get an e-mail with the error.\n\n1. Check the status of psad:\n\n    ``` bash\n    sudo psad --Status\n    ```\n\n    \u003e ```\n    \u003e [-] psad: pid file /var/run/psad/psadwatchd.pid does not exist for psadwatchd on vm\n    \u003e [+] psad_fw_read (pid: 3444)  %CPU: 0.0  %MEM: 2.2\n    \u003e     Running since: Sat Feb 16 01:03:09 2019\n    \u003e \n    \u003e [+] psad (pid: 3435)  %CPU: 0.2  %MEM: 2.7\n    \u003e     Running since: Sat Feb 16 01:03:09 2019\n    \u003e     Command line arguments: [none specified]\n    \u003e     Alert email address(es): root@localhost\n    \u003e \n    \u003e [+] Version: psad v2.4.3\n    \u003e \n    \u003e [+] Top 50 signature matches:\n    \u003e         [NONE]\n    \u003e \n    \u003e [+] Top 25 attackers:\n    \u003e         [NONE]\n    \u003e \n    \u003e [+] Top 20 scanned ports:\n    \u003e         [NONE]\n    \u003e \n    \u003e [+] iptables log prefix counters:\n    \u003e         [NONE]\n    \u003e \n    \u003e     Total protocol packet counters:\n    \u003e \n    \u003e [+] IP Status Detail:\n    \u003e         [NONE]\n    \u003e \n    \u003e     Total scan sources: 0\n    \u003e     Total scan destinations: 0\n    \u003e \n    \u003e [+] These results are available in: /var/log/psad/status.out\n    \u003e ```\n\n([Table of Contents](#table-of-contents))\n\n### Application Intrusion Detection And Prevention With Fail2Ban\n\n#### Why\n\nUFW tells your server what doors to board up so nobody can see them, and what doors to allow authorized users through. PSAD monitors network activity to detect and prevent potential intrusions -- repeated attempts to get in. \n\nBut what about the applications/services your server is running, like SSH and Apache, where your firewall is configured to allow access in. Even though access may be allowed that doesn't mean all access attempts are valid and harmless. What if someone tries to brute-force their way in to a web-app you're running on your server? This is where Fail2ban comes in.\n\n#### How It Works\n\nFail2ban monitors the logs of your applications (like SSH and Apache) to detect and prevent potential intrusions. It will monitor network traffic/logs and prevent intrusions by blocking suspicious activity (e.g. multiple successive failed connections in a short time-span).\n\n#### Goals\n\n- network monitoring for suspicious activity with automatic banning of offending IPs\n\n#### Notes\n\n- As of right now, the only thing running on this server is SSH so we'll want Fail2ban to monitor SSH and ban as necessary.\n- As you install other programs, you'll need to create/configure the appropriate jails and enable them.\n\n#### References\n\n- https://www.fail2ban.org/\n- https://blog.vigilcode.com/2011/05/ufw-with-fail2ban-quick-secure-setup-part-ii/\n- https://dodwell.us/security/ufw-fail2ban-portscan.html\n- https://www.howtoforge.com/community/threads/fail2ban-and-ufw-on-debian.77261/\n\n#### Steps\n\n1. Install fail2ban.\n\n    On Debian based systems:\n\n    ``` bash\n    sudo apt install fail2ban\n    ```\n\n1. We don't want to edit `/etc/fail2ban/fail2ban.conf` or `/etc/fail2ban/jail.conf` because a future update may overwrite those so we'll create a local copy instead. Create the file `/etc/fail2ban/jail.local` and add this to it after replacing `[LAN SEGMENT]` and `[your email]` with the appropriate values:\n\n    ```\n    [DEFAULT]\n    # the IP address range we want to ignore\n    ignoreip = 127.0.0.1/8 [LAN SEGMENT]\n\n    # who to send e-mail to\n    destemail = [your e-mail]\n\n    # who is the email from\n    sender = [your e-mail]\n\n    # since we're using exim4 to send emails\n    mta = mail\n\n    # get email alerts\n    action = %(action_mwl)s\n    ```\n\n    **Note**: Your server will need to be able to send e-mails so Fail2ban can let you know of suspicious activity and when it banned an IP.\n\n1. We need to create a jail for SSH that tells fail2ban to look at SSH logs and use ufw to ban/unban IPs as needed. Create a jail for SSH by creating the file `/etc/fail2ban/jail.d/ssh.local` and adding this to it:\n\n    ```\n    [sshd]\n    enabled = true\n    banaction = ufw\n    port = ssh\n    filter = sshd\n    logpath = %(sshd_log)s\n    maxretry = 5\n    ```\n\n    [For the lazy](#editing-configuration-files---for-the-lazy):\n\n    ``` bash\n    cat \u003c\u003c EOF | sudo tee /etc/fail2ban/jail.d/ssh.local\n    [sshd]\n    enabled = true\n    banaction = ufw\n    port = ssh\n    filter = sshd\n    logpath = %(sshd_log)s\n    maxretry = 5\n    EOF\n    ```\n\n1. In the above we tell fail2ban to use the ufw as the `banaction`. Fail2ban ships with an action configuration file for ufw. You can see it in `/etc/fail2ban/action.d/ufw.conf`\n\n1. Enable fail2ban:\n\n    ``` bash\n    sudo fail2ban-client start\n    sudo fail2ban-client reload\n    sudo fail2ban-client add sshd # This may fail on some systems if the sshd jail was added by default\n    ```\n\n1. To check the status:\n\n    ``` bash\n    sudo fail2ban-client status\n    ```\n\n    \u003e ```\n    \u003e Status\n    \u003e |- Number of jail:      1\n    \u003e `- Jail list:   sshd\n    \u003e ```\n\n    ``` bash\n    sudo fail2ban-client status sshd\n    ```\n\n    \u003e ```\n    \u003e Status for the jail: sshd\n    \u003e |- Filter\n    \u003e |  |- Currently failed: 0\n    \u003e |  |- Total failed:     0\n    \u003e |  `- File list:        /var/log/auth.log\n    \u003e `- Actions\n    \u003e    |- Currently banned: 0\n    \u003e    |- Total banned:     0\n    \u003e    `- Banned IP list:\n    \u003e ```\n\n#### Custom Jails\n\nI have not needed to create a custom jail yet. Once I do, and I figure out how, I will update this guide. Or, if you know how please help [contribute](#contributing).\n\n#### Unban an IP\n\nTo unban an IP use this command:\n\n``` bash\nfail2ban-client set [jail] unbanip [IP]\n```\n\n`[jail]` is the name of the jail that has the banned IP and `[IP]` is the IP address you want to unban. For example, to unaban `192.168.1.100` from SSH you would do:\n\n``` bash\nfail2ban-client set sshd unbanip 192.168.1.100\n```\n\n([Table of Contents](#table-of-contents))\n\n### Application Intrusion Detection And Prevention With CrowdSec\n\n#### Why\n\nUFW tells your server what doors to board up so nobody can see them, and what doors to allow authorized users through. PSAD monitors network activity to detect and prevent potential intrusions -- repeated attempts to get in. \n\nCrowdSec is similar to Fail2Ban in that it monitors the logs of your applications (like SSH and Apache) to detect and prevent potential intrusions. However, CrowdSec is coupled with a community that shares threat intelligence back to CrowdSec to then distribute a Community Blocklist to all users.\n\n#### How It Works\n\nCrowdSec monitors the logs of your applications (like SSH and Apache) to detect and prevent potential intrusions. It will monitor network traffic/logs and prevent intrusions by blocking suspicious activity (e.g. multiple successive failed connections in a short time-span). Once a malicious IP is detected, it will be added to your local decision list and threat information is shared with CrowdSec to update the Community Blocklist on malicious IP addresses. Once an IP address hits a certain threshold of malicious activity, it will be automatically propogated to all other CrowdSec users to proactively block.\n\n#### Goals\n\n- network monitoring for suspicious activity with automatic banning of offending IPs\n\n#### Notes\n\n- As of right now, the only thing running on this server is SSH so we'll want CrowdSec to monitor SSH and ban as necessary.\n- As you install other programs, you'll need to install additional collections and configure the appropriate acquisitions.\n\n#### References\n\n- https://www.crowdsec.net/\n- [Read how CrowdSec curates the Community Blocklist](https://www.crowdsec.net/our-data)\n- [Read what threat intelligence is shared with CrowdSec](https://docs.crowdsec.net/docs/next/central_api/intro#signal-meta-data)\n- https://docs.crowdsec.net/\n\n#### Steps\n\n1. Install CrowdSec Security Engine. (IDS)\n\n    On any linux distro (including Debian based systems)\n    \n    Install the CrowdSec repository:\n    ``` bash\n    curl -s https://install.crowdsec.net | sudo sh\n    ```\n\n    Install the CrowdSec Security Engine:\n    ``` bash\n    sudo apt install crowdsec\n    ```\n\n\u003e [!TIP]\n\u003e if `curl | sh` is not your thing, you can find additional install methods [here](https://docs.crowdsec.net/u/getting_started/installation/linux).\n\nBy default whilst CrowdSec is installing the Security Engine it will auto-discover your installed applications and install the appropriate parsers and scenarios for them. Since we know most Linux servers are running ssh out of the box CrowdSec will automatically configured this for you.\n\n2. Install a Remediation Component. (IPS)\n\n    CrowdSec by itself is a detection engine, since in most modern infrastructures you may have an upstream firewall or WAF, CrowdSec will not block the IP addresses by itself. You can install a Remediation Component to block the IP addresses detected by CrowdSec.\n    ```bash\n    sudo apt install crowdsec-firewall-bouncer-iptables\n    ```\n\n\u003e [!TIP]\n\u003e If your installation of UFW is not using `iptables` as the backend, you can alternatively install `crowdsec-firewall-bouncer-nftables`. There is no difference in the installed binaries, only the configuration file is different.\n\nBy default whilst the Remediation Component is installing it will auto-configure the necessary settings to work with the Security Engine if deployed on the same host (and if the security engine is not within a container environment).\n\n3. Check detection and remediation is working as intended:\n\n    CrowdSec package comes with a CLI tool to check the status of the Security Engine and the Remediation Component.\n\n    ```bash\n    sudo cscli metrics\n    ```\n\n    ```bash\n    Acquisition Metrics:\n    ╭────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────╮\n    │ Source                 │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │\n    ├────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤\n    │ file:/var/log/auth.log │ 5          │ 4            │ 1              │ 10                     │ -                 │\n    │ file:/var/log/syslog   │ 30         │ -            │ 30             │ -                      │ -                 │\n    ╰────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯\n\n    Local API Decisions:\n    ╭────────────────────────────────────────────┬────────┬────────┬───────╮\n    │ Reason                                     │ Origin │ Action │ Count │\n    ├────────────────────────────────────────────┼────────┼────────┼───────┤\n    │ crowdsecurity/http-backdoors-attempts      │ CAPI   │ ban    │ 73    │\n    │ crowdsecurity/http-bad-user-agent          │ CAPI   │ ban    │ 4836  │\n    │ crowdsecurity/http-path-traversal-probing  │ CAPI   │ ban    │ 87    │\n    │ crowdsecurity/http-probing                 │ CAPI   │ ban    │ 2010  │\n    │ crowdsecurity/thinkphp-cve-2018-20062      │ CAPI   │ ban    │ 88    │\n    │ crowdsecurity/CVE-2019-18935               │ CAPI   │ ban    │ 7     │\n    │ crowdsecurity/CVE-2023-49103               │ CAPI   │ ban    │ 5     │\n    │ crowdsecurity/http-admin-interface-probing │ CAPI   │ ban    │ 91    │\n    │ ltsich/http-w00tw00t                       │ CAPI   │ ban    │ 3     │\n    │ crowdsecurity/apache_log4j2_cve-2021-44228 │ CAPI   │ ban    │ 18    │\n    │ crowdsecurity/nginx-req-limit-exceeded     │ CAPI   │ ban    │ 280   │\n    │ crowdsecurity/ssh-slow-bf                  │ CAPI   │ ban    │ 3412  │\n    │ crowdsecurity/spring4shell_cve-2022-22965  │ CAPI   │ ban    │ 1     │\n    │ crowdsecurity/ssh-cve-2024-6387            │ CAPI   │ ban    │ 24    │\n    │ crowdsecurity/CVE-2023-22515               │ CAPI   │ ban    │ 2     │\n    │ crowdsecurity/http-cve-2021-41773          │ CAPI   │ ban    │ 172   │\n    │ crowdsecurity/netgear_rce                  │ CAPI   │ ban    │ 14    │\n    │ crowdsecurity/ssh-bf                       │ CAPI   │ ban    │ 2000  │\n    │ crowdsecurity/CVE-2022-35914               │ CAPI   │ ban    │ 1     │\n    │ crowdsecurity/http-cve-2021-42013          │ CAPI   │ ban    │ 2     │\n    │ crowdsecurity/jira_cve-2021-26086          │ CAPI   │ ban    │ 9     │\n    │ crowdsecurity/http-sensitive-files         │ CAPI   │ ban    │ 166   │\n    │ crowdsecurity/http-wordpress-scan          │ CAPI   │ ban    │ 272   │\n    │ crowdsecurity/CVE-2022-26134               │ CAPI   │ ban    │ 5     │\n    │ crowdsecurity/http-generic-bf              │ CAPI   │ ban    │ 7     │\n    │ crowdsecurity/http-open-proxy              │ CAPI   │ ban    │ 948   │\n    │ crowdsecurity/http-crawl-non_statics       │ CAPI   │ ban    │ 339   │\n    │ crowdsecurity/http-cve-probing             │ CAPI   │ ban    │ 5     │\n    │ crowdsecurity/CVE-2017-9841                │ CAPI   │ ban    │ 117   │\n    │ crowdsecurity/CVE-2022-37042               │ CAPI   │ ban    │ 1     │\n    │ crowdsecurity/fortinet-cve-2018-13379      │ CAPI   │ ban    │ 5     │\n    ╰────────────────────────────────────────────┴────────┴────────┴───────╯\n\n    Local API Metrics:\n    ╭──────────────────────┬────────┬──────╮\n    │ Route                │ Method │ Hits │\n    ├──────────────────────┼────────┼──────┤\n    │ /v1/alerts           │ GET    │ 2    │\n    │ /v1/decisions/stream │ GET    │ 5    │\n    │ /v1/usage-metrics    │ POST   │ 2    │\n    │ /v1/watchers/login   │ POST   │ 4    │\n    ╰──────────────────────┴────────┴──────╯\n\n    Local API Bouncers Metrics:\n    ╭────────────────────────────────┬──────────────────────┬────────┬──────╮\n    │ Bouncer                        │ Route                │ Method │ Hits │\n    ├────────────────────────────────┼──────────────────────┼────────┼──────┤\n    │ cs-f","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimthenachoman%2FHow-To-Secure-A-Linux-Server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimthenachoman%2FHow-To-Secure-A-Linux-Server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimthenachoman%2FHow-To-Secure-A-Linux-Server/lists"}