Conrad Bailey

How To Make This Website - Part 3: Basic Website and Deployment

What's a Website?

I sort of tried to answer this back in Part 1, but we've come quite far since then. We've established a host that runs a server and we've given it a domain name. The only thing left before it's an adult website is to add some content! That content could be html pages, css stylesheets, image resources, scripts, or whatever your designs require.

Adding Content

File Structure

Okay, so all of that stuff I mentioned has to go somewhere, and it starts with the root of your website. The root of your website is the top-most directory in which your content is stored. Various operating systems and servers will set this location at a variety of default places. After a little Googling I settled on /srv/domainname (/srv/cbailey.tech in my case) purely aesthetic reasons. I want the default owner of these files to be root so that carelessness is minimized. Towards that end, create the directory with $ sudo mkdir -p /srv/domainname. I also decided I wanted a staging area that only I can see, and a production area that's public. Each of them will hold a copy of the website, and this way I can experiment and debug in staging without breaking production. This isn't a new or original idea by any measure, and there are tools out there that automate this process, but those that I've seen are overkill for my purposes. To set this up I begin by making the areas with $ sudo mkdir /srv/domainname/prod /srv/domainname/stage. Next, let's put some dummy files in there for testing later

$ for i in stage prod; do echo "Hello, I'm $i!" | sudo tee /srv/domainname/$i/index.html > /dev/null; done

There's a problem though: I'd like the permissions on stage to be a little lax so I can make updates easily. I went about this by making a staging group with $ sudo groupadd stage, adding myself to it with $ sudo usermod -a -G stage myusername, changing the group ownership with $ chown -R root:stage /srv/domainname/stage, and relaxing permissions with $ chmod 775 /srv/domainname/stage.

Serve Up Production

So how do I get nginx to serve those dummy files to my browser? Let's start with production. We'll need to edit a configuration file with root privileges, so do $ sudo editor /etc/nginx/nginx.conf replacing editor with your favorite (mine is emacs). You'll notice a section like this. That is called a server block in nginx terminology. They are what define distinct portions of your domain, e.g. prod will have one and stage will have one. If a line's first non-whitespace character is #, then that line is a comment. It's worth doing some extra research right now to understand what's going on here, but for now I'll just tell you how to manipulate the files to get the desired results.

Other distros, like Ubuntu, server blocks are organized such that each one has its own file in a directory called sites-enabled. I find this structure easier to maintain. As you can see, Arch likes to cram them all into nginx.conf one after another. To get the Ubuntu-style organization we'll first create the folder with $ sudo mkdir /etc/nginx/sites-enabled. Then cut the whole server block out of /etc/nginx/nginx.conf and paste it into a new file at /etc/nginx/sites-enabled/yourdomain.conf. Go back to nginx.conf and somewhere in the http block put this line

include /etc/nginx/sites-enabled/*;

Now open /etc/nginx/sites-enabled/yourdomain.conf for editing. Replace the server-name line with

server_name domain.name www.domain.name;

And replace the root line with

root /srv/domainname/prod;

So when finished mine, cbailey.tech.conf, is effectively just

server {
	      listen 80;
  server_name  cbailey.tech www.cbailey.tech;

  location / {
    root   /srv/cbailey.tech/prod;
    index  index.html index.htm;
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}

You can probably get the hang of how these things work just by looking at it carefully.

Now restart nginx with $ sudo systemctl restart nginx to load up the new config. Visiting your domain name should now result in a page that says "Hello, I'm prod!"

Serve Up Staging

I decided I wanted to access the staging area via stage.cbailey.tech. The stage part is called a sub-domain. We need a new server block for this portion of the website, so open up /etc/nginx/sites-enabled/stage.domainname.conf for editing. It's easiest to just paste the contents of domainname.conf in here and change the values, in a way similar to how we did it before. When finished mine, stage.cbailey.tech.conf, is effectively just

server {
	      listen 80;
  server_name  stage.cbailey.tech;

  location / {
    root   /srv/cbailey.tech/stage;
    index  index.html index.htm;
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}

Noticing the patterns yet? Restart nginx again with $ sudo systemctl restart nginx for the changes to take effect.

But that's not all; we actually need to let Linode's name servers know about this sub-domain. Sign in at Linode and visit the Linode Manager. Click on the DNS Manager tab and click on Edit for the appropriate domain zone. Under A/AAAA Records click Add a new A/AAAA record. Enter stage.domain.name (in my case stage.cbailey.tech) for Hostname and your host's IPv4 address. I left the TTL as default. Press Save Changes. You can repeat this for the IPv6 address if you want.

Once again these DNS changes will need some time to propagate before you see results, but eventually stage.domain.name should bring you to a page that says "Hello, I'm stage!".

Restricting Stage Access

Remember earlier I told you nobody should be able to see the staging area but me? Well that is not the case currently. We can achieve this through nginx though. Nginx borrows something from Apache called htpasswd files. They hold encrypted usernames and passwords for really basic http authentication.

If you want to make things easy on yourself, then run $ sudo pacman -Syu apache to install the apache package which provides the htpasswd utility. If you're a minimalist there are ways to create the htpasswd file without installing all of apache, but I won't cover them here.

Now run $ sudo htpasswd -c /srv/domainname/.htpasswd admin and enter a strong password when prompted. This creates a user for the staging area called admin and stores that username/password pair in the /srv/domainname/.htpasswd file.

Now open /etc/nginx/sites-enabled/stage.domainname.conf for editing. Add these lines somewhere in the server block, of course replacing domainname

auth_basic "Domainname Staging Sub-domain";
      auth_basic_user_file /srv/domainname/.htpasswd;

Restart nginx one more time with $ sudo systemctl restart nginx. Now when you visit stage.domainname.whatever you should be greated with a login prompt that keeps prying eyes out! And after successfully signing in, you should be greeted with "Hello, I'm stage!"

Deployment Process

Take a step back and try to remember why we went through all of this. stage.domain.name is a copy of www.domain.name, but hidden to the public. You should test all updates and changes to the website in this staging area, and when you're ready, just move it into production. This is easily done with a simple shell script.

As I said before there are many, many tools made to serve this purpose. But this little script fulfills my needs for now: backups and publishing. When I am done testing in the staging area I simply call $ sudo ./deploy.sh cbailey.tech.

Wrap-up

Now you've got a sandbox to play in, protected from the public, and a published site that can handle seemless deployments! Try making some changes to stage and deploying them. Then try restoring a backup! Bear in mind that the backups will slowly eat up disk space and that needs to be managed. Perhaps look into a cron job or systemd timer to handle that automatically!

In the next episode we will be encrypting the website with SSL thanks to the incredible Let's Encrypt service.