Host a website in your home with SSL

Lately I've been managing quite a few servers across the globe for my video saas solution, and I've been constantly trying to find ways to minimize the cost of the whole infrastructure.

Well guess what, in order to run a site, the only thing you'll have to pay is only the domain! Sounds hillarious right?

Other costs you might have are the cost of electricity in order to run your server 24/7 but you can minimize these also by running a low power single board computer like a Raspberry Pi and the home/office internet connection with a high upload rate (minimum 5-10 MBit).

With this setup you'll ditch the greedy dynamic dns providers you hate paying 20-30 euros per year and still manage to have a better service!


1. Register a domain

hover
I use hover and also recommend the privacy-first NJALLA as they're well respected registrars known not to poach your domain (like Namecheap and GoDaddy) right after you've searched it!


2. Get a free nameserver for your domain

Lately I've been struggling to find the best solution for dns answers based on the user's location and there are quite a few great services out there. Our setup is a little primitive for these stuff so what we need is a simple, good, robust and fast cheap free solution in order for our nameserver to respond almost instantly in whatever part of the world. Cloudflare ticks all the boxes for that matter especially performance-wise.

I'd strongly recommend you to use Cloudflare -or some other- and not host your own dns even if you have static IP in home as it's prone to ddos attacks.

Add your domain to cloudflare.
cloudflarecreatenew
Make sure status (in overview tab) is paused if you don't want your traffic to passthrough cloudflare's servers.
Cloudflare
Add a new record. At this point it doesn't matter to point to your IP address because it will be updated by our cron job (see part 5) and be sure to select the absolutely minimum TTL (that is 2 minutes) because you don't want to reboot your modem and your dns still sending your old IP.
Cloudflare2
The entry should be something like this. Again make sure the cloud is grey to direct the traffic directly to your server.
Cloudflare3


3. Create a webserver

If you already have a webserver skip this section. If you don't I'd recommend the use of EasyEngine that'll do all the hard work needed for a wordpress installation. Nginx, MySQL, PHP 7, SSL from let's encrypt, even do caching for you!

Also I'd highly suggest using a CDN solution in order to minimize traffic usage and save your server's resources. Most simply by enabling the Cloudflare's caching solution and enjoy SSL too.

Hit wget -qO ee rt.cx/ee && sudo bash ee on a freshly baked Ubuntu server (16.04 or later).
easyengine1

Then you only have to run sudo ee site create example.com --wp but also make sure if you need caching with additional parameters like --wpsc for wp super cache and --w3tc for w3 total cache.
easyengine2-1

And that's it! That's all for your server setup. Took 3-4 minutes and you hit 2 commands and enter some details. Make sure you write down your passwords.
easyengine3


4. Update your dns records when your IP is changed

Create a new file in /etc/myddns/cloudflare-update-record.sh with this script

#!/bin/bash

# CHANGE THESE
auth_email="<your email used to signup to cloudflare>"
auth_key="API_KEY" # found in cloudflare account settings
zone_name="yourdoman.com" # your TLD or Top Level Domain
record_name="yourdoman.com" # your record which is probably the same as above

# MAYBE CHANGE THESE
ip=$(curl -s http://ipv4.icanhazip.com)
ip_file="ip.txt"
id_file="cloudflare.ids"
log_file="cloudflare.log"

# LOGGER
log() {
    if [ "$1" ]; then
        echo -e "[$(date)] - $1" >> $log_file
    fi
}

# SCRIPT START
#log "Check Initiated"

if [ -f $ip_file ]; then
    old_ip=$(cat $ip_file)
	if [ $ip = $old_ip ]; then
#	  log "IP did not change."
	exit 0
fi
    if [ $ip == $old_ip ]; then
        echo "IP has not changed."
        exit 0
    fi
fi

if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
    zone_identifier=$(head -1 $id_file)
    record_identifier=$(tail -1 $id_file)
else
    zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
    record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json"  | grep -Po '(?<="id":")[^"]*')
    echo "$zone_identifier" > $id_file
    echo "$record_identifier" >> $id_file
fi

update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"name\":\"$record_name\",\"content\":\"$ip\"}")

if [[ $update == *"\"success\":false"* ]]; then
    message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
    log "$message"
    echo -e "$message"
    exit 1
else
    message="IP changed to: $ip"
    echo "$ip" > $ip_file
    log "$message"
    echo "$message"
fi

Then make it check your IP every minute and update the dns record if necessary using crontab

Hit crontab -e in an non-root account and add this line:
*/1 * * * * /bin/sh /etc/myddns/cloudflare-update-record.sh
If you want to change the interval to your liking I'd suggest help from crontab.guru.

Your crontab should be like this now:
crontab

After a minute passes you should head to your website and see the result yourself! A free hosted website on your home using barely few euros. Now you can continue your daily routine even if your father decides to reboot the modem for no reason because his facebook tablet is slow and rest assured your server will update his dns in a minute (at most!).

If you are not seeing your website live probably you have not configured port forwarding which will describe in the next step.


5. Do port forwarding

Your server should have static IP (or fixed IP as they say) and forwarded to it the ports 80 and 443 (if you want the SSL be managed by you).


6. Make it rain

After all this setup you are now ready to enter the blogging or whatever world you're getting into. Populate your new blog and announce it on search engines.

If your traffic starts to rise, use a CDN solution as we described (part 3).

Have fun with your server!