Deploying a Hugo website to Amazon S3 using Bitbucket Pipelines

Atlassian recently released a new feature for their hosted Bitbucket product called “Pipelines”. It’s basically their version of Travis CI, that can do simple building, testing and deployment.

In this blog post I’ll show you how I use Pipelines to deploy my Hugo site to AWS S3. This is short and to-the-point, if you know AWS this should tell you enough to set up your own deployment in about 5 minutes.

Create an AWS user for Pipelines

You need an AWS user that can deploy to your bucket, do NOT use your admin user for this! Simply create a new user called “pipelines” and give it only access to your blog bucket.

This inline policy should be enough access to do these deployments (replace BUCKETNAME with the name of your bucket):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:List*",
                "s3:Put*",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::BUCKETNAME",
                "arn:aws:s3:::BUCKETNAME/*"
            ],
            "Effect": "Allow",
            "Sid": "AllowPipelinesDeployAccess"
        }
    ]
}

Configure Pipelines with your AWS credentials

Generate an access and secret key for this new user and add these 3 variables in the environment variables settings page in Bitbucket:

AWS Variables:

AWS_ACCESS_KEY_ID: xxx
AWS_SECRET_ACCESS_KEY: xxx
AWS_DEFAULT_REGION: (your bucket's region)

Bitbucket Pipelines environment settings page:

Bitbucket Pipelines environment variables settings page

Create the Pipelines build config

I’m assuming your hugo site lives in the root of your git repository. In my case my repository looks like this:

karel:Hostile ~/KarelBemelmans/karelbemelmans-hugo$ tree -L 2
.
├── README.md
├── bitbucket-pipelines.yml
├── config.toml
├── content
│   ├── about-me.md
│   └── post
├── public
│   ├── 2015
│   ├── 2016
│   ├── 404.html
│   ├── CNAME
│   ├── about-me
│   ├── categories
│   ├── css
│   ├── favicon.png
│   ├── goals
│   ├── images
│   ├── index.html
│   ├── index.xml
│   ├── js
│   ├── page
│   ├── post
│   ├── sitemap.xml
│   ├── touch-icon-144-precomposed.png
│   └── wp-content
├── static
│   ├── CNAME
│   ├── css
│   ├── images
│   └── wp-content
└── themes
    └── hyde-x

Then create the file bitbucket-pipelines.yml in the root of your repository, replace BUCKETNAME with the name of your blog’s bucket:

image: karelbemelmans/pipelines-hugo

pipelines:
  default:
    - step:
        script:
          - hugo
          - aws s3 sync --delete public s3://BUCKETNAME

Docker Hub and Github links for this Docker image, feel free to fork and modify:

That’s all.

One single remark though

As you can see I use the aws s3 sync method to upload to S3. When I do this from my laptop, where files persist over deployments, that actually makes sense and saves me some upload traffic.

Doing this on Pipelines, where the hugo site is always completely re-generated from scratch inside a Docker container, is actually useless as it will always upload the entire site as every file is “new”.

comments powered by Disqus