Moving From Shared Hosting to a VPS

It was time to get off shared hosting. I had been using the same shared hosting service for many years, and for the most part it worked just fine. The service was easy and fast - enough - and the hosting cPanel had lots of nifty widgets.

But I was also stuck with whatever software versions the hosting provider had installed. MySQL and PHP were well behind the current stable releases, and great new language features I wanted to use were not available in production. At the same time, updates that I did not ask for would roll out and unexpectedly break things before I could regression test. It was time to move on and graduate to my own Virtual Private Server (VPS).

Jumping ahead to the results: I am happy with my VPS, the performance, and the management. A win-win. Page load speeds improved significantly. The page source dropped from around the 300ms range to about 70ms, and total load times are averaging about a third of what it used to be.

Going back to the beginning, after enough quality Google time on how to do this I chose this approach:

VPS Server: DigitalOcean DigitalOcean provides fast inexpensive servers across many global data centers, starting at $5/month (in 2016). They have grown quickly to become popular for high performance, quick and easy VPS's when you don't need the complexity of Amazon Web Services.

Server Management: ServerPilot Do you really need server management software to run a VPS? No, not really. If you are actually considering a VPS you probably know enough about servers and using the command line that you can realistically administer your own server. However, you'll need to stay on top of keeping the servers patched and updated, and for each web application you deploy you'll need to be comfortable with managing your web server configuration. ServerPilot helps nicely with all of that and a few more things to boot. In a neat trick it is all done remotely (not on your server) without a huge server side install (just a little server side install).

ServerPilot also completes your initial server configuration and locks it down (at least according to their standards, which are probably higher than my own). Other features include being able to run multiple versions of PHP for different applications, and they also configure Nginx as the public facing web server while using Apache on the back end so your htaccess rules are easy to manage.

ServerPilot has a basic free version, which is sufficient for my needs.

CDN: CloudFlare On shared hosting if your website gets too much traffic the host might just throttle your traffic to not overload multiple customers, but on a VPS you are all alone and too much traffic might just overwhelm the server. Too much traffic is not an issue for my sites, but it would be nice to unburden the server a bit on the off chance there is a bump in traffic. CloudFlare does this elegantly by caching most of your assets (JS, CSS, images, files) across their global Content Distribution Network so the user gets to experience a nice boost in speed and your server is saved from having to dish up all those extra files. CloudFlare can also optionally minify your JS and CSS files, helps filter some known threats (not all), and can help with a DDoS attack.

CloudFlare has a basic free version, which is sufficient for my needs.

Deployment: Git I am using Git for version control, and using it to deploy simple websites is easy.

Putting it all Together

Saving you a bit of the trial and error experience, here is how it all came together.

One: Start with ServerPilot

Create a ServerPilot account and select the free version. You cannot use ServerPilot if you already have a provisioned server as ServerPilot needs a clean vanilla server without PHP or MySQL to run their configuration scripts.

Two: Create a DigitalOcean Droplet

Create a DigitalOcean account. I initially used PayPal for billing, but later learned I could not setup automatic payments without manually refilling my PayPal credit with DigitalOcean. I would suggest just using a credit card.

Follow the instructions from ServerPilot on how to provision the DigitalOcean Ubuntu server, called a Droplet. I selected the least expensive $5/month option in a data center in my region. This option has 512MB RAM, 20GB SSD, 1000GB data transfer - more than enough for our multiple sites. Scaling up (or down) is easy, so I thought I would start here.

You'll be asked to name your server, I selected app1 with the thought that someday I may end up with more application servers, database servers, and load balancers, each using a consistent naming convention. Or maybe I won't ever need all that.

When the Droplet is ready (which takes about a minute to build), DigitalOcean will show you your new static server IP address and root password. Make sure to securely save that information as you'll need it in your next step.

Three: Back to ServerPilot

Now go back to ServerPilot and click Servers > Connect Server. Enter the IP address and root password provided by DigitalOcean. ServerPilot will also create a new user account on your server called (originally enough) serverpilot. This user will own and run your applications, not root. Enter a new password for this serverpilot user. Click connect and wait a moment.

ServerPilot will verify it can connect to your server, installs a small agent to manage your server, then hardens the server by closing some ports, makes sure it's patched up, and installs PHP and MySQL.

Four: Ready for SSH

