{"id":23803531,"url":"https://github.com/d3cod3/raspbian-server","last_synced_at":"2025-11-11T14:32:23.585Z","repository":{"id":149329791,"uuid":"80621003","full_name":"d3cod3/raspbian-server","owner":"d3cod3","description":"Let's build a server at home with a RaspberryPI","archived":false,"fork":false,"pushed_at":"2025-01-19T19:15:39.000Z","size":112,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-19T20:24:28.757Z","etag":null,"topics":["raspbian-server","raspbian-ua-netinst","security","web-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":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/d3cod3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2017-02-01T13:11:17.000Z","updated_at":"2025-01-19T19:15:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"ec194b2b-f8a5-4661-bca3-3ab8ee442f4f","html_url":"https://github.com/d3cod3/raspbian-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/d3cod3%2Fraspbian-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d3cod3%2Fraspbian-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d3cod3%2Fraspbian-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d3cod3%2Fraspbian-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/d3cod3","download_url":"https://codeload.github.com/d3cod3/raspbian-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240054101,"owners_count":19740766,"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":["raspbian-server","raspbian-ua-netinst","security","web-server"],"created_at":"2025-01-01T22:32:15.224Z","updated_at":"2025-11-11T14:32:23.457Z","avatar_url":"https://github.com/d3cod3.png","language":null,"readme":"\n# Raspbian Secure Server Config Tutorial (R.S.S.C.T)\n\n\nTable of Contents\n=================\n\n   * [Description](#description)\n   * [Install](#install)\n   * [Post-Install Config](#post-install-config)\n   * [Configuration](#configuration)\n      * [Users](#users)\n         * [SSH](#ssh)\n         * [Fail2ban (Special Section)](#fail2ban-special-section)\n      * [Net](#net)\n      * [DNS](#dns)\n      * [Services](#services)\n         * [SFTP](#sftp)\n         * [Apache](#apache)\n         * [MySQL Server](#mysql-server)\n         * [PHP](#php)\n         * [Ruby on Rails with rbenv (EXTRA BONUS - INTERMEDIATE LEVEL!!!)](#ruby-on-rails-with-rbenv-extra-bonus---intermediate-level)\n      * [Hide](#hide)\n         * [Port Knock](#port-knock)\n      * [Security](#security)\n         * [RKHunter](#rkhunter)\n         * [psad Network Intrusion Detection System](#psad-network-intrusion-detection-system)\n         * [Tripwire Intrusion Detection System](#tripwire-intrusion-detection-system)\n         * [Logwatch Log Analyzer](#logwatch-log-analyzer)\n         * [TLS/SSL](#tlsssl)\n      * [HARDENING (BONUS)](#hardening-bonus)\n    * [HOME ROUTER SETTINGS](#home-router-settings)\n    * [Your 80€ dedicated server (80DS)](#your-80-dedicated-server-80ds)\n\n\n\n# Description\n\nLet's build a server at home with a RaspberryPI, a minimal optimized [Raspbian](https://www.raspbian.org/) OS, configure it, secure it, hide it, test it and of course, enjoy it!\n\nThis tutorial is for Raspberry Pi Model 1B, 1B+ and 2B, a minimal microSD card of 8GB (i'm using a 95mb/s 64GB) and the standard RPi 1GB of RAM memory\n\n_For RPi Model 3 or RPi zero, check the [alpha branch v1.1.x of raspbian-ua-netinst](https://github.com/debian-pi/raspbian-ua-netinst/tree/v1.1.x), but beware, some stuff from this tutorial will be probably different, and you'll be able to solve things only with a lot of passion and enthusiasm._\n\nHere follow the detailed process of building the server, let's make coffee and get to it!\n\n\n# Install\n\nFirst of all, we want to start with a minimal version of Raspbian, something similar to the [netinst version of Debian](https://www.debian.org/CD/netinst/), so i searched the web (not googleed, i prefer to use [DuckDuckGo](https://duckduckgo.com/) because they do not track you, or at least it seems so) and i find a great contribution from [debian-pi](https://github.com/debian-pi) github user, the [raspbian-ua-netinst](https://github.com/debian-pi/raspbian-ua-netinst) repo, a Raspbian (minimal) unattended netinstaller!\n\nAmazing!\n\nSo, follow the repo instructions, download the last release installer and flash the SD card. Easy.\nThe second step is to put the flashed SD card in your RPi, power on and wait, the installer will boot your RPi, connect to the internet (you need to connect the RPi with an ethernet cable), downloading the latest version of Raspbian, and installing it. Depending on your internet connection speed you will have to go for another coffee, or not.\n\nWhen this step is finished you will have a minimal Raspbian system with ssh enabled by default, the root account with password: raspbian, and all the necessary basic command line tools. (you can check the details in the [raspbian-ua-netinst](https://github.com/debian-pi/raspbian-ua-netinst) repo)\n\nIf everything went ok, now you can ssh into your RPi with {user : root, password: raspbian}:\n\n```bash\nssh root@RPI_ip_number\n```\n\nLet's print some system info, first the running kernel version:\n\n```bash\ncat /proc/version\n```\nmy output:\n\n```bash\nLinux version 4.4.0-1-rpi2 (debian-kernel@lists.debian.org) (gcc version 4.9.2 (Raspbian 4.9.2-10) ) #1 SMP Debian 4.4.6-1+rpi14 (2016-05-05)\n```\nThe Linux distribution and version:\n\n```bash\ncat /etc/*release*\n```\n\nmy output:\n\n```bash\nPRETTY_NAME=\"Raspbian GNU/Linux 8 (jessie)\"\nNAME=\"Raspbian GNU/Linux\"\nVERSION_ID=\"8\"\nVERSION=\"8 (jessie)\"\nID=raspbian\nID_LIKE=debian\nHOME_URL=\"http://www.raspbian.org/\"\nSUPPORT_URL=\"http://www.raspbian.org/RaspbianForums\"\nBUG_REPORT_URL=\"http://www.raspbian.org/RaspbianBugs\"\n```\n\nThe block devices:\n\n```bash\nlsblk\n```\nmy output (with 64GB SD card):\n\n```bash\nNAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT\nmmcblk0     179:0    0  59.5G  0 disk\n├─mmcblk0p1 179:1    0 122.1M  0 part /boot\n└─mmcblk0p2 179:2    0  59.4G  0 part /\n```\n\nor more human readable:\n\n```bash\ndf -h --output=source,fstype,size,pcent,target -x tmpfs -x devtmpfs\n```\n\nThis is just the beginning! In the next session we'll make a little post-install configuration, just the suggestions from [raspbian-ua-netinst](https://github.com/debian-pi/raspbian-ua-netinst) repo, next story, \"Post-Install Config\".\n\n# Post-Install Config\n\n1 - Set new root password:\n\n```bash\npasswd\n```\n\n2 - Configure your default locale\n\n```bash\ndpkg-reconfigure locales\n```\n\n3 - Configure your timezone\n\n```bash\ndpkg-reconfigure tzdata\n```\n\n4 - Improve memory management performance\n\n```bash\napt-get install raspi-copies-and-fills\n```\n\n5 - Install and auto-load and use the kernel module for the hardware random number generator. This improves the performance of various server applications needing random numbers significantly.\n\n```bash\napt-get install rng-tools\n```\n\n6 - Create a 1GB SWAP file, and enable it on boot modifing fstab file:\n\n```bash\ndd if=/dev/zero of=/swap bs=1M count=1024 \u0026\u0026 mkswap /swap \u0026\u0026 chmod 600 /swap\necho \"/swap none swap sw 0 0\" | tee -a /etc/fstab\n```\n\nOk, we have our basic Raspbian server post installation!\n\nI'm curious at this moment about things like [Attack Surface](https://en.wikipedia.org/wiki/Attack_surface), let's print some information:\n\n```bash\nfind / -perm -4000 -print\n```\n\nThis command will list potential 'vulnerable' system points, listing all executable files with [SUID](https://en.wikipedia.org/wiki/Setuid) . My output:\n\n```bash\n/bin/mount\n/bin/umount\n/bin/su\n```\n\nbasically SUID flag allow a user to run an executable with the permissions of the executable owner, so if someone finds a vulnerability in one of this programs and exploits it, GAME OVER, he/she will have root permissions on the system, goodbye Raspbian Secure Server!!!\n\nBut don't worry, we are just getting started, a long journey awaits us, with so much to learn.\n\nLet's install and configure all the essentials for our Raspbian Secure Server, next story, \"Configuration\".\n\n# Configuration\n\nFirst of all, install some package downloader utils:\n\n```bash\napt-get install apt-utils\n```\n\nWe will need to get comfortable with edit a lot of text files, maybe some programming too :P, so we begin installing our favorite console text editor, i'm going to use \"nano\", but there are better options like \"vim\", choose here whatever suits you:\n\n```bash\napt-get install nano\n```\n\nAnd customize it by adding line numbering:\n\n```bash\nnano /etc/nanorc\n```\n\nUncomment # set const to add line numbering:\n\n```bash\n# set const\nset const\n```\n\n## Users\n\nFirst of all, we need to install **sudo**, a program designed normal users to execute some commands as root, and why is that? Because it's safer than always opening root sessions, nobody will need to know the root password, every execution will be logged and so on with a few more security related reasons.\n\n```bash\napt-get install sudo\n```\n\nCreate a new user with regular account privileges (change \"user\" with your username of choice):\n\n```bash\nadduser user\n```\n\nFollow instructions, fill all the fields you want, and most important, enter a strong password.\n\nNow we need to add the new user to the sudo group, in order to grant sudo capabilities:\n\n```bash\nadduser user sudo\n```\n\nMy output:\n\n```bash\nAdding user 'user' to group 'sudo'\nAdding user user to group sudo\nDone.\n```\n\nIn order to apply the new group assign log out and log in again.\n\nNext story, SSH\n\n### SSH\n\nCreate a new SSH Key Pair for securing the server with a public key authentication for the new user:\n\n1 - **On your local machine**, generate a key pair:\n\n```bash\nssh-keygen -t rsa -b 4096 -C \"raspbian_rsa\"\n```\n\nChoose the name of the key (Ex. myKey) files and set a password\nThis generates a private key \"myKey\" and a public key \"myKey.pub\", in the .ssh directory of the localuser's home directory. Remember that the private key should not be shared with anyone who should not have access to your servers!\n\n2 - **On your local machine**, copy the public key to our server:\n\n```bash\nssh-copy-id -i myKey.pub user@RPI_ip_number\n```\n\nThat's it, now we may SSH login to our server using the private key as authentication, so the time has come for configuring our SSH daemon for better security\n\nLet's open the SSH configuration file:\n\n```bash\nnano /etc/ssh/sshd_config\n```\n\nAnd change:\n\n0 - Disable ipv6\n\n```bash\n#ListenAddress ::\nListenAddress 0.0.0.0\n```\n\n1 - Disallow SSH access to root account\n\n```bash\nPermitRootLogin no\n```\n\n2 - Disable X11Forwarding:\n\n```bash\nX11Forwarding no\n```\n\n3 - Add AllowUsers user, in order to enable access for your new user ONLY:\n\n```bash\nAllowUsers user\n```\n\n4 - Disable tunneled cleartext password authentication and enable SSH public key only access\n\n```bash\nPasswordAuthentication no\nPubkeyAuthentication yes\nAuthorizedKeysFile      %h/.ssh/authorized_keys\n```\n\n5 - Save the file (ctrl o), close it (ctrl x) and restart the ssh service:\n\n```bash\n/etc/init.d ssh restart\n```\n\n6 - **On your local machine**, Log out and ssh login to check, now with your generated ssh key, normal cleartext password is now disabled.\n\n```bash\nssh -i ~/.ssh/your_rsa_key_name -p 22 username@RPi_ip_number\n```\n\nFor the most curious, -i specify the identity_file (your private key from the key pair), and -p specify the port where to connect (22 is the standard ssh port).\n\n7 - For more info about securing services, take a look at the [debian manual](https://www.debian.org/doc/manuals/securing-debian-howto/ch-sec-services.en.html)\n\nNow let's harden our SSH for protection against [brute force attacks](https://en.wikipedia.org/wiki/Brute-force_attack), installing **fail2ban**\n\n### Fail2ban (Special Section)\n\nfail2ban provides a way to automatically protect virtual servers from malicious behavior. The program works by scanning through log files and reacting to offending actions such as repeated failed login attempts.\n\n```bash\napt-get install fail2ban\n```\n\nNow make a local copy of the configuration file:\n\n```bash\ncp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local\n```\n\nAnd go on configuring it (the elegant stuff):\n\n```bash\nnano /etc/fail2ban/jail.local\n```\n\nWe start with the [DEFAULT] section, edit this lines:\n\n```bash\nignoreip = 127.0.0.1/8 192.168.1.0/24\nbantime  = 3600\nmaxretry = 3\n```\n\nThis will whitelist the local direction (127.0.0.1/8) and the local net (192.168.1.0/24), and ban a malicious ip after 3 wrong login intents, for 1 hour (3600 seconds).\n\nNow to the [JAILS] section, under ssh you'll see:\n\n```bash\nenabled  = true\nport     = ssh\nfilter   = sshd\nlogpath  = /var/log/auth.log\nmaxretry = 6\n```\n\nThis are the specific settings for SSH service, we don't need to change it, but in case you change the standard port for ssh (22) to another, you'll need to set it up:\n\n```bash\nport     = 33000 # for example\n```\n\nPerfect, we have it, save the file, close it and restart fail2ban:\n\n```bash\n/etc/init.d/fail2ban restart\n```\n\nOk, user configuration and SSH login secured and tested, if everything is working correctly, next story, \"Net\".\n\n## Net\n\nSo, basically, at this stage we want to connect our Raspbian Server at our local network via ethernet cable and ssh into it to continue installing and configuring stuff, and probably we are not going to do that always at the same place, sometimes we will working on that from home, and maybe sometimes we are going to work from a friend house, or a co-working somewhere, or whatever.\nThe point is, we don't want to check every time the IP number of our RPi, we don't want to have DHCP (default) assign a new IP every time we connect our RPi to a new router, so we disable DHCP and assign a static IP. That means, our Raspbian Server, locally, will always have the IP we choose. This is really trivial, so let's do it.\n\n1 - Open the file /etc/network/interfaces\n\n```bash\nnano /etc/network/interfaces\n```\n\n2 - You'll see a line like this:\n\n```bash\niface eth0 inet dhcp\n```\n\nThis is the default configuration for eth0, the RPi standard ethernet device, with DHCP enabled. [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) is a protocol commonly used by the vast majority of routers to dynamically assign a free IP to the connected device. It's really the easy choice, but we don't want that here (not because of the \"easy\" part), we just want our RPi to have always the same IP number (static).\n\n3 - So we comment the default DHCP config line and we add a static IP:\n\n```bash\n#iface eth0 inet dhcp\niface eth0 inet static\n  address your.static.ip.number # Ex. 192.168.1.59\n  gateway your.router.ip.number # Ex. 192.168.1.1\n  netmask 255.255.255.0\n```\n\nThe address and netmask goes accordingly with your router configuration, but the above example is really common\n\n4 - Save the file and close it\n\nWe have it! Try rebooting your RPi and check for the eth0 assigned IP:\n\n```bash\nifconfig eth0 | grep inet\n```\n\nIf everything is correct, your output will show the IP and netmask you configured in the /etc/network/interfaces file\n\nOk, so pack your RPi with an ethernet cable, and stuff it in your bag, now we will be able to work at our server at any place with a router; we connect the RPi, start it up, and from another computer connected to the same router we ssh to our server, great!\n\nLet's take a look now at a really useful tool for when we are working with network stuff, [netstat](https://www.lifewire.com/netstat-linux-command-4095695)\n\n```bash\nnetstat -apt\n```\n\nThis will output all(listening and established) active tcp connections, my output:\n\n```bash\nActive Internet connections (servers and established)\nProto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name\ntcp        0      0 RPi.static.ip:22        *:*                     LISTEN      294/sshd        \ntcp        0      0 RPi.static.ip:22        client.ip.number:22     ESTABLISHED 388/sshd: username\n```\n\nEverything seems ok, we have our SSH daemon listening at port 22 and our active ssh connection established.\nPort 22 is the standard port for SSH, and what are the standard port numbers for other services? To answer that, the best thing we can do is to take a look at the list of common standard ports in a server.\n\nSuper easy, just take a look at the /etc/services file:\n\n```bash\ncat /etc/services\n```\n\nSo services and ports, and netstat, we will use this tool a lot, so check it out and get comfortable with it ;\n\nOk, we'll hit pause right here, it's the update/dist-upgrade moment, we'll repeat this step a number of times over the entire server configuration:\n\n```bash\napt-get update \u0026\u0026 apt-get dist-upgrade\n```\n\nTo obtain all the updates for our current raspbian system, and:\n\n```bash\napt-get clean\n```\n\nTo clean disk space removing temporary updates installation files.\n\nIn one line:\n\n```bash\napt-get update \u0026\u0026 apt-get dist-upgrade -y \u0026\u0026 apt-get clean\n```\n\nSo far so good, we have now a decent secure access door to our Raspbian server, we can now start installing and configure all our services, more or less depending on what we'll need from our server, but this is the next chapter so, see you in a bit.\n\n## DNS\n\nBefore continuing with our installs and configs, we need to tell the system where to ask for ip \u003c--\u003e domain names associations, and for that we need to use what is called Domain Name System Server (DNS server), basically we need to pass the system the ip of one or varios DNS servers so it will be able to get the ip of a domain or viceversa.\n\nWe'll use the standard [OpenDNS](https://www.opendns.com) servers here, but feel free to use whatever you like more.\n\nSo, edit the /etv/resolv.conf file:\n\n```bash\nnano /etc/resolv.conf\n```\n\nAnd add your DNS servers ip, in case of using OpenDNS's:\n\n```bash\nnameserver 208.67.222.222\nnameserver 208.67.220.220\n```\n\nSave the file, close it and reboot. DONE!\n\n## Services\n\nFrom [wikipedia](https://en.wikipedia.org/wiki/Server_(computing)): \"Servers can provide various functionalities, often called 'services',  such as sharing data or resources among multiple clients, or performing computation for a client.\"\n\n![CERN First WWW Server](https://upload.wikimedia.org/wikipedia/commons/2/2c/First-server-cern-computer-center.jpg)\n**The first HTTP web server of the history, year 1990 (from CERN, where they actually invented the web!)**\n\nWhy are we building a server? This is what you need to ask yourself just now! Because depending on what the answer will be, the content of this chapter will eventually change a lot, but anyway, we'll tray to stay cool and cover at least all the basic services, and maybe something more, but enough with the chatting, let's get to it.\nThere is no better or specific order to install services, in general at least, so i will use mine but you feel free to change it, and of course contributions are welcome and really appreciated.\n\n### SFTP\n\nSo, we'll start with implementing a SFTP service with a Chroot'ed Isolated File Directory, WHAAAAAAAAT?\n\nWell, yes, it's not double click on the icon :P, but we are trying to be pro here, and the tutorial title say \"Secure Server Config...\" so, but don't worry, we'll crack it step by step.\n\n**Step 1**, what is SFTP? From [digitalocean](https://www.digitalocean.com/community/tutorials/how-to-use-sftp-to-securely-transfer-files-with-a-remote-server) : \"it stands for SSH File Transfer Protocol, or Secure File Transfer Protocol, is a separate protocol packaged with SSH that works in a similar way over a secure connection. The advantage is the ability to leverage a secure connection to transfer files and traverse the filesystem on both the local and remote system.\"\n\n**Step 2**, what in the hell means chroot'ed? From [wikipedia](https://en.wikipedia.org/wiki/Chroot) : \"A chroot on Unix operating systems is an operation that changes the apparent root directory for the current running process and its children. A program that is run in such a modified environment cannot name (and therefore normally cannot access) files outside the designated directory tree. The term \"chroot\" may refer to the chroot(2) system call or the chroot(8) wrapper program. The modified environment is called a chroot jail.\"\n\n**Step 3**, in short, let's implement a secure difficult hackable file transfer protocol service for our Rasbian Server, yheaaaaaa! With this service we will be able to safe connect with our server and upload files, including let someone else access to our server to upload/download files, but in a chroot jail environment, like a bubble with no exits, a chroot environment is the only observable universe, so the rest of the system where we don't want anyone peeking or worse (see [Directory traversal attack](https://en.wikipedia.org/wiki/Directory_traversal_attack)), will not exists.\n\n**Step 4**, install OpenSSH server software\n\n```bash\napt-get install openssh-server\n```\n\n**Step 5**, create a users group for sftp access and a specific user, this is a good practice for every kind of services, create specific groups for every service in order to limit access, if i will connect via sftp, i will have access to ONLY that.\n\n```bash\ngroupadd sftpgroup\n```\n\n```bash\ncat /etc/group\n```\n\nTake note here of the id related with the newly created group, in my case is 1001:\n\n```bash\nsftpgroup:x:1001:\n```\n\nAdd now a new user that we will use exclusively for SFTP access (change 1001 with your group id, and choose your user name):\n\n```bash\nsudo useradd [user name] -d /home/[user name] -g 1001 -N -o -u 1001\nsudo passwd [user name]\n```\n\n* **-d** is the user home directory which needs to be set to /home/[user name].\n* **-g** is the user group id to assign which in our example needs to be assigned to sftpgroup.\n* **-N** useradd by default creates a group with the same name as the new user, this disables that.\n* **-u** is the user id, which in our case needs to be the same id value as sftpgroup.\n* **-o** allows duplicate, non-unique user ids.\n* The **passwd** command sets an encrypted user password.\n\nNow output the system users list to check that everything went fine:\n\n```bash\ncat /etc/passwd\n```\n\nIn the last line we'll see the new added user\n\n```bash\nsftpuser:x:1001:1001::/home/sftpuser:/bin/sh\n```\n\nNow, before configuring the SSH daemon, we need to create a new keypair for this new user, in my case sftpuser, we did it before for the regular ssh connecting user (NET chapter?), so here a little refresh:\n\n1 - Generate the new keypair on your client machine:\n\n```bash\nssh-keygen -t rsa -b 4096 -C \"raspbian_sftp_key\"\n```\n\n2 - Copy the public key to the server:\n\n```bash\nssh-copy-id -i myKey.pub sftpuser@RPI_ip_number\n```\n\n3 - That's it, exit from actual ssh session and try to log in with the new sftpuser just for testing.\n\n**Step 6**, we need now to edit the SSH daemon configuration file, the same one we edited for SSH connection some while ago, remember? Let's do it:\n\n```bash\nnano /etc/ssh/sshd_config\n```\n\nSearch for the line\n\n```bash\nSubsystem sftp /usr/lib/openssh/sftp-server\n```\n\nAnd change it to\n\n```bash\n#Subsystem sftp /usr/lib/openssh/sftp-server\nSubsystem sftp internal-sftp\n```\n\nNow the cool part, go to the end of the document and add the following block:\n\n```bash\nMatch group sftpgroup\nChrootDirectory /var/www\nX11Forwarding no\nAllowTcpForwarding no\nForceCommand internal-sftp\n```\n\nAnd the last really important one, add the new user **sftpuser** to the AllowUsers line:\n\n```bash\nAllowUsers user sftpuser\n```\n\nAnd this is the part where we confine the sftpgroup users group to the /var/www directory (they will not be able to escape from there, or at least they will have to sweat it).\nWe use /var/www because is the standard directory for web servers, but feel free to choose another folder if you prefer, like /var/sftp for example.\nThis step is really important, if you forget to configure the ChrootDirectory for the specific users group, a connected user could gain access to the / (the server root) and we do not actually want that!!!\n\nSo, save the document and\n\n**Step 7**, create the /var/www folder, if you don't have it already:\n\n```bash\nmkdir /var/www\n```\n\n**Step 8**, create some testing folder, a read-only one, a read/write one and a no-access one:\n\n```bash\ncd /var/www\nmkdir test_readonly\nmkdir test_readwrite\nmkdir test_noaccess\n```\n\nAt this moment the three folders have the same permissions, let's explain a bit:\n\n```bash\nls -la\n```\n\nGive me (we are inside /var/www):\n\n```bash\ndrwxr-xr-x  5 root root 4096 Mar 26 05:41 .\ndrwxr-xr-x 12 root root 4096 Mar 26 05:37 ..\ndrwxr-xr-x  2 root root 4096 Mar 26 05:41 test_noaccess\ndrwxr-xr-x  2 root root 4096 Mar 26 05:40 test_readonly\ndrwxr-xr-x  2 root root 4096 Mar 26 05:41 test_readwrite\n```\n\nWe see here a list of the folder content, just the three folders we just created, and on the left we have the permission mode:\n\ndrwxr-xr-x\n\nLet's break it in parts:\n\nd   \n\nFor now we will focus on the last three blocks:\n\nrwx   r-x   r-x\n\nThe first one on the left represent the root permissions, the second one in the center represent the group permissions, and the third one on the right represent permissions for everyone else, and we can read it this way:\n\nr w x  --\u003e  2^2 2^1 2^0  --\u003e  4  2  1\n\nAnd in bits we can read it:\n\nr w x --\u003e 1 1 1\n\nr - x --\u003e 1 0 1\n\nAnd so on\n\nSo we have some possibilities, but not so much in the end:\n\n* 0 - No permissions\n* 1 - execute permission\n* 2 - write permission\n* 3 - execute+write permissions\n* 4 - read permission\n* 5 - execute+read permissions\n* 6 - read+write permissions\n* 7 - execute+read+write permissions\n\nMore about Linux permissions [here](http://en.wikipedia.org/wiki/File_system_permissions#Symbolic_notation)\n\nSo, coming back to our list:\n\n```bash\ndrwxr-xr-x  5 root root 4096 Mar 26 05:41 .\ndrwxr-xr-x 12 root root 4096 Mar 26 05:37 ..\ndrwxr-xr-x  2 root root 4096 Mar 26 05:41 test_noaccess\ndrwxr-xr-x  2 root root 4096 Mar 26 05:40 test_readonly\ndrwxr-xr-x  2 root root 4096 Mar 26 05:41 test_readwrite\n```\n\nWe have now all the folders with 755 permissions (rwx r-x r-x), and this is ok for the test_readonly one, but we need to change the permissions for the other two:\n\n```bash\nchown root:sftpgroup test_readwrite\nchmod 775 test_readwrite\n```\n\nWith that we assign root as owner of the folder and sftpgroup as folder group, and with 775 permissions we grant full permission to owner, full permissions to assigned group, and execute+read permission to everyone else.\n\nSo for the noaccess folder we set permissions to 711, execute only for group and everyone else:\n\n```bash\nchmod 711 test_noaccess\n```\n\nAnd our list again:\n\n```bash\ndrwxr-xr-x  5 root root      4096 Mar 26 05:41 .\ndrwxr-xr-x 12 root root      4096 Mar 26 05:37 ..\ndrwx--x--x  2 root root      4096 Mar 26 05:41 test_noaccess\ndrwxr-xr-x  2 root root      4096 Mar 26 05:40 test_readonly\ndrwxrwxr-x  2 root sftpgroup 4096 Mar 26 05:41 test_readwrite\n```\n\n**Step 9**, test it! We are done, restart the SSH server:\n\n```bash\n/etc/init.d/ssh restart\n```\n\n**Step 10**, connect to our SFTP server from a client, i'm using [FileZilla](https://filezilla-project.org/):\n\nCreate a new connection, with the server ip of your Raspbian server, port 22, SFTP protocol, and Key file as access type, set the name of the user, \"sftpuser\" in my case, and set the path to the private key from the key pair we recently create in step 5.\n\nSo, if everything was correct, we are now able to navigate our /var/www server folder from a filezilla client, great!\n\nNext story, Apache web server install...\n\n### Apache\n\nA web server, this sounds like troubles! Well, it's not untrue, but here we go, let's take a step back and talk about something indispensable, the firewall, and prepare yourself, we' wi'll come back to this topic a lot, while installing all our server stuff.\nA server without a good firewall set up is like a safe without a door, right now it will probably not last till the end of the day. So let's learn something about linux firewalls!\n\nThe standard debian firewall is called iptables (for IPv4, and ip6tables for IPv6) , so we'll using that, first step install it:\n\n```bash\napt-get install iptables iptables-persistent\n```\n\nThe package iptables-persistent is used to make our firewall rules persistent over reboots.\n\nOk, now print the current iptable rules, none right now:\n\n```bash\niptables -L\n```\n\nMy output:\n\n```bash\nChain INPUT (policy ACCEPT)\ntarget     prot opt source               destination\n\nChain FORWARD (policy ACCEPT)\ntarget     prot opt source               destination\n\nChain OUTPUT (policy ACCEPT)\ntarget     prot opt source               destination\n```\n\nAnd a useful command to flush all rules (like a firewall reset):\n\n```bash\niptables -F\n```\n\nNow, we don't want to be lock out from our server, and playing with the firewall can lock us out really easy, so first of all we add a rule that assure us to maintain untouched all current connections (basically our actual ssh connection):\n\n```bash\niptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n```\n\nIn english, we tell to iptables to **-A** append the rule, **INPUT** to the input chain, **-m conntrack --ctstate ESTABLISHED,RELATED** relate this rule with the current connections ONLY, **-j ACCEPT** JUMP to accept and the connection are still in place.\n\nIf we list our rules again:\n\n```bash\niptables -L\n```\n\nWe'll see something new, the \"door\" opened for incoming current connections (our SSH connection), amazing!\n\nNow we start to design our firewall, starting with the basics for what we already have now (SSH, SFTP and soon Apache web server), along the way we will come back and add some new rules for all the other stuff we will need on our server. Maybe it's a good idea to make yourself a new cup of coffee, or whatever you like to drink.\n\nLet's start blocking off insecure connections, we actually are using port 22 for SSH and SFTP, and we'll want to have port 80 (http) and port 443 (https) available:\n\n```bash\niptables -A INPUT -p tcp --dport 22 -j ACCEPT\n```\n\n```bash\niptables -A INPUT -p tcp --dport 80 -j ACCEPT\n```\n\n```bash\niptables -A INPUT -p tcp --dport 443 -j ACCEPT\n```\n\nNow block all the remaining traffic:\n\n```bash\niptables -P INPUT DROP\n```\n\nAllow loopback access (**-I INPUT 1** place this rule first in the list, IMPORTANT):\n\n```bash\niptables -I INPUT 1 -i lo -j ACCEPT\n```\n\nAnd do not forget to permit outgoing connections (for apt-get, web browsing, sendmail, etc..)\n\n```bash\niptables -F OUTPUT  # remove your existing OUTPUT rules if you have some\niptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT\niptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT\niptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT\niptables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT\niptables -A OUTPUT -p tcp --dport 25 -m state --state NEW -j ACCEPT\niptables -A OUTPUT -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT\niptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -P OUTPUT DROP\niptables -P FORWARD DROP\n```\n\nList now rules in verbose mode:\n\n```bash\niptables -L -v\n```\n\nMy output:\n\n```bash\nChain INPUT (policy DROP 1 packets, 32 bytes)\n pkts bytes target     prot opt in     out     source               destination\n    8  1104 ACCEPT     all  --  lo     any     anywhere             anywhere\n 6779 9556K ACCEPT     all  --  any    any     anywhere             anywhere             state RELATED,ESTABLISHED\n 1087 75053 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:ssh\n    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:http\n    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:https\n\nChain FORWARD (policy DROP 0 packets, 0 bytes)\n pkts bytes target     prot opt in     out     source               destination\n\nChain OUTPUT (policy DROP 0 packets, 0 bytes)\n pkts bytes target     prot opt in     out     source               destination\n 3435  250K ACCEPT     all  --  any    any     anywhere             anywhere             state RELATED,ESTABLISHED\n   13   780 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:http state NEW\n    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:https state NEW\n    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:domain state NEW\n   21  1415 ACCEPT     udp  --  any    any     anywhere             anywhere             udp dpt:domain state NEW\n```\n\nWe have now our basic firewall! Let's save it (do not change the saving files path /etc/iptables/rules.vX):\n\n```bash\niptables-save \u003e /etc/iptables/rules.v4 \u0026\u0026 ip6tables-save \u003e /etc/iptables/rules.v6\n```\n\nRestart your Raspbian server and check if everything is ok, and if the rules are automatically loaded.\n\nWe are ready now to start with the Apache installation/configuration, let's do it:\n\n```bash\napt-get install apache2\n```\n\nNow, from a client browser, let's check if it's working, copy in the url the ip of your Raspberry server and hit enter\n\n![Apache web server](http://synlogic.d3cod3.org/RSS/apache_screenshot.jpg)\n\nThat's it, Apache installed, and up\u0026running! Now the configuration:\n\n* 1 - Hide Apache version:\n\n```bash\nnano /etc/apache2/conf-enabled/security.conf\n```\n\nAnd add/edit this lines:\n\n```bash\nServerSignature Off\nServerTokens Prod\n```\n\nSave and restart apache2:\n\n```bash\n/etc/init.d/apache2 restart\n```\n\n* 2 - Turn Off Directory Browsing, Disable Symbolic Links, Limit request size (to 600 Kb) and Turn Off Server Side Includes and CGI Execution\n\n```bash\nnano /etc/apache2/apache2.conf\n```\n\nThen edit the following lines:\n\n```bash\n\u003cDirectory /var/www/\u003e\n        LimitRequestBody 614400\n        Options -FollowSymLinks -Includes -ExecCGI\n        AllowOverride None\n        Require all granted\n\u003c/Directory\u003e\n```\n\nSave and restart again.\n\n* 3 - Disable unnecessary modules and restart again\n\n```bash\na2dismod autoindex\na2dismod status\n/etc/init.d/apache2 restart\n```\n\n* 4 - Install additional modules\n\n```bash\napt-get install libapache2-mod-security2\n```\n\nModSecurity need to be enabled:\n\n```bash\nmv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf\nnano /etc/modsecurity/modsecurity.conf\n```\n\nAnd edit this line:\n\n```bash\n#SecRuleEngine DetectionOnly\nSecRuleEngine On\n```\n\nRestart apache service and install the next module:\n\n```bash\napt-get install libapache2-mod-evasive\n```\n\nThen append this an the end of /etc/apache2/apache2.conf:\n\n```bash\n\u003cIfModule evasive_module\u003e\n    #optional directive (default value equals to 1024)\n    DOSHashTableSize    1024\n\n    #obligatory directives (if even one of them is not set, malfunctioning is possible)\n    DOSPageCount        10\n    DOSSiteCount        150\n    DOSPageInterval     1\n    DOSSiteInterval     1\n    DOSBlockingPeriod   10\n\u003c/IfModule\u003e\n```\n\nRestart apache again, we got it! Now it's time for the next component, the MySQL Server!\n\n### MySQL Server\n\nFirst step, install it, easy (always use strong passwords):\n\n```bash\napt-get install mysql-server\n```\n\nAnd, to secure the install:\n\n```bash\nmysql_secure_installation\n```\n\nLet's test it:\n\n```bash\nmysql -u root -p\n```\n\nAnd you will enter the mysql console, perfect! Now install PHP!\n\n### PHP\n\nNow, we have a small issue here, the latest Raspbian is based on debian Jessie, that still comes with PHP 5.6 by default (from the stable branch), but we don't want an older almost unsupported (and most insecure) PHP release, we want to install PHP 7, the last release. In order to do that we'll need to tweak a little bit our apt system, let's get to it:\n\n```bash\nnano /etc/apt/sources.list\n```\n\nAnd add at the end:\n\n```bash\n# TWEAK - Stretch (testing) branch for PHP7 install on Jessie\ndeb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi\n```\n\nNow what we don't want is that every package is updated or installed from the stretch (testing) branch. To do this we can set some preferences that we want all packages to be selected from Jessie by default. Open up the following file **/etc/apt/preferences**, and add the following:\n\n```bash\nPackage: *\nPin: release n=jessie\nPin-Priority: 600\n```\n\nSave the file and update:\n\n```bash\napt-get update\n```\n\nWe have it, every time we want to install something from the testing branch, we'll do it like that (this will update the apache2 package, when asked, maintain the current config files):\n\n```bash\napt-get install -t stretch php7.0-cli php7.0-dev php-pear libapache2-mod-php7.0 php7.0-mysql php7.0-mcrypt php7.0-sqlite3 php7.0-bcmath php7.0-bz2 php7.0-curl php7.0-gd php7.0-imap php7.0-mbstring php7.0-odbc php7.0-pgsql php7.0-soap php7.0-xml php7.0-xmlrpc php7.0-zip\n```\n\nAnd, to fix some issues due to this change of repo:\n\n```bash\napt-get install -t stretch mailutils maildir-utils sendmail-bin\napt-get install sensible-mda\n```\n\nThis one we'll need to wait a little longer, so we have some time to clarify something here, the moment we use the testing branch (from debian stretch), we are mixing \"not yet marked stable\" packages in our system, this is not a good policy for a security oriented server, but an older release of php is surely a worst case scenario, so buckle up, we just passed to the next level, little bit more challenging, feels scary but don't lie, you're liking it!\n\nNow the last module, a specific one for [GnuPG](https://gnupg.org/) for encryption:\n\n```bash\napt-get install -t stretch gnupg libgpg-error-dev libassuan-dev\n```\n\nGo to a temp folder and download gpgme library:\n\n```bash\nwget https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-1.8.0.tar.bz2\n```\n\nExtract, configure, make \u0026\u0026 make install:\n\n```bash\ntar xvfj gpgme-1.8.0.tar.bz2 \u0026\u0026 cd gpgme-1.8.0 \u0026\u0026 ./configure\n```\n\nThen\n\n```bash\nmake \u0026\u0026 make install\n```\n\nand\n\n```bash\npecl install gnupg\n```\n\nlast one, open /etc/php/7.0/apache2/conf.d/20-gnupg.ini\n\n```bash\nnano /etc/php/7.0/apache2/conf.d/20-gnupg.ini\n```\n\nand add the following line:\n\n```bash\nextension=gnupg.so\n```\n\nSave \u0026 close the file, and to fix a little library loading issue, open this new file:\n\n```bash\nnano /etc/ld.so.conf.d/userlib.conf\n```\n\nthen add this line:\n\n```bash\n/usr/local/lib\n```\n\nSave/close the file, and rerun ldconfig to rebuild the cache:\n\n```bash\nldconfig\n```\n\nFinally restart apache, and create a new file for print php info:\n\n```bash\nnano /var/www/html/info.php\n```\n\nThen add the following typical php code:\n\n```bash\n\u003c?php phpinfo(); ?\u003e\n```\n\nNow open from your client browser the following url: http://your_raspbian_server_ip/info.php, if everything went fine you will see the common php information page.\n\n![PHP Install](http://synlogic.d3cod3.org/RSS/php_install.jpg)\n\nWe are done with PHP installation, now we remove the info file for security reasons:\n\n```bash\nrm -i /var/www/html/info.php\n```\n\nThis is starting to look nice!\n\nOk, let's hit pause for a moment, and take a better look at what we have at the moment:\n\n```bash\nservice --status-all\n```\n\nThis command will give us the complete list of services available on our server, where [ + ] means service started, [ - ] service stopped, and [ ? ] state unknown.\n\nBut let's take a deep look with another program:\n\n```bash\napt-get install chkconfig\n```\n\nand\n\n```bash\nchkconfig --list\n```\n\nThis will show us the availability of our services at all different runlevels. No room here for a runlevel class, so [here](https://en.wikipedia.org/wiki/Runlevel) some more info.\n\nAnd another really powerful tool for discovering services is the systemd init system:\n\n```bash\nsystemctl list-units -t service\n```\n\nAnd as we did before with netstat, let's check all active tcp connections:\n\n```bash\nnetstat -atp\n```\n\nMy output:\n\n```bash\nProto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name\ntcp        0      0 localhost:smtp          *:*                     LISTEN      1151/exim4\ntcp        0      0 192.168.1.104:22        *:*                     LISTEN      310/sshd\ntcp        0      0 localhost:mysql         *:*                     LISTEN      781/mysqld\ntcp        0     92 raspbian.ip.number:22   client.ip.number:port   ESTABLISHED 1188/sshd: username\ntcp6       0      0 localhost:smtp          [::]:*                  LISTEN      1151/exim4\ntcp6       0      0 [::]:http               [::]:*                  LISTEN      736/apache2\n```\n\nAs you can see, we have our newly installed apache2 and mysql services listening, our active ssh connection established, and a new one, the exim4 service listening too, but hey, we do not install this exim4, what is that? Well, when we installed php7, one of his dependencies is the exim4 service for sending system information to internal users, so the system installed it automatically.\n\nNext story, a special bonus, Ruby on Rails!\n\n### Ruby on Rails with rbenv (EXTRA BONUS - INTERMEDIATE LEVEL!!!)\n\nRuby on Rails is a rapid development web framework that allows web designers and developers to implement dynamic fully featured web applications.\nPersonally, i believe that RoR is really a better option than PHP, and i'm not the only one, but anyway, search the internet and learn about it, you'll choose\nto have it or not on your personal server.\n\nLet's get to work! We start as always with the dependencies:\n\n```bash\napt-get install autoconf bison build-essential curl libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev\n```\n\nand\n\n```bash\napt-get install git-core\n```\n\nRight, now install, from github, [rbenv](https://github.com/rbenv/rbenv):\n\n```bash\ngit clone https://github.com/rbenv/rbenv.git ~/.rbenv\n```\n\nAdding his PATH for using the command line utility:\n\n```bash\necho 'export PATH=\"$HOME/.rbenv/bin:$PATH\"' \u003e\u003e ~/.bashrc\necho 'eval \"$(rbenv init -)\"' \u003e\u003e ~/.bashrc\n\nsource ~/.bashrc\n```\n\nTime to test it:\n\n```bash\ntype rbenv\n```\n\nYou should see this, if everything is fine:\n\n```bash\nrbenv is a function\nrbenv ()\n{\n    local command;\n    command=\"$1\";\n    if [ \"$#\" -gt 0 ]; then\n        shift;\n    fi;\n    case \"$command\" in\n        rehash | shell)\n            eval \"$(rbenv \"sh-$command\" \"$@\")\"\n        ;;\n        *)\n            command rbenv \"$command\" \"$@\"\n        ;;\n    esac\n}\n```\n\nAnd remember, from time to time, to update rbenv, as it is installed from Git, we'll need to do it manually:\n\n```bash\ncd ~/.rbenv\ngit pull\n```\n\nPerfect! Now install a rbenv plugin to make life easier, [ruby-build](https://github.com/rbenv/ruby-build):\n\n```bash\ngit clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build\n```\n\nAt this point, we have all the tools to start installing ruby and configuring it properly, so let's install Ruby!\n\nSo, here it comes our first dilemma, which version of Ruby? Well, rbenv help us with that, as it manage and organize,\nbehind the curtain, one or multiple installed version of Ruby, cool!\n\nWe can then list all versions available at the moment:\n\n```bash\nrbenv install -l\n```\n\nand choose one, i picked 2.3.3 this time:\n\n```bash\nrbenv install 2.3.3\n```\n\nBE ADVISED, this step can take a lot, maybe a lot as in go to lunch or whatever you prefer, but a coffee will not be enough!\nSee you in a bit then :P\n\nOK, we are back and Ruby is installed, my output:\n\n```bash\nInstalled ruby-2.3.3 to /home/your_username/.rbenv/versions/2.3.3\n```\n\nLast things, setting this version as default:\n\n```bash\nrbenv global 2.3.3\n```\n\nAnd test it, obviously:\n\n```bash\nruby -v\n```\n\nMy output:\n\n```bash\nruby 2.3.3p222 (2016-11-21 revision 56859)\n```\n\nGreat, now we need to configure Gems (packages that extend the functionality of Ruby), we turn off local documentation\nin order to have more speed, and we install a dependencies manager called **bundler** :\n\n```bash\necho \"gem: --no-document\" \u003e ~/.gemrc\ngem install bundler\n```\n\nMy output:\n\n```bash\nFetching: bundler-1.15.1.gem (100%)\nSuccessfully installed bundler-1.15.1\n1 gem installed\n```\n\nLet's check if the Gems path is correct:\n\n```bash\ngem env home\n```\n\nMy output:\n\n```bash\n/home/your_username/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0\n```\n\nFine, Gems is correctly set up, now we install Rails:\n\n```bash\ngem install rails\n```\n\nThis one, could take a while...\nWhen finished, as always, we check the installed version:\n\n```bash\nrails -v\n```\n\nAnd my output is:\n\n```bash\nRails 5.1.2\n```\n\nSUPER! Now we need to install JavaScript Runtime, because some Rails features depends on it:\n\n```bash\ncd /tmp\n\\curl -sSL https://deb.nodesource.com/setup_6.x -o nodejs.sh\n```\n\nAnd we take a look at the script file we just downloaded (just in case):\n\n```bash\nless nodejs.sh\n```\n\nIf we are satisfied and everything is correct, we quit by typing **q**\n\nOk, let's install the NodeSource Node.js v6.x repo:\n\n```bash\ncat /tmp/nodejs.sh | sudo -E bash -\n```\n\nWhere the -E flag used here will preserve the user's existing environment variables.\n\nAlmost done, we now can simply install  nodejs via apt:\n\n```bash\napt-get install nodejs\n```\n\nAnd that's it! We can start now testing our Ruby on Rails installation!\nThere are different options to deploy a Ruby on Rails App, we will try here to use our already installed Apache web server,\nso, this is what we need, the Passenger Apache Module.\nDebian repository comes with an older version of the libapache2-mod-passenger, so we install the correct version through gem:\n\n```bash\n# First install some dependencies\napt-get install libcurl4-openssl-dev apache2-threaded-dev\n\n# Install Passeneger module\ngem install passenger\n\n# Install Passenger + Apache module\npassenger-install-apache2-module\n```\n\nNow follow the instruction and the module will compile (damn fine cup of coffee time).\n\nWe need now to properly configure apache in order to have Passenger working correctly:\n\n```bash\nnano /etc/apache2/mods-available/passenger.load\n```\n\nAnd copy the line suggested from previous Passenger install instruction:\n\n```bash\nLoadModule passenger_module /home/user/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/passenger-5.1.5/buildout/apache2/mod_passenger.so\n```\n\nThen:\n\n```bash\nnano /etc/apache2/mods-available/passenger.conf\n```\n\nAnd copy:\n\n```bash\n\u003cIfModule mod_passenger.c\u003e\n        PassengerRoot /home/your_user_name/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/passenger-5.1.5\n        PassengerDefaultRuby /home/your_user_name/.rbenv/versions/2.3.3/bin/ruby\n\u003c/IfModule\u003e\n```\n\nAnd the last step, enable the module and restart apache:\n\n```bash\na2enmod passenger\nservice apache2 restart\n```\n\nFine, now let's understand how to deploy our Rails applications, but in order to do that, we first need one!\nAs always, we will use a testing app, and with the help the previously installed tools, it'll be super easy!\n\nWe'll start creating a new directory for storing rails apps:\n\n```bash\ncd /home/your_username/ \u0026\u0026  mkdir your_rails_dev_folder_name\n```\n\nAnd we create a testing app:\n\n```bash\nrails new testapp --skip-bundle\n```\n\nPerfect, enter the directory and modify the Gemfile to install a JavaScript execution environment:\n\n```bash\ncd testapp \u0026\u0026 nano Gemfile\n```\n\nNow search for this line:\n\n```bash\n# gem 'therubyracer',  platforms: :ruby\n```\n\nuncomment it, save the file and close it.\n\nAll right, now launch the automatic install (thanks (bundler)[https://bundler.io/]):\n\n```bash\nbundle install\n```\n\nWOW, we are almost finished, apache is running fine with Passenger module configured, Ruby on Rails is fine tuned with rbenv, now we'll check if everything is sound, and finally, we'll create a virtual host file for testing our rails app.\n\nSo, the testing:\n\n```bash\npassenger-memory-stats\n```\n\nAnd my output:\n\n```bash\n--------- Apache processes ---------\nPID  PPID  VMSize    Resident  Name\n------------------------------------\n855  1     12.8 MB   6.3 MB    /usr/sbin/apache2 -k start\n899  855   232.1 MB  5.9 MB    /usr/sbin/apache2 -k start\n900  855   230.0 MB  4.2 MB    /usr/sbin/apache2 -k start\n\n\n-------- Nginx processes ---------\n\n\n\n---- Passenger processes -----\nPID   VMSize   Resident  Name\n------------------------------\n861   30.7 MB  8.1 MB    Passenger watchdog\n866   93.9 MB  11.4 MB   Passenger core\n877   39.1 MB  8.9 MB    Passenger ust-router\n```\n\nYou can see the apache processes and the Passenger processes up and running, GREAT!\n\nFinally, we create a new virtual host file for our **testapp** rails app:\n\n```bash\ncp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/testapp.conf\nnano /etc/apache2/sites-available/testapp.conf\n```\n\nThe file need to look like this:\n\n```bash\n\u003cVirtualHost *:80\u003e\n\n        ServerAdmin webmaster@localhost\n        DocumentRoot /home/your_username/rails_folder/testapp/public\n        RailsEnv development\n\n        ErrorLog ${APACHE_LOG_DIR}/error.log\n        CustomLog ${APACHE_LOG_DIR}/access.log combined\n\n        \u003cDirectory \"/home/your_username/rails_folder/testapp/public\"\u003e\n                Allow from all\n                Options -FollowSymLinks -MultiViews\n                Require all granted\n        \u003c/Directory\u003e\n\n\u003c/VirtualHost\u003e\n```\n\nThen, disable the default apache virtual host, enable the new **testapp** rails, and restart apache:\n\n```bash\na2dissite 000-default\na2ensite testapp\nservice apache2 restart\n```\n\nAND THAT'S IT, PEOPLE! Open in your browser the ip of your raspbian server and check it out:\n\n\n![Raspbian RoR](http://synlogic.d3cod3.org/RSS/raspbian_rails.jpg)\n\n\nSo here we are, our server is starting to get all the pieces in place. Next story? Hide our SSH service!\n\n## Hide\n\nThis is the last last layer of security we are going to add to our SSH and SFTP services, it is some kind of advanced obfuscation technique, so not everyone will agree that it is really useful, but hey, in my opinion it can add some trouble for an attacker trying to own our server, so here we go, let's install a port knocker!\nAnd what is a port knocker? Is a special type of disguised service that listen for a specific sequence of \"knocks\" on a predefined list of ports, when this list of port is correctly \"knocked\" this service opens temporarily a specified port (our enter door to the server, the SSH port 22) in order to obtain access, and close it again after we log in.\nIt's the same as knocking at your house door with a predefined knocking code, then someone open the door, and close it again after you are inside.\nSo, in terms of visibility (port scanning for example), our server will be invisible, because at the question: is the SSH port listening?, the answer will be NO.\n\nBut BEWARE! Port Knocking techniques are an open debate about actual efficiency and if we can really gain some more security with it, so search the internet and read about it, then choose if you want that on your server, or not.\n\n### Port Knock\n\nLet's get to it, install the debian standard port knocker:\n\n```bash\napt-get install knockd\n```\n\nThen edit his main config file, /etc/knockd.conf, you will have something like this:\n\n```bash\n[options]\n        UseSyslog\n\n[openSSH]\n       sequence    = 7000,8000,9000\n       seq_timeout = 5\n       command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT\n       tcpflags    = syn\n\n[closeSSH]\n       sequence    = 9000,8000,7000\n       seq_timeout = 5\n       command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT\n       tcpflags    = syn\n```\n\nAnd change it to something like this:\n\n```bash\n[options]\n        UseSyslog\n\n#[openSSH]\n#       sequence    = 7000,8000,9000\n#       seq_timeout = 10\n#       command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT\n#       tcpflags    = syn\n\n#[closeSSH]\n#       sequence    = 9000,8000,7000\n#       seq_timeout = 10\n#       command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT\n#       tcpflags    = syn\n\n[SSH]\n        sequence        = 5004,1233,8732,1112,6\n        seq_timeout     = 10\n        cmd_timeout     = 15\n        start_command   = /sbin/iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT\n        stop_command    = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT\n        tcpflags        = syn\n```\n\nLet's see, we commented out the [openSSH] and [closeSSH] blocks, and added a new block called [SSH], this is because we want to automatically close the port 22 some seconds after we opened it, we do not want to have different knocking sequences for first open and then later close the port.\nIn our new [SSH] block we configured the port knocking sequence with a random port sequence (i've used 5004,1233,8732,1112,6, you choose yours), the time for receiving the knocks (seq_timeout), the time the system wait to close the port after the opening (cmd_timeout), then the command for open the port (start_command, an iptables rule that momentarily give us access to the port), and finally the closing command (stop_command).\n\nOk, so now edit another file, /etc/default/knockd and make it look like this:\n\n```bash\n################################################\n#\n# knockd's default file, for generic sys config\n#\n################################################\n\n# control if we start knockd at init or not\n# 1 = start\n# anything else = don't start\n#\n# PLEASE EDIT /etc/knockd.conf BEFORE ENABLING\nSTART_KNOCKD=1\n\n# command line options\nKNOCKD_OPTS=\"-i eth0\"\n```\n\nThat's it, restart the knockd service and test it:\n\n```bash\n/etc/init.d/knockd restart\n```\n\nNow, before we finish to configure the firewall and hide our SSH service, we have to make sure this is working, because is we do not configure it properly, or something go wrong, we will be closed out by our server!!! The firewall will close the port 22, and we will need to access directly to the server to fix the issue (not a problem if your server is in your room, a little worst if the server is elsewhere...)\nSo, let's test it!\n\n**From a client machine**, create the following script:\n\n```bash\n#!/bin/bash\n\nfor x in 5004,1233,8732,1112,6;\ndo nmap -Pn --host_timeout 201 --max-retries 0 -p $x your.rpi.server.number;\ndone\n```\n\nChange the port sequence accordingly and the server IP, and save it the script as knock_rpi.sh\n\nIf you don't have nmap installed in your client, install it, [nmap](https://nmap.org/)\n\nThe moment of truth, run from a terminal in your client:\n\n```bash\nsh knock_rpi.sh\n```\n\nThen in your server print the iptables rules:\n\n```bash\niptables -L -v\n```\n\nIf everything went right, you will see something similar to this line at the beginning of the INPUT chain:\n\n```bash\n27  1872 ACCEPT     tcp  --  any    any     your.client.ip.number        anywhere             tcp dpt:ssh\n```\n\nThat's it, this is the line tha knockd temporarily add to the firewall in order to let us in via port 22.\n\nIf we print the iptables rules again, this rule had disappeared because knockd command will timeout, so server hidden again.\n\nOk, last step, we need to delete from our firewall the rule we configured before about listening at port 22, remember? :\n\n```bash\niptables -A INPUT -p tcp --dport 22 -j ACCEPT\n```\n\nIn order to do that we open the file /etc/iptables/rules.v4:\n\n```bash\nnano /etc/iptables/rules.v4\n```\n\nAnd remove this line:\n\n```bash\n-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT\n```\n\nThis is it! Restart our server and try it!\n\n```bash\nshutdown -r now\n```\n\nNow, if we try to connect via SSH like always, the server will not respond, because the port 22 is actually closed! In order to SSH into our server we need to \"knock\" before, and then ask for a ssh connection.\n\nSo:\n\n```bash\nsh knock_rpi.sh\n```\n\nThen later (like always):\n\n```bash\nssh -i ~/.ssh/your_rsa_key_name -p 22 username@RPi_ip_number\n```\n\nAnd that's it, SSH service well hidden!\n\nThis will be the same for SFTP connection, \"knock\" before ask for connection!\n\nWell, we have done most of the job, we almost have our secure server, we just need to secure something more, then configure our domain DNS, configure our local router, and finally start using it.\nBut don't rush, one step at the time, next story, \"Fingerprint Your Files\"\n\n## Security\n\nLet's say it, this was not so difficult in the end, we are now reaching the end of our journey, and this doesn't mean we looked at everything nor that we are now good sysadmin security experts, nothing more far from the truth actually, this field is an incredibly complex one, especially for online servers, it needs dedication, continuos update (on personal side as on machine side), imagination and a lot of hours of practice, really a lot!\nSo, we are not experts yet, but maybe some of us will be one day, who knows. In the meantime, let's finish our basic security configuration for our Raspbian personal server, intrusion detection systems, here we go.\n\n### RKHunter\n\nRKHunter is a [rootkit](https://en.wikipedia.org/wiki/Rootkit) protection system. Rootkits are an extremely dangerous problems for online servers, once secretly installed on servers, they permit intruders to repeatedly enter the server without been detected. In short, if a server have a unresolved vulnerability, some attacker could use it to install a rootkit, then imagine that the sysadmin of the server fix the vulnerability, the server is now secure! but the invisible rootkit is already there, so the attacker can come back whenever he/she want, through the rootkit that was installed.\n\nSo, it's a good idea to install RKhunter, it will help us to protect our system from this kinds of problems, let's do it:\n\n```bash\napt-get install -t stretch libwww-perl\n```\n\nWe need to install it from the testing repo because some dependencies of rkhunter was previously installed by the php installation.\n\n```bash\napt-get install -t stretch rkhunter\n```\n\nThis will install the rkhunter 1.4.2, let's check it:\n\n```bash\nrkhunter --versioncheck\n```\n\nOk, now we perform an update of our data files, some kind of \"base\" information about our filesystem that rkhunter will use for checks:\n\n```bash\nrkhunter --update\n```\n\nNow we confir to rkhunter that this is the baseline from which to do the checks:\n\n```bash\nrkhunter --propupd\n```\n\nPerfect, we are ready to perform our initial run, this will probably produce some warnings, but don't worry, this is expected:\n\n```bash\nrkhunter -c --enable all --disable none\n```\n\nThis will take his time, and will ask to press enter for execute different checks.\n\nOk, log saved, open it and review:\n\n```bash\nnano /var/log/rkhunter.log\n```\n\nThen search for \"Warning\", i have the following:\n\n```bash\n...\nWarning: Found preloaded shared library: /usr/lib/arm-linux-gnueabihf/libarmmem.so\n...\nWarning: The command '/sbin/chkconfig' has been replaced by a script: /sbin/chkconfig: Perl script, ASCII text executable\n...\nWarning: The following processes are using deleted files:\nProcess: /usr/sbin/apache2    PID: 673    File: /tmp/.ZendSem.BwxJJJ\nProcess: /usr/sbin/mysqld    PID: 794    File: /tmp/ibI3FUpC\nProcess: /usr/sbin/apache2    PID: 3078    File: /tmp/.ZendSem.BwxJJJ\nProcess: /usr/sbin/apache2    PID: 3079    File: /tmp/.ZendSem.BwxJJJ\nProcess: /usr/sbin/apache2    PID: 3080    File: /tmp/.ZendSem.BwxJJJ\nProcess: /usr/sbin/apache2    PID: 3081    File: /tmp/.ZendSem.BwxJJJ\nProcess: /usr/sbin/apache2    PID: 3082    File: /tmp/.ZendSem.BwxJJJ\n...\nWarning: Process '/usr/sbin/knockd' (PID 366) is listening on the network.\n...\n```\n\nAnother way to perform a complete check printing warning only is:\n\n```bash\nrkhunter -c --enable all --disable none --rwo\n```\n\nWe have now a simple example of rkhunter warning, let's configure it a little:\n\n```bash\nnano /etc/rkhunter.conf\n```\n\nFirst, we set up local mail for receiving notification when rkhunter hits a warning:\n\n```bash\nMAIL-ON-WARNING=root@localhost\nMAIL_CMD=mail -s \"[rkhunter] Warnings found for ${HOST_NAME}\"\n```\n\nThen we'll fix the warnings that told us that some binary packages have been replaced by scripts:\n\n```bash\nSCRIPTWHITELIST=/sbin/chkconfig\n```\n\nNext, allow apache2 and mysqld process to use deleted files, this is not ALWAYS the better thing to do, but in our case, we have a clean box, no one has touched our server (at least in my case) apart from me, and we haven't open it to the internet yet, so, it is not crazy to consider this a false positive, in which case i decided to whitelist it:\n\n```bash\nALLOWPROCDELFILE=/usr/sbin/apache2\nALLOWPROCDELFILE=/usr/sbin/mysqld\n```\n\nNext, we whitelist a specific rpi arm preloaded shared library that is giving us another false positive:\n\n```bash\nSHARED_LIB_WHITELIST=/usr/lib/arm-linux-gnueabihf/libarmmem.so\n```\n\nNext, we disable the warning about Protocol 1 which is no longer supported on OpenSSH: we do this by using the option 2 for the allow_ssh_prot (as per instructions _If the 'Protocol' option has not been set in the SSH configuration file, then a value of '2' may be set here in order to  suppress a warning message_)\n\n```\nALLOW_SSH_PROT_V1=2\n```\n\nAnd finally, the last one (in my case), we have knockd installed and listening to the network interface (our port knocker), so we need to whitelist it:\n\n```bash\nALLOWPROCLISTEN=/usr/sbin/knockd\n```\n\nOk, we check the configuration for errors:\n\n```bash\nrkhunter -C\n```\n\nIf no errors, then we re-run a check again:\n\n```bash\nrkhunter -c --enable all --disable none --rwo\n```\n\nRKHunter will tell us here that the rkhunter.conf file properties has changed, fine, so we update his db (set a new baseline):\n\n```bash\nrkhunter --propupd\n```\n\nThat's it, we are ready for the last step, enable automated checks with a [CRON job](https://en.wikipedia.org/wiki/Cron).\nEdit file /etc/default/rkhunter\n```bash\nCRON_DAILY_RUN=\"true\"\nCRON_DB_UPDATE=\"true\"\nREPORT_EMAIL=\"root\"\n```\n\nThis will activate the rkhunter job defined in /etc/cron.daily which sources its configuration from /etc/default/rkhunter\n```\n# source our config\n. /etc/default/rkhunter\n```\n\nWe have it! RKHunter ready and running checks every day, amazing! But remember, you'll need to check regularly for messages about warnings, at least once a week, in order to keep everything in order, every new change in the system could be recognized as a warning by rkhunter, so we'll need to always take a look a keep it clean from false positives, if we want to be able in the future to recognize real bad files.\n\nPerfect, we'll now install and configure a network intrusion detection, next story PSAD!\n\n### psad Network Intrusion Detection System\n\n**psad** stands for port scan attack detection, and is a software that monitors firewall logs to determine is a scan/attack is in progress. It can alert system administrators, like rkhunter via mail, or it can take active steps to deter the threat.\n\nAs always, let's install it:\n\n```bash\napt-get install -t stretch psad\n```\n\nNow the firewall config, let's add the necessary rules to our firewall (iptables) to let psad do the work:\n\n```bash\niptables -A INPUT -j LOG \u0026\u0026 iptables -A FORWARD -j LOG\n```\n\nThat's it, this was super easy!\n\nNow it's the config time, open the psad config file:\n\n```bash\nnano /etc/psad/psad.conf\n```\n\nAnd start by configuring the scans detection, search and change the following:\n\n```bash\nHOSTNAME    pi; # or whatever hostname you set on your raspbian server, if you don't know it, use the \"hostname\" command\nIPT_SYSLOG_FILE         /var/log/syslog;\nIGNORE_PORTS            your_port_knocking_ports;\nENABLE_PERSISTENCE          N;\nMAX_SCAN_IP_PAIRS           50000;\nMIN_DANGER_LEVEL            3;\nEMAIL_ALERT_DANGER_LEVEL    4;\n```\n\nNow implement intrusion detection, but first update psad signature definitions and restart the service:\n\n```bash\npsad --sig-update \u0026\u0026 /etc/init.d/psad restart\n```\n\nBut before implement the intrusion detection, let's play a little, we are going to do a port scan!!!\nFrom a client run this on a terminal:\n\n```bash\nsudo nmap -PN -sS your_rpi_server_ip\n```\n\nThen wait for finish or stop it after a while, then run on server:\n\n```bash\npsad -S\n```\n\nAHHHHHHHHHH! Don't worry, it was you with your port scan doing all that. This is the current status of psad service, cool eh? A lot of info about our server network!\nVery good, now it's time to edit some more config:\n\n```bash\nnano /etc/psad/auto_dl\n```\n\nThen add:\n\n```bash\n127.0.0.1       0;\nyour.local.machine.ip   0; # local machine\n```\n\nThis will exempt those ip numbers from psad intrusion detection system, good so we don't ever end locked out from our server.\n\nNow go back to the psad main config file /etc/psad/psad.conf end edit the following:\n\n```bash\nENABLE_AUTO_IDS         Y;\nAUTO_IDS_DANGER_LEVEL       4;\nAUTO_BLOCK_TIMEOUT          3600;\n```\n\nThis will enable the auto firewall configuration, banning a specific ip for 60 minutes if detected a danger level 4 (a normal SYN scan for example), we got it!\n\nIt's testing time, from another client connected to your local network, not from the one where you have the current SSH connection open, run this command:\n\n```bash\nsudo nmap -PN -sS your_rpi_server_ip\n```\n\nIn the meantime, close your ssh connection and reconnect, then on your server show the actual iptables rules:\n\n```bash\niptables -S\n```\n\nMy output:\n\n```bash\n...\nN PSAD_BLOCK_FORWARD\n-N PSAD_BLOCK_INPUT\n-N PSAD_BLOCK_OUTPUT\n...\n-A PSAD_BLOCK_FORWARD -d the.scanning.client.ip/32 -j DROP\n-A PSAD_BLOCK_FORWARD -s the.scanning.client.ip/32 -j DROP\n-A PSAD_BLOCK_INPUT -s the.scanning.client.ip/32 -j DROP\n-A PSAD_BLOCK_OUTPUT -d the.scanning.client.ip/32 -j DROP\n...\n```\n\nAs you can see psad added a new chain with new rules to our firewall, and the scanning ip number is banned now!!! YHEAAAAAAAA! It's working!\n\nNow we'll couple **psad** with **tripwire**, and our Intrusion Detection System will become fairly good, but this is the next story.\n\n### Tripwire Intrusion Detection System\n\nTripwire is host-based intrusion detection system (HIDS), it collects details about our filesystem and configurations.\n\nFirst, install:\n\n```bash\napt-get install tripwire\n```\n\nAnswer yes to everything and set the passwords it asks.\n\nThen, similar as rkhunter, initialize the tripwire database:\n\n```bash\ntripwire --init\n```\n\nAnd we run a check saving the result into a file:\n\n```bash\ncd /etc/tripwire\nsh -c 'tripwire --check | grep Filename \u003e test_results'\n```\n\nWe have now a starting list of tripwire complains, let's configure it good to match our system:\n\n```bash\nnano /etc/tripwire/twpol.txt\n```\n\nIn the \"Boot Scripts\" section we comment the /etc/rc.boot line, since this isn't present in our raspbian system:\n\n```bash\n#        /etc/rc.boot            -\u003e $(SEC_BIN) ;\n```\n\nAnd the same for the \"Root config files\" section, comment all the lines from your test_results file. In my case:\n\n```bash\n/root                           -\u003e $(SEC_CRIT) ; # Catch all additions to /root\n        /root/mail                      -\u003e $(SEC_CONFIG) ;\n        #/root/Mail                     -\u003e $(SEC_CONFIG) ;\n        #/root/.xsession-errors         -\u003e $(SEC_CONFIG) ;\n        #/root/.xauth                   -\u003e $(SEC_CONFIG) ;\n        #/root/.tcshrc                  -\u003e $(SEC_CONFIG) ;\n        #/root/.sawfish                 -\u003e $(SEC_CONFIG) ;\n        #/root/.pinerc                  -\u003e $(SEC_CONFIG) ;\n        #/root/.mc                      -\u003e $(SEC_CONFIG) ;\n        #/root/.gnome_private           -\u003e $(SEC_CONFIG) ;\n        #/root/.gnome-desktop           -\u003e $(SEC_CONFIG) ;\n        #/root/.gnome                   -\u003e $(SEC_CONFIG) ;\n        #/root/.esd_auth                        -\u003e $(SEC_CONFIG) ;\n        #/root/.elm                     -\u003e $(SEC_CONFIG) ;\n        #/root/.cshrc                   -\u003e $(SEC_CONFIG) ;\n        /root/.bashrc                   -\u003e $(SEC_CONFIG) ;\n        /root/.bash_profile            -\u003e $(SEC_CONFIG) ;\n        /root/.bash_logout             -\u003e $(SEC_CONFIG) ;\n        /root/.bash_history             -\u003e $(SEC_CONFIG) ;\n        #/root/.amandahosts             -\u003e $(SEC_CONFIG) ;\n        #/root/.addressbook.lu          -\u003e $(SEC_CONFIG) ;\n        #/root/.addressbook             -\u003e $(SEC_CONFIG) ;\n        #/root/.Xresources              -\u003e $(SEC_CONFIG) ;\n        #/root/.Xauthority              -\u003e $(SEC_CONFIG) -i ; # Changes Inode number on login\n        #/root/.ICEauthority                -\u003e $(SEC_CONFIG) ;\n```\n\nAlmost done, we had some complains about some files descriptors inside /proc filesystem, and this files changes all the time, so in order to avoid regular false positives, we'll remove the specific check over the general /proc folder and we'll add all directories under /proc that we want to check.\nGo to the \"Devices \u0026 Kernel information\" section and make it look like this:\n\n```bash\n        /dev            -\u003e $(Device) ;\n        /dev/pts        -\u003e $(Device) ;\n        #/proc          -\u003e $(Device) ;\n        /proc/devices           -\u003e $(Device) ;\n        /proc/net               -\u003e $(Device) ;\n        /proc/tty               -\u003e $(Device) ;\n        /proc/sys               -\u003e $(Device) ;\n        /proc/cpuinfo           -\u003e $(Device) ;\n        /proc/modules           -\u003e $(Device) ;\n        /proc/mounts            -\u003e $(Device) ;\n        /proc/filesystems       -\u003e $(Device) ;\n        /proc/interrupts        -\u003e $(Device) ;\n        /proc/ioports           -\u003e $(Device) ;\n        /proc/self              -\u003e $(Device) ;\n        /proc/kmsg              -\u003e $(Device) ;\n        /proc/stat              -\u003e $(Device) ;\n        /proc/loadavg           -\u003e $(Device) ;\n        /proc/uptime            -\u003e $(Device) ;\n        /proc/locks             -\u003e $(Device) ;\n        /proc/meminfo           -\u003e $(Device) ;\n        /proc/misc              -\u003e $(Device) ;\n```\n\nAnd the last one, we need to comment out the /var/run and /var/lock lines so that our system does not flag normal filesystem changes by services:\n\n```bash\n        #/var/lock              -\u003e $(SEC_CONFIG) ;\n        #/var/run               -\u003e $(SEC_CONFIG) ; # daemon PIDs\n        /var/log                -\u003e $(SEC_CONFIG) ;\n```\n\nDONE! With tripwire configured, first we recreate his encrypted policy:\n\n```bash\ntwadmin -m P /etc/tripwire/twpol.txt\n```\n\nand reinitialize the database:\n\n```bash\ntripwire --init\n```\n\nIf everything went right, we we'll have no warnings, so run a check:\n\n```bash\ntripwire --check\n```\n\nThere we go, this will be a typical tripwire report.\n\nLet's clean the system from sensitive information:\n\n```bash\nrm /etc/tripwire/test_results\nrm /etc/tripwire/twpol.txt\n```\n\nJust in case we someday need to edit again the tripwire config, we'll need to temporarily recreate the plaintext file we just edited:\n\n```bash\nsh -c 'twadmin --print-polfile \u003e /etc/tripwire/twpol.txt'\n```\n\nThis is how we do it!\n\nRight, we are near the end of the story, we only need to set up tripwire email notification and automate checks with CRON, like we did it for rkhunter, let's get to it:\n\n```bash\ntripwire --check | mail -s \"Tripwire report for `uname -n`\" your@email\n```\n\nThis will generate a tripwire report and send it to the specified mail. Just like that!\n\nWhat next then, well we add a new cron job to our cron table:\n\n```bash\ncrontab -e\n```\n\nand we add this line:\n\n```bash\n30 03 * * * /usr/sbin/tripwire --check | mail -s \"Tripwire report for `uname -n`\" your@email\n```\n\nSo, every day we will receive a report from our **tripwire** system, and another one from **rkhunter** in case it find some warnings.\n\nBut that is a lot of logs and reports, so we will install a very powerful log parser to help us organize and recover information about our system, so next story, a short one, Logwatch Log Analyzer!\n\n### Logwatch Log Analyzer\n\nUsually, system log files are really, really long files with eventually a lot of information repeated, so in order to help us maintaining our beautiful raspbian server, we'll install here a very useful application that take all the system logs and create a nice and clean digest about our system activities (the good ones and the not so good ones), so let's install logwatch:\n\n```bash\napt-get install logwatch\n```\n\nDone! Now the configuration. we'll need to, as always, edit his config file:\n\n```bash\nnano /usr/share/logwatch/default.conf/logwatch.conf\n```\n\nAnd edit the **MailTo** line, entering the mail where you want logwatch to send the reports:\n\n```bash\nMailTo = email@address\n```\n\nAnd that's all! So we now have a perfectly readable daily report automatically generated by logwatch, great!\n\nIf you want to test it from terminal to get a look at the reports, just type:\n\n```bash\nlogwatch --detail High --mailto email@address\n```\n\nWait a little bit and check your mail, there it is!\n\nWe are set and decently secured, we are at the last steps of our journey, we'll just need to secure apache with a TLS/SSL certificate from Let's Encrypt, then set up our hostnames we are going to host, and finally, correctly and securely configure our home router to have our amazing Raspbian Server available on the internet!!!!\n\nNext story, TLS/SSL certificates.\n\n### TLS/SSL\n\nSSL certificates are used within web servers to encrypt the traffic between the server and client, providing extra security for users accessing your application. Let's Encrypt provides an easy way to obtain and install trusted certificates for free.\n\nRemember that in order to complete this step, you need to have already configured some domain (www.yourdomain.com) with DNS pointing to your home server (your home IP address).\n\nSo we are going to install and configure our apache server with a TLS/SSL certificate from [Let's Encrypt](https://letsencrypt.org/), let's do it:\n\n```bash\napt-get install augeas-lenses libaugeas0\napt-get install -t stretch python-certbot-apache\n```\n\nNow set up the SSL certificate:\n\n```bash\ncertbot --apache\n```\n\nThis will be really straightforward, the certbot mechanism will do all the work, answer his questions and you will have it!\n\nNow try to connect to https://www.yourdomain.whatever and that's it, SSL certificate up and running.\n\nNow, let's encrypt certificates needs to be renewed every 90 days, so the best is to automatize the check for renewal with a cronjob, open your crontab:\n\n```bash\ncrontab -e\n```\n\nand add this line (customize the time at your wish):\n\n```bash\n00 4 * * 1 /usr/bin/certbot renew \u003e\u003e /var/log/le-renewal.log\n```\n\nThat line means check, every monday at 04:00h if we need to renew our let's encrypt certificates, and if that's the case, renew them. Easy!\n\nWe have it, our server is almost complete, next story, HARDENING!\n\n## HARDENING (BONUS)\n\nKernel hardening and IPv6 disable, edit file /etc/sysctl.conf and add/edit:\n\n```bash\n# Turn on execshield\nkernel.exec-shield=1\nkernel.randomize_va_space=1\n...\n# Disable tcp timestamps\nnet.ipv4.tcp_timestamps = 0\n...\n#Uncomment the next two lines to enable Spoof protection (reverse-path filter)\n# Turn on Source Address Verification in all interfaces to\n# prevent some spoofing attacks\nnet.ipv4.conf.default.rp_filter=1\nnet.ipv4.conf.all.rp_filter=1\n...\n# Do not send ICMP redirects (we are not a router)\nnet.ipv4.conf.all.send_redirects = 0\n#\n# Do not accept IP source route packets (we are not a router)\nnet.ipv4.conf.all.accept_source_route = 0\n#net.ipv6.conf.all.accept_source_route = 0\n#\n# Log Martian Packets\nnet.ipv4.conf.all.log_martians = 1\n...\n# Disable IPv6\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\nnet.ipv6.conf.lo.disable_ipv6 = 1\nnet.ipv6.conf.eth0.disable_ipv6 = 1\n```\n\nNow open file /etc/default/ntp and make it look like this:\n\n```bash\nNTPD_OPTS='-4 -g'\n```\n\nReboot and enjoy!\n\n## HOME ROUTER SETTINGS\n\nIn order to be available on the internet, we'll need to open the specific ports for the specific services we want to offer to users, so, at home we have our fantastic Raspbian Server connected to the internet BEHIND our router, and even if the server is perfectly configured with his firewall, the router is, by default, completely closed for input connections, with the consequence of not letting no one reach our webpage on port 80 (http) or port 443 (https) because when we'll ask for it, our router will deny the access. This is actually good, if our router was completely open, probably our internet connection will be flooded in no time!\n\nSo, remember here that, for every port you'll open on your router, that means availability but exposure too, and it's because of it that we are trying to build a pretty secure server.\n\nEnough chat, in short we'll need to access our router settings, in general at ip 192.168.1.1 (but now always, check your router user manual), and in the firewall section, or in the port forwarding section (it depends on the router model), we'll need to open the port for our specific server, for example, if we want to run a web server, we'll need to forward port 80 to port 80 of our Raspbian (pointing to the internal LAN server ip), and the same for port 443.\nOr, if we want to access via SSH from internet, we'll need to forward input port 22 to port 22 of the server internal LAN ip.\n\nThe same for every other service you'll need.\n\nSo do it, and then test your services, if everything was correct, your server is actually AVAILABLE!!! Congratulation!\n\n## Your 80€ dedicated server (80DS)\n\nThis is the finish line, we've done it, but before we say goodbye, let's just take the final step, a step that a good sysadmin at least repeat once per week:\n\n1 - Check for updates and apply\n\n```bash\napt-get update \u0026\u0026 apt-get dist-upgrade\n```\n\n2 - Update rkhunter\n\n```bash\nrkhunter --propupd\n```\n\n3 - Update tripwire\n\n```bash\ntripwire --init\n```\n\n4 - Time to go, our Raspbian Server is rock n rollin'.\n\nFinally, it's time for the conclusions, we can say that this journey was not so easy, neither always comfortable, but damn, it was adventurous, it was not? So, like the simplest comparative between tourists and travelers, this one was indeed one of travelers, don't you think?\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd3cod3%2Fraspbian-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fd3cod3%2Fraspbian-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd3cod3%2Fraspbian-server/lists"}