Gregor Müllegger webdev by heart

Hosting a static website with GitLab and Cloudflare for free

I decided to strip down my hosting costs by getting rid of a personal virtual server that I managed the last ten years. One of the sites on this server is my personal website gremu.net. Since it is just generated from a static website generator, I figured I could deploy it for free somewhere using GitHub Pages or a similiar service.

I decided to go with the alternative GitLab. GitLab allows for as many private repositories as you want in their free plan and has an integrated CI system for free that you can use to deploy the site however you need.

TL/DR:

Setting up GitLab Pages

First thing we are going to try is to deploy your website to a GitLab Page.

I assume that you already have a static site generator setup, and that you manage it using a git repository. You can choose from a large variaty, I went with Pelican. However if you don't have anything setup so far, just place a Hello World into a index.html in the root of your git repository.

Register a free account on gitlab.com to get started. Now you can create a private repository that will contain your raw source files. The GitLab project should have the name <username>.gitlab.io, so for example in my case it is named gregmuellegger.gitlab.io. Now push the source files there and see how the git repository is populated in GitLab. It will look very similiar to any GitHub project that you have seen before:

Screenshot of the gregmuellegger.gitlab.io repository on gitlab.com

Unlike with GitHub pages, the content of this repository will not be published automatically onto your website. GitLab allows you to use a build step that for instance can generate your HTML files from your Markdown files. The beauty of this is, that you do not need to check in the generated HTML files into your repository. And you don't have to remember generating and commiting them everytime you change something on the source files.

In order to use GitLab's CI system to generate the HTML files, you create a .gitlab-ci.yml file in the root of your repository. Mine looks something like this:

image: python:3.5

pages:
  script:
    - pip install "pelican==3.5.0"
    - pelican -o dist/ -s src/pelicanconf.py src/content
    - mv dist/ public/
  artifacts:
    paths:
      - public
  only:
    - master

This is a straightforward piece of configuration. Let's look at the different parts. It starts with image: python:3.5, that defines the base docker image we are using to build the site. The script part let's you define a list of commands that are necessary to build your site. The important part here is, that the built files need to end up somehow in the public/ directory.

I do this by first executing my build step, i.e. the pelican command, and then mv the generated files into the public/ directory.

The artifacts section is just here to point at the right location where it should look for the created files. I have found that this must be public/, otherwise it won't pick up the files for the GitLab page. And last there is the only config. I choose to always let the CI deploy my site when I commit something to master. You can for example change the branch here if you want to have a designated release branch. However be aware that if you leave out the only filtering, you will end up deploying to your website with every commit, even if you only worked in an experimental branch.

Here is an in-depth documentation on how to configure GitLab pages in your .gitlab-ci.yml file.

Congratulations! Once you push your .gitlab-ci.yml configuration to the repository, the CI should kick in and do the rest. You can go to the Pipelines section in your project, and see if the build goes green or has some errors. If everything went as expected, the build will look something like the screenshot below. You can now access your website with the URL https://<username>.gitlab.io.

Screenshot of GitLab pipelines successful build

Using a custom domain with SSL encryption with GitLab pages

Now we want to use our own custom domain, so we have a pretty URL in the browser, in my case I want to configure https://gremu.net to point to the GitLab page. So as a prerequisite, you need your domain already ordered (which will probably not be free, but that's the only part of your website that you need to pay for).

You could go now and configure your domain's CNAME entry to point to your GitLab page. However that has the drawback, that if you want to secure it with SSL, you would need to aquire your own certificate that you would then configure in your GitLab account. That could be done for free if you go with a service like Let's Encrypt, but it would require you to re-new the certificate manually every few months. As I'm too lazy for this I looked for other ways.

And as it turned out Cloudflare let's you do exactly that. The way it can do that is to configure your domain to use Cloudflare's DNS servers. Cloudflare as a CDN will then intercept all the traffic that goes to your domain and proxy your CNAME configuration.

