6 Answers
6

David's answer is a good baseline of the general principles of server hardening. As David indicated, this is a huge question. The specific techniques you take could depend highly on your environment and how your server will be used. Warning, this can take a lot of work in a test environment to build out and get done right. Followed by a lot of work to integrate into your production environment, and more importantly, business process.

First, however, check to see if your organization has any hardening policies, as those might be the most directly relevant. If not, depending on your role, this might be a great time to build them out. I would also recommend tackling each component separately from the bottom up.

The L
There are lots of good guides available to help you out. This list may or may not help you depending on your distribution.

The P
This runs headlong into the whole idea of Secure Programming Practices, which is an entire discipline of its own. SANS and OWASP have a ridiculous amount of information on the subject, so I won't try to replicate it here. I will focus on the runtime configuration and let your developers worry about the rest. Sometimes the 'P' in LAMP refers to Perl, but usually PHP. I am assuming the latter.

It's so easy to forget the firewall. I heard of someone who built a web server for a website and even went as far as hacking the TCP/IP stack to throw away traffic that wasn't port 80. Another thing that gets overlooked is unnecessary services - if it doesn't need to be turned on, turn it off.
– Aaron MasonSep 13 '13 at 1:35

4

@AaronMason: Congratulations! You have a successful anecdote. Let's remember that your specific situation worked out well, but let's hope future readers understand your unusual environment. In the general case this advice is pretty dangerous.
– Scott PackSep 16 '13 at 4:37

You've asked a question that is, quite frankly, worthy of a few books on the topic. But there are some general basic guidelines that work well:

Keep Updated. This means the OS, all services, and ESPECIALLY all webapps you're running.

