Hello Nikola!

So, finally! I have switched to a statical generated called Nikola. If you are familiar with the Python ecosystem you might have already heard of this project with more than 1000 stars on GitHub.

First choice

Nikola was however not my first choice. I actually started with Pelican.

To bad I had some issues with that:

  • Pelican 3.7.0 has issues with the localisation in the Quickstart script.

  • Pelican prefers to use Makefile, Windows does not. I discovered a blog that offers .bat alternatives.

  • Pelican's Makefile uses the s3cmd command line tool. There is still development on this, but I prefer the AWS CLI. This can be changed inside the Makefile.

    s3_upload: publish
        aws s3 sync --delete output/ s3://${S3_BUCKET}
  • The AGPL license creates a lot of legal uncertainties around 3rd-party files and compiled content.


I went with the latest version of Nikola and I used the Zen theme. The Zen theme uses LESS, so a LESS compiler is required.

This theme uses a different structure for navigating. Compared to the original theme, an icon class has been added to the tuple format.

        ('/index.html', 'Home', 'icon-home'),
        ('/archive.html', 'Archives', 'icon-folder-open-alt'),
        ('/rss.xml', 'RSS', 'icon-rss'),

Hosting it

Nikola has an integrated system for deployments. I just tuned it for S3 bucket synchronisation et voila!

S3_BUCKET = 'xxxxxxxxxx'

    'default': [
        "aws s3 sync --delete output/ s3://{S3_BUCKET}".format(S3_BUCKET=S3_BUCKET),

There are some other important configuration details to keep in mind. These are not set to the correct settings when deploying your static website with CloudFront. For example, requesting http://www.example.com/ usually returns http://www.example.com/index.html. This behaviour defined in the web server configuration, and is often done by default. In CloudFront, this needs to be explicitly defined by setting DefaultRootObject: index.html in the CloudFront distribution configuration. This only works for the root path, not for subsequent paths. Nikola by default tries to generate Nice URLs, this behavior expects index.html to be the default object for a path. Nikola needs to be aware that CloudFormation does not support this by setting STRIP_INDEXES = False.

Creating a Amazon CloudFront distribution is fairly simple, just select the correct S3 bucket, set the Default Root Object to index.html and your good to go.

Or if you want do something fancy like I did using a AWS CloudFormation YAML template:

AWSTemplateFormatVersion: '2010-09-09'
    Type: AWS::CloudFront::Distribution
        - DomainName: bucket.s3.amazonaws.com
          Id: S3-bucket
            OriginAccessIdentity: origin-access-identity/cloudfront/XXXXXXXXXXXXXX
        Enabled: 'true'
        Comment: 'bucket using CloudFormation'
        HttpVersion: http2
        DefaultRootObject: index.html
        - xxxxxxx.com
          - GET
          - HEAD
          TargetOriginId: S3-bucket
            QueryString: 'false'
              Forward: none
          ViewerProtocolPolicy: allow-all
        PriceClass: PriceClass_100
          CloudFrontDefaultCertificate: 'true'

The CloudFormation User Guide contains more template snippets for CloudFront.

The only feature that seems to be missing is IPv6 support in CloudFront when using CloudFormation.


There are a lot of online tools that measure the latency to a certain website. The issue with these tools is that they often run in a datacenter and not from an end-user ISP. All tests are done using IPv4 ping or traceroute utilities from desktops and smartphones. These results should be consistent for other websites on CloudFront. YMMV.

ISP (Technology) (Country) AWS edge location Latency (ms)
EDPnet (VDSL2) (BE) Amsterdam (AMS1) 25
Luxembourg Online (ADSL2+) (LU) Frankfurt (FRA6) 33
Orange (LTE) (LU) Amsterdam (AMS1) 30
Post (Fiber) (LU) Frankfurt (FRA5) 6
Post (VDSL2) (LU) Frankfurt (FRA5) 31
Proximus (VDSL2) (BE) London (LHR50) 30
Tango (LTE) (LU) Frankfurt (FRA50) 41
Telenet (HSPA+) (BE) Amsterdam (AMS50) 343


Comments powered by Disqus