Max Krebs

Setting up a VPS on Heroku

This is Part Two in my series of posts on moving from Heroku to Linode for web application hosting. You can read part one here.

Front Matter

The most intimidating part of setting up a self-managed hosting solution, for me, was figuring out exactly how to configure my server at an OS level. I am not a sys-admin (or at least I am not one full-time) and so it was scary thinking about managing a machine all from the command line. I had some experience with playing around with Ubuntu servers before for fun and for assignments in university, and I had fairly successfully setup hosting for a client’s Wordpress site on Linode before.

I am going to be upfront here: Linode’s documentation is inconsistent in quality. The most basic “Getting Started” and “Securing Your Server” guides are fine. They are easy to follow and descriptive, but the more you dig into guides for specific implementations, the quality takes a sharp decline. My experience is specifically with guides for setting up a Rails application, so you millage may vary. For example, the guides for setting up a basic LAMP stack I find to be better than the Rails stack. Because of this, after a certain point, I had to look elsewhere for meaningful instruction.

Ironically, I found that DigitalOcean, Linode’s main competition, has better generalized documentation for setting up servers and stacks. Because of this, I put together my own checklists based on a combination of Linode’s and DigitalOcean’s documentation. Those checklists are what I am basing these posts on, but I will link out to the relevant documentation as I go along in case you want more detail and/or want to fact check me.

Creating Your Server

I am going to assume that you have already gone through all the steps required to actually procure a Virtual Private Server on whatever hosting provider you prefer and have provisioned it with whatever flavor of Linux you are most comfortable with. I will be using Ubuntu 16.04 on Linode.

Getting Started

Read More

Once you server is created and the image is built, find your server’s IP address (in the Linode control panel it is under “Remote Access” and ssh in using the root password you created when deploying your server.

$ ssh root@ipaddr

The first thing you should do is make sure all your software is up to date by running:

% apt update && apt upgrade

Quick sidebar, if you are on an older version of Ubuntu, you will have to substitute apt with apt-get, since apt is not supported. Also, if you are using a different distribution, mentally replace apt with your package manager of choice.

Anyway, moving on, next you want to set the hostname for this machine. There are also two different ways to do this based on what version of Ubuntu you are running.

# < version 15
% echo "hostname" > /etc/hostname
% hostname -F /etc/hostname
# > 15
% hostnamectl set-hostname hostname

I am going to take one sidebar here and install zsh and vim, just to make my life easier.

% apt install vim zsh -y
% zsh

This is just a personal preference thing. Ubuntu ships with vi, but I am used to vim, and zsh is my shell of choice.

Now we want to add the hostname that we set before to the hosts file. Using your editor of choice (e.g. vim, nano, vi, emacs ect.) add this line to /etc/hosts.

ipaddr hostname.tld hostname

Replace ipaddr with your server’s IP Address, hostname is the hostname you just set before, and hostname.tld is the domain name you plan to use for your server. If you don’t know what it will be yet, just set it to hostname.com, you can always change it later.

The last step in the general setup is setting the timezone of your server.

% dpkg-reconfigure tzdata

Securing Your Server

Read More

This is an optional step, and I am not really sure how I feel about it myself, but you can configure Ubuntu to automatically update your packages by using unattended-upgrades.

% apt install unattended-upgrades -y

This will create a configuration file at /etc/apt/apt.conf.d/50unattended-upgrades. There are a lot of configuration options here, so I won’t go into detail about them, but you can find more info here.

Something you definitely want to do is create a non-root user. Everything we’ve done up until now has been as the root user, but for security purposes, we don’t want our web app, or any of the software we install in the next post, to be run as root. The user we create will also be used for deploying our Rails app using Capistrano for simplicity purposes. We also want them to be in the sudoers group, so they can run commands as the super user without compromising the security model.

% adduser user_name
% adduser user_name sudo

You will be prompted to set the Unix password for that user, so now you can login over ssh with ssh user_name@ipaddr and using the password you just set.

For this next step, you will want to run the next two commands from your local machine, so logout of your server using exit. I am also going to assume you are using a Mac (because that seems to be the most common machine in Rails development). We are going to create an ssh key and upload it to your new server, because it is more secure than logging in with a password, and because I get sick of constantly typing in passwords. Because they are better people than I am, Github has much better documentation around checking for existing ssh keys and generating them, and they even have guides for Windows.

For our purposes, we are going to use a package called ssh-copy-id to upload our ssh public key. I believe this comes packaged with some distros of Linux, but for macOS, you can install it using Homebrew.

$ brew update
$ brew install ssh-copy-id

If you know you already have generated an SSH key on your local machine, you can go ahead and skip this next step, as it will potentially overwrite existing keys.

$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
$ eval "$(ssh-agent -s)"
$ ssh-add -K ~/.ssh/id_rsa

This will walk you through the steps to adding an ssh key. It should be pretty straightforward, just go with the defaults and set a strong password.

Whether you had to create one just now, or you already had an existing SSH key, upload it to your Linode server using ssh-copy-id.

$ ssh-copy-id user_name@ipaddr

One more optional step that I like to take for convenience sake is to add your server to your SSH config file on your local machine. This will allow your to login without having to type out the entire ssh command every time. To do this, open ~/.ssh/config with your favorite text editor (you may have to create this file first) and add an entry that is formatted like this:

Host hostname
  HostName ipaddr
  User user_name

For example, the config entry for this website on my local machine looks like this.

Host sadrobot
  HostName 8.8.8.8
  User deploy

Go ahead and log in to your server with your new fancy non-root user. If you did both of those steps, you should be able to just run ssh hostname and log in successfully.

A couple of last security settings to configure. I always disable root log in over ssh to force me to use my non-root user. This can be done by setting PermitRootLogin no in /etc/ssh/sshd_config. That is a long file, so to find the relevant section, search for # Authentication. You can also prevent anyone from SSH’ing into your server using a password in the same file for extra security. The downside is that you can only log in from a machine that has your SSH key on it. So if you switch machines or overwrite that SSH key, you are SOL.

Regardless, restart the SSH service to apply the changes to the conf file.

% sudo service ssh restart

Fussy Customizations

These last couple of items are just customizations that I do to make life on the server a little more bearable and more like my development machine. Feel free to steal them or adapt them to suit your preferences.

Switch the default shell to zsh.

% chsh -s $(command -v zsh)

Set the zsh prompt to be more useful.

% echo "autoload -Uz promptinit" > .zshrc
% echo "promptinit" >> .zshrc
% echo "prompt redhat" >> .zshrc

Add a sanity alias for ls, because I hate the default ls behavior.

% echo "alias ls='ls -alph'" >> .zshrc

Alias vim so I don’t accidentally open vi when I meant to open vim.

% echo "alias vi='vim'" >> .zshrc

Reload zsh config.

% source .zshrc

Download and use my VimRC configuration. You might have to install git first for this one.

% git clone git@github.com:P-Krebs/vimrc.git ~/.vim_runtime
% sh ~/.vim_runtime/install_awesome_vimrc.sh

What’s next?

Phew. I am sure that was a lot. Hopefully that wasn’t too intimidating. I think this should leave you with some sensible defaults for hosting and basic security on your server. Of course, I could be way off base here, but if I am doing something wrong, I am sure the internet will tell me.

In the next part, we are going to actually do the interesting stuff: deploying your Rails app to your newly created server! Woo!