So once the domain (let's say gremu.net) is set up correctly with Cloudflare, and a CNAME is in configured Cloudflare's DNS settings to point to GitLab pages (say gregmuellegger.gitlab.io), then the following will happen when you access your site:

  1. You type https://gremu.net into your address bar.
  2. Your browser will load an IP for this domain that points to a Cloudflare CDN server.
  3. The CDN server will look into it's configuration and make its own request to gregmuellegger.gitlab.io in the background.
  4. The CDN server will hand back the response it got from GitLab back to your browser.

So effectively Cloudflare is used as a proxy. That sounds weird in the first place, but gives us a few key parts which makes things easier:

  • Cloudflare can now cache the responses from GitLab pages and make the page loads a lot faster (that's basically what every CDN does).
  • Cloudflare provides a simple, but free SSL certificate out of the box for our domain. As the webtraffic goes to Cloudflare, they take the work of setting up the certificate. We don't need to renew anything.
  • Cloudflare is an HTTP proxy, so we are more flexible with it than with what we could do with just a CNAME DNS entry. For example we can do redirects.
  • You can configure a redirect from all http:// addresses to https://
  • Cloudflare allows me to setup a redirect from www.gremu.net to gremu.net, so no matter what domain you access, you will always end up on https://gremu.net

So getting all these points to work for you is the goal. Let's walk briefly to what you need to do to achieve this.

Setting up Cloudflare

Of course you need to have an account with Cloudflare. Once you have set it up, you are prompted to configure your DNS nameservers to use the ones provided by Cloudflare.

You need to do so in the admin panel of your Domain hoster. Depending on the usability of this admin panel, the option might be very deeply hidden inside some side menu unrelated to you domain configuration. Once you have found it, change the DNS servers to the Cloudflare ones. Now Cloudflare will show you the current status of the switch, this might take up to a few hours, but for me it was finished after about ten minutes.

Once this is completed the status on your domain overview page will switch to Active:

Screenshot of Cloudflare, say "status: active" after DNS server has been enabled.

Cloudflare will by default keep your DNS settings that you have used before on the previous DNS server, so the transition should be smooth if you have the domain already in use. If not already done, you can now configure a CNAME entry, so that the domain will point to the hosted static website on GitLab.

Cloudflare DNS config, showing CNAME entry for gremu.net

Congratulations! You now have a static website hosted under your own domain.

However for my choice this is not yet enough. I'm not happy without having set up SSL for the site. Even though it's static content and no one will want to enter a password on the site, it's good to put it behind SSL to mitigate man in the middle attacks that could inject malicious JavaScript into your site.

So let's activate SSL. The config is as simple as it can get. Just switch to the Crypto tab in Cloudflare and set the SSL setting to Full.

Cloudflare SSL config, set to "Full"

Voila! Everything encrypted. Like nearly everything. If a user accesses the site directly by typing typing gremu.net, the browser will show a non encrypted version. That is unfortunate as there would be an encrypted equivalent available. This is now were Cloudflare gets really useful. We can configure a redirect for this case.

You can configure redirects in the Page Rules tab in Cloudflare. For my project, I have setup two different redirects, they look like this:

Setting up a Cloudflare page rule that redirects all HTTP traffic to HTTPS.

This one takes care of redirecting all the incoming HTTP requests to a secure HTTPS connection.

Setting up a Cloudflare page rule to redirect www. subdomain to gremu.net without www.

The second rule is useful since I want my site only t be displayed on the root domain gremu.net. However I also want users be able to type www.gremu.net directly into the browser bar, which this page rule will take care of. Visitors arriving on www.gremu.net/page will be automatically redirected to gremu.net/page.

Everything is ready to go

After just a bit of configuration, everything is setup. I really enjoyed the easy-ness of this setup and the no-brain involved here. I didn't need to configure any HTTP server myself, no .htaccess rules were necessary, everything works very cleanly out of the box and all I need to do now to deploy something to my website is a simple git push.

Have you found another setup simpler? Any feedback on how I approached static website hosting in this post? Then get in touch.