Disable any unneeded services, limit those that are needed to the minimum exposure (if you're not remotely connecting to MySQL, then don't have it listening on TCP), and run a host-based firewall. (If it's strictly LAMP, you should be good with 80 and 443, but maybe SSH as well for administration.))

Use strong passwords. Better yet, if you use SSH, use only key-based auth.

Make sure you're not logging in as root. Log in as users and use su & sudo.

While it doesn't make things more secure, you should run tools like logwatch so you're aware of what's happening on your server.

Firewall

A nice approach is to not allow any traffic to begin with, then only
open what you need, as you need it. This results in opening the
minimum ports/ips to make things work and that minimises your
exposure.

For a LAMP server you may only need to open up ports for
http/https to the world and ssh for sysadmins.

Make sure things like ipv6 traffic is locked down if not using it

AWS provides security groups, linux has iptables as well as plenty of packages to choose
from.

SSH & Users

No password for ssh access (use private key)

Don't allow root to ssh (the appropriate users should ssh in, then su or sudo)

ssh on non-standard port (this can be useful to make sure you're not low hanging fruit, and keep a lot of the annoying traffic away, but won't do much for security, particularly by itself)

lock down ssh to only the ip range your require (a big range is better than no range)

Database

Sanitise user data

Parameterize queries

Consider abstracting the DB to it's own machine. This separation can make it more difficult for an attacker to get to your web stack and vice versa.

Like any software keeping up to date is important.

A user for each purpose. When creating users start with no privileges and add only the ones they need to preform their role. Having separate users for different applications (or sometimes distinct parts of applications) will help reduce the benefit an attacker has should they compromise any one account. Also be careful with special privileges like GRANT which shouldn't be assigned lightly.

Having a policy to change passwords periodically is a good idea. If you're worried about the amount of effort required remember less frequent is better than never.

Understand password encryption. Salt passwords. Don't use md5!

Software

Keep software up to date (os, web server, scripting language, CMS). Lots of people out there will scan for known vulnerabilities in old (unpatched) versions

Remove any software you don't need (ideally don't keep package required to compile software on production servers, it's better to pre-compile software and make it available as a package to your production machines)

Make sure file permissions are locked down (especially for things like user uploads and config files)

Password protect admin area for CMS at the web server level (http authentication can sit in-front of a vulnerabile CMS and help block access, which is a good way to prevent attacks)

Use SSL for admin area's and other sensitive data

Automate the management of your servers and infrastructure (Something like Puppet, Chef or SaltStack. If using AWS CloudFormation too). This will help you patch things across lots of servers, and cut down scenarios like fixing permissions on Server A but forgetting to do it on Server B

Where possible don't give away the particular version of your CMS, PHP or WebServer. While obscuring this information isn't security there are many people out there scaning for particular versions of different software and the less information you freely give out the more an attacker has to work. This is a good way to make sure you're not one of the low hanging fruit. Of course this will do nothing to someone who wants to spend a bit more effort getting in

Adding to what David suggests, the more modular your installation, by that I mean restricting access to certain users/groups created specifically for one task and limiting their scope, the more secure your LAMP stack: An example of this is to have an Apache user for Apache files/folders with permissions set accordingly and not in any groups that can access critical system files/folders. A user that can access the MySql tables that are associated with your websites that you are going to serve and only those tables. Additionally, you can restrict their access to give the minimum amount of access from a PHP call. Also, make sure that the MySQL username used/exposed through the PHP file is not the same username or password used for another user.

What this means: if either the apache user or the MySql user are compromised, they can't do any harm outside the scope of the folder(s) apache has access to (in the case of the apache user) and outside the table(s)/database(s) (in the case of the user for the MySQL database).

If somehow the MySQL user were to be compromised, they couldn't, for instance, access the database and drop all the databases from MySQL and ruin all your data. They MIGHT under some circumstances be able to drop tables or insert information in some tables in an isolated database, which is why it is important to only grant table access where it is absolutely necessary and only grant the permissions needed...if you don't need to have drop tables privileges or update privileges, then don't give them to that user.

Also, if for some reason your administrative account username and password are found out for MySQL, if you use a different username than any usernames on your system, they have to first break the security of your system before getting into your database to do damage. The same holds true about the apache user and access to files.

Example time!
I'm going to give a system example to sort of simplify the idea.

say you have users on your system (root should be disabled for security through something like umod -l or passwd -l, etc.):
john, barney, terence, and lisa.

you could create a user in MySQL with the name of bigbird (make sure you use a hashed password). Bigbird only has select privileges and update privileges, but not drop or create, and certainly not .
Additionally, you create another administrative MySQL user with the name garfield for working on the MySQL database and you delete the root user from the MySQL database so that it can't be comprimised. garfield has been granted . privileges throughout MySQL (effectively, this is just renaming root).

now, you create either an apache group or a user and we'll call it apweb2. Appweb2 is not a member of other groups, and all files/folders for apache are stored in /home/apweb2/. Each virtual host would have its own subfolder and each of these hosts would have document root set to that subfolder. Symlinks would be disabled in order to not accidentally provide access to the rest of the system.

Also, you can restrict ssh access to certain users only (or certain groups, I like to put them in the ssh group, and make that the only thing able to use ssh).

Also, you can choose which users have sudo privileges to restrict things even further. Another step you can take it further is to make any ssh users not able to sudo, you could create special users that can use sudo that can't use ssh, so that once you ssh in, you have to log into another user to have access to sudo.

So, by modularizing each segment, if one is compromised, the whole stack won't be compromised and you can remedy the 1 problem instead of having to start all over again from scratch.

Welcome to Server Fault! Generally we like answers on the site to be able to stand on their own - Links are great, but if that link ever breaks the answer should have enough information to still be helpful. Please consider editing your answer to include more detail. See the FAQ for more info.
– slmAug 10 '13 at 12:43

At the present time, do not neglect container virtualization, namely Docker, systemd-nspawn and the mechanisms of container virtualization on which they are built (namespaces, cgroups).
Using container virtualization allows you to isolate processes, for example, if one of the services is compromised, an attacker will not gain access to other services.

In the case of LAMP, it is possible to use, for example, four Docker containers with SSH-server, Apache, MySQL, PHP-FPM/Python/Perl/etc.