ServerPilot recommends just using the serverpilot user password you supplied in step three when you remote in via SSH. However, I didn't want to have to dig up that password each time I connected so I added my SSH public key to my server Droplet.

I had already previously generated my RSA key on my Mac, so I copied the contents of ~/.ssh/id_rsa.pub to my clip board, SSH'd into the new server, CD'd to ~/.ssh/, opened the authorized_keys file and pasted in my public key and saved.

Five: Create an Application

When you want to create a new web application, start with ServerPilot. From the ServerPilot console, select Apps > Create App. Then enter a name for the application, the domain (without the www), check if it is WordPress (not in my case), select which version of PHP to use, and then select the server you created at DigitalOcean. The user should default to the serverpilot user you had initially created. When you click Create App, ServerPilot automatically creates the required directories, configures the web server to direct requests for your domain (both www and non-www) to the new application folder that it creates for you.

By default, ServerPilot places all applications you create in ~/apps/APP_NAME/ as the project root, and it then points the web root to ~/apps/APP_NAME/public/. This was perfect in my case, as my applications already were set up that way.

If you need a MySQL database, you can now create a DB from the ServerPilot console by clicking into the application project name, and then clicking the Database tab. Enter the databae name and user, and add a password or save the generated password. ServerPilot will then create the DB and grant all privileges on it.

Using your DigitalOcean IP you should be able to get to your new application by going to http://<ip_address> and see a default HTML page provided by ServerPilot. Your server build is done at this point, but getting your project out there is the next step, using Git.

Six: Setup Git Deployment

My Git deployment model is simple. I have a Git remote in my production application project folder, but since you cannot push to another working remote, I have a Git bare repo in my user home as an intermediary. This bare repo has a post-receive hook script that pulls from the bare repo to the production project repo.

To setup that, SSH into the server and create a directory to contain the various bare repos for your projects. From the user home:

mkdir gitprojects
cd gitprojects
git init --bare APP_NAME.git

Where APP_NAME is your project name, or whatever you want to call this. Now go to your new project root and create a normal repo there:

cd ~/app/APP_NAME
git init

Now add the bare repo as a remote called "origin".

git remote add origin ~/gitprojects/APP_NAME.git

With this in place, add the hook to the bare repo:

cd ~/gitprojects/APP_NAME.git/hooks/
nano post-receive

In the nano editor, paste the script like this, and edit the APP_NAME (GIT_DIR is left as is, it's an environment variable):

#!/bin/sh
# Moving git changes to production
echo "Deploying changes to production"
cd ~/apps/APP_NAME || exit
unset GIT_DIR

# Git pull, but overwrites any local uncommitted changes
git fetch origin
git reset --hard origin/master

Now our Git bare repo is primed to have the production repo pull the most recent changes.

Seven: Build DB and Push

If you have a database build SQL script, you can run the script from your local computer:

ssh serverpilot@IP_ADDRESS mysql -u DATABASE_USERNAME -pPASSWORD DATABASE_NAME < ~/Desktop/SCRIPT_NAME.sql

Where you replace everything caps with your own values. Note that the password is indeed jammed against the -p switch without a space (or better yet, leave the -pPASSWORD out and you will be prompted to enter it). This statement assumes the script is on your desktop, so edit the path as needed.

Now add the bare repo as a remote to your local project:

git remote add production serverpilot@IP_ADDRESS:gitprojects/APP_NAME.git

To deploy, just push to the production remote your master branch.

Eight: DNS Changes

This requires patience. No matter who is your domain registrar, you can have your DNS handled by someone else. CloudFlare offers a fast DNS service (free), and they also offer some extra features you can read about on their website. To get started, go to CloudFlare and sign up for a free account. You will be prompted to enter your domain. After they scan and import your existing DNS records, you can delete nearly all entries. All you will need (if you don't care about email and only care about resolving your domain name for HTTP) are two A records.

You should have at least two entries like this:

TypeNameValueTTLStatus
ADOMAIN_NAMEIP_ADDRESSAutomaticOrange
AwwwIP_ADDRESSAutomaticOrange

Next copy the two CloudFlare nameservers and update your domain registration. Go to your registrar and in your zone editor and add the CloudFlare nameservers.

For an existing site, this may take up to 48 hours to fully propagate, so be patient.

Nine: All Done

All in all this was much easier than I expected, and with the server already setup adding a new web project is quite easy. Performance has been impressive, and I am enjoying being able to use the latest stable language releases.

What Do You Think?

* Required