How To Set Up Your Linode For Maximum Awesomeness » Feross.org


Feross Aboukhadijeh is a computer security researcher, teacher, web developer, designer, long distance runner, gamer, music lover, and builder of websites that (sometimes) go viral.



 
 

Related Links:

Content

Cached Text (at the time of saving)


So, you followed the advice in my Linode Hosting Review and decided to host your website with Linode. Excellent choice!
But, if you’re new to the command line (perhaps you are familiar with CPanel or Plesk?) or you’ve never setup a server from scratch before, you may be wondering what dark magic vudu is required to get up and running.
Well, you’ve come to the right place!
The Command Line Is Hard (…at first)
I’ve set up at least five new servers with Linode and each time I complete the ritual, I learn new incantations that make the Linux angels sing. I’m pretty happy with my current recipe.
Setting up a new server can be confusing, so using a tutorial like this one is a good idea the first time you do it.
Tutorial: How To Set Up Your Linode
In this guide, I will demonstrate how to set up a fresh Ubuntu server from scratch, update everything, install essential software, lock down the server to make it more resilient against basic attacks and denial-of-service, improve server stability, and finally install common software like Nginx, MySQL, Python, Node, etc.
A Note About This Guide
I originally compiled this guide as a .txt file of notes for myself, but decided to share it in case anyone finds it useful. If you’re looking for something straight from the horse’s mouth, Linode offers guides that cover how to set up a new server, but some of the info is out of date.
Let’s get started!
Provision a New Linode
First, you need to provision a new Linode. Using Linode’s web UI, it’s quite easy. Select your desired Linode size. If you’re unsure, choose the smallest size. You can always resize it later. Select “Ubuntu 12.04 LTS” as your OS. You’ll be asked to create a password for the root user.
After a few minutes, your server will be ready. Now, it’s time to connect to it!
Connecting to Your Server
First, open Terminal on your Mac. On Windows, you’ll want to use putty, since Windows doesn’t come with a proper terminal.
To connect to your server, type this into your terminal and hit Enter:
ssh root@
Of course, replace with your Linode’s actual IP address, which you can find on the “Remote Access” tab in the control panel.
This command launches the SSH program and asks it to connect to your server with the username root, which is the default Ubuntu user. You will be prompted for the root password you created earlier.
Basic Ubuntu Setup
To set up your new server, execute the following commands.
Set the hostname
Set the server hostname. Any name will do — just make it memorable. In this example, I chose “future”.
echo"future" > /etc/hostname hostname -F /etc/hostname
Let’s verify that it was set correctly:
Set the fully-qualified domain name
Set the FQDN of the server by making sure the following text is in the /etc/hosts file:
127.0.0.1 localhost.localdomain localhost 127.0.1.1 ubuntu future..net future
It is useful if you add an A record that points from some domain you control (in this case I used “future.
.net”) to your server IP address. This way, you can easily reference the IP address of your server when you SSH into it, like so:
ssh future..net
If you’re curious, you can read more about the /etc/hosts file.
Set the time
Set the server timezone:
dpkg-reconfigure tzdata
Verify that the date is correct:
Update the server
Check for updates and install:
aptitude update aptitude upgrade
Basic Security Setup
Create a new user
The root user has a lot of power on your server. It has the power to read, write, and execute any file on the server. It’s not advisable to use root for day-to-day server tasks. For those tasks, use a user account with normal permissions.
Add a new user:
adduser
Add the user to the sudoers group:
usermod -a -G sudo
This allows you to perform actions that require root priveledge by simply prepending the word sudo to the command. You may need to type your password to confirm your intentions.
Login with new user:
exit ssh @
Set up SSH keys
SSH keys allow you to login to your server without a password. For this reason, you’ll want to set this up on your main computer. SSH keys are very convenient and don’t make your server any less secure.
If you’ve already generated SSH keys before (maybe for your GitHub account?), then you can skip the next step.
Generate SSH keys
Generate SSH keys with the following command:
ssh-keygen -t rsa -C "@.org"
When prompted, just accept the default locations for the keyfiles. Also, you’ll want to choose a nice, strong password for your key. If you’re on Mac, you can save the password in your keychain so you won’t have to type it in repeatedly.
Now you should have two keyfiles, one public and one private, in the ~/.ssh folder.
If you want more information about SSH keys, GitHub has a great guide.
Copy the public key to server
Now, copy your public key to the server. This tells the server that it should allow anyone with your private key to access the server. This is why we set a password on the private key earlier.
From your local machine, run:
scp ~/.ssh/id_rsa.pub @:
On your Linode, run:
mkdir .ssh mv id_rsa.pub .ssh/authorized_keys chown -R : .ssh chmod 700 .ssh chmod 600 .ssh/authorized_keys
Disable root login
Since all Ubuntu servers have a root user and most servers run SSH on port 22 (the default), criminals often try to guess the root password using automated attacks that try many thousands of passwords in a very short time. This is a common attack that nearly all servers will face.
We can make things substantially more difficult for automated attackers by preventing the root user from logging in over SSH and changing our SSH port to something less obvious. This will prevent the vast majority of automatic attacks.
Disable remote root login and change SSH port:
sudo nano /etc/ssh/sshd_config Set "PermitRootLogin no" Set "Port 44444" sudo service ssh restart
In this example, we changed the port to 44444. So, now to connect to the server, we need to run:
ssh @future..net -p 44444
Advanced Security Setup
Prevent repeated login attempts with Fail2Ban
Fail2Ban is a security tool to prevent dictionary attacks. It works by monitoring important services (like SSH) and blocking IP addresses which appear to be malicious (i.e. they are failing too many login attempts because they are guessing passwords).
Install Fail2Ban:
sudo aptitude install fail2ban
Configure Fail2Ban:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local sudo nano /etc/fail2ban/jail.local Set "enabled" to "true" in [ssh-ddos] section Set "port" to "44444" in [ssh] and [ssh-ddos] sections
Restart to put new Fail2Ban rules into effect:
sudo service fail2ban restart
Add a firewall
We’ll add an iptables firewall to the server that blocks all incoming and outgoing connections except for ones that we manually approve. This way, only the services we choose can communicate with the internet.
The firewall has no rules yet. Check it out:
Setup firewall rules in a new file:
sudo nano /etc/iptables.firewall.rules
The following firewall rules will allow HTTP (80), HTTPS (443), SSH (44444), ping, and some other ports for testing. All other ports will be blocked.
Paste the following into /etc/iptables.firewall.rules:
*filter # Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0 -A INPUT -i lo -j ACCEPT -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT # Accept all established inbound connections -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow all outbound traffic - you can modify this to only allow certain traffic -A OUTPUT -j ACCEPT # Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL). -A INPUT -p tcp --dport 80 -j ACCEPT -A INPUT -p tcp --dport 443 -j ACCEPT # Allow ports for testing -A INPUT -p tcp --dport 8080:8090 -j ACCEPT # Allow ports for MOSH (mobile shell) -A INPUT -p udp --dport 60000:61000 -j ACCEPT # Allow SSH connections# The -dport number should be the same port number you set in sshd_config -A INPUT -p tcp -m state --state NEW --dport 44444 -j ACCEPT # Allow ping -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT # Log iptables denied calls -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 # Reject all other inbound - default deny unless explicitly allowed policy -A INPUT -j REJECT -A FORWARD -j REJECT COMMIT
Activate the firewall rules now:
sudo iptables-restore < /etc/iptables.firewall.rules
Verify that the rules were installed correctly:
Activate the firewall rules on startup:
sudo nano /etc/network/if-pre-up.d/firewall
Paste this into the /etc/network/if-pre-up.d/firewall file:
#!/bin/sh /sbin/iptables-restore < /etc/iptables.firewall.rules
Set the script permissions:
sudo chmod +x /etc/network/if-pre-up.d/firewall
Get an email anytime a user uses sudo
I like to get an email anytime someone uses sudo. This way, I have a “paper trail” of sorts, in case anything bad happens to my server. I use a Gmail filter to file these away and only look at them occasionally.
Create a new file for the sudo settings:
sudo nano /etc/sudoers.d/my_sudoers
Add this to the file:
Defaults mail_always Defaults mailto="feross@feross.org"
This is isn’t mentioned anywhere on the web, as far as I know, but in order for the “mail on sudo use” feature to work, you need to install an MTA server. sendmail is a good choice:
sudo aptitude install sendmail
Now, you should get an email anytime someone uses sudo!
Improve Server Stability
VPS servers can easily run out of memory during traffic spikes.
For example, most people don’t change Apache’s default setting which allows 150 clients to connect simultaneously. This is way too large a number for a typical VPS server. Let’s do the math. Apache’s processes are typically ~25MB each. If our website gets a temporary traffic spike and 150 processes launch, we’ll need 3750MB of memory on our server. If we don’t have this much (and we don’t!), then the OS will grind to a halt as it swaps memory to disk to make room for new processes, but then immediately swaps the stuff on disk back into memory.
No useful work gets done once swapping happens. The server can be stuck in this state for hours, even after the traffic rush has subsided. During this time, very few web requests will get serviced.
It’s very important to configure your applications so memory swapping does not occur. If you use Apache, you should set MaxClients to something more reasonable like 20 or 30. There are many other optimizations to make, too. Linode has a Library article with optimizations for Apache, MySQL, and PHP.
Reboot server on out-of-memory condition
Still, in cases where something goes awry, it is good to automatically reboot your server when it runs out of memory. This will cause a minute or two of downtime, but it’s better than languishing in the swapping state for potentially hours or days.
You can leverage a couple kernel settings and Lassie to make this happen on Linode.
Adding the following two lines to your /etc/sysctl.conf will cause it to reboot after running out of memory:
vm.panic_on_oom=1 kernel.panic=10
The vm.panic_on_oom=1 line enables panic on OOM; the kernel.panic=10 line tells the kernel to reboot ten seconds after panicking.
Read more about rebooting when out of memory on Linode’s wiki.
At this point, you have a pretty nice server setup. Congrats! But, your server still doesn’t do anything useful. Let’s install some software.
Install Useful Server Software
Install a compiler
A compiler is often required to install Python packages and other software, so let’s just install one up-front.
aptitude install build-essential
Install MySQL
Install MySQL:
sudo aptitude install mysql-server libmysqlclient-dev
Set root password when prompt asks you.
Verify that MySQL is running.
sudo netstat -tap | grep mysql
For connecting to MySQL, instead of the usual PHPMyAdmin, I now use Sequel Pro, a free app for Mac.
Install Python
Install Python environment:
sudo aptitude install python-pip python-dev sudo pip install virtualenv
This creates a global “pip” command to install Python packages. Don’t use it, because packages will be installed globally. Instead, use virtualenv.
Create a new virtualenv Python environment with:
distribute
Switch to the new environment with:
cd source bin/activate
Note that the name of your environment is added to your command prompt.
Install Python packages with “pip” inside of virtualenv:
pip search pip install
This is the best Python workflow that I’ve found. Let me know if you know of a better way to manage Python packages and Python installations.
Install Nginx
sudo aptitude install nginx
Install Apache
sudo aptitude install apache2
Install PHP5
sudo aptitude install php5 libapache2-mod-php5 php5-mysql sudo service apache2 restartq
Install Node.js
sudo apt-get install python-software-properties sudo add-apt-repository ppa:chris-lea/node.js sudo apt-get update sudo apt-get install nodejs npm nodejs-dev
Linode rocks!
If, after reading this, you want to sign up for Linode, use this link and I’ll get a couple weeks of free hosting. If you prefer not to, here’s the plain link: Linode.com
Happy hacking!
(If you liked this, you might like Freedom of Speech on the Internet.)
Discussion, links, and tweets
Share this article with your friends:
Thoughts on free willcomments powered by