Serving sites the lazy way


As someone who tinkers around with ideas randomly and want to show them off, it's nice to be able to have an easy and reliable way to host these services and websites.

Not all the time are these websites static, and even though they sometimes can be, I always have more fun writing a little server for them. As a first post It thought it be fun to write how to set up a system that allows you to be as lazy as possible when setting up a hosting solution.

Stack Setup

My set up is basically

Any of these are interchangeable allowing you to circumvent any vendor lock in. In fact I was able to change my VPS recently very easily.

My Actual Setup

With these components in mine, here's how I arranged mine.

For a VPS I went with digital ocean. Their prices are fine at 5 dollars and they are a reliable company, so your VPS won't randomly disappear one day. Another bonus is their one click droplet set up. They provide a ton of prebuilt images that kickstarts a server with software already installed and ready to go. Vultr is another great choice, you can check out serverhunter to search though a ton.

Dokku is an open source PaaS solution, built to be comparable to Heroku. I've used Heroku before so this was an easy choice. The gist of it is that it will host multiple projects for you on the same machine, each having its own container.

Before using dokku, make sure you purchased a domain name. You'll need it when initially setting up Dokku. Creating and deploying is as simple as setting up your initial domain then adding an app.

And on your local machine

Wow, your app is automagically built and deployed to the dokku instance under the domain www.my-website.mydomain.com. Dokku picked up your Dockerfile, built it, then deployed that container.

But, you say, why do I have to push to my source control, AND my server? It's 2020. Okay, just throw a CI/CD server in to do it for you. I mean, you do have one already to run your tests right?

Here's an example job I have for Gitlab to push it for me. You could even add a step in the script to ssh in and create the app if it doesn't exist already, making it even easier to deploy a new app

stages:
  - build
  - deploy

Build:
  image: golang:1.13.14-stretch
  stage: build
  script:
    - go get github.com/magefile/mage
    - go get github.com/golangci/golangci-lint/cmd/golangci-[email protected]
    - mage buildr

Deploy:
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H '165.22.107.199' >> ~/.ssh/known_hosts
  script:
    - git checkout master
    - git push ssh://[email protected]/blog
  only:
    refs:
      - master
    changes:
      - ./*.go
      - posts/public/*

Yes, you do need a private key on your CI server and yes you should make one just for this and yes you should protect it.

You quickly interject that I need to encrypt my sites with SSL, even if they don't require sensitive user input! You're right. Normally that could be a semi annoying precess, having to potentially set up a letsencrypt script in an nginx container, caddy, etc.

Here's how to create and use a cert in 4 lines.

ssh [email protected]
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku config:set --no-restart my-website DOKKU_LETSENCRYPT_EMAIL=[email protected]
dokku letsencrypt my-website

You now have a fully secure cert, none of that cloudflare flexible garbage that only encrypts halfway.

When all this is set up it lets you:

Where to go from here

I hope this enlightened on how easy it is to build a hosting for multiple sites. When you outgrow this set up and your server is crashing left and right, I recommend looking up: