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.
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.
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
apt is not supported. Also, if you are
using a different distribution, mentally replace
apt with your package manager
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
ipaddr hostname.tld hostname
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
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
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
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 "firstname.lastname@example.org" $ 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,
~/.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 18.104.22.168 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
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
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 email@example.com:P-Krebs/vimrc.git ~/.vim_runtime % sh ~/.vim_runtime/install_awesome_vimrc.sh
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!