Deploying Hugo to Fly.io

Deploying Hugo to Fly.io requires a webserver, for this we will use NGINX. Continuing from Hugo + Alpine.js + TailwindCSS Quickstart and Integrating OpenGraphImage.com we will update the Dockerfile in our project by adding two addition stages, builder and release.

The builder stage extends our hugo image and run the npm run build npm script that will trigger the Hugo production release, saving the output to /src/public/.

The release stage uses an nginx:alpine docker image and copies in the files in /src/public/ from the builder stage and a custom nginx.config.

# hugo/Dockerfile
# ...

FROM hugo as builder
ARG HUGO_OPENGRAPH_KEY
ENV HUGO_OPENGRAPH_KEY $HUGO_OPENGRAPH_KEY

ARG HUGO_OPENGRAPH_SECRET
ENV HUGO_OPENGRAPH_SECRET $HUGO_OPENGRAPH_SECRET

RUN npm run build

FROM nginx:alpine as release
EXPOSE 8080
COPY --from=builder /src/public /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf

The nginx.conf we will use is pretty bare bones for this example, it listens on Fly.io’s default port 8080, serves the static files and handles any 404 errors with Hugo’s 404 page.

# hugo/nginx.conf

user nginx;
worker_processes auto;

events {
  worker_connections  1024;
}

http {
  server {
    # `8080` is the defalt port Fly.io uses
    listen 8080;
    listen [::]:8080;

    # the domain name of the server
    server_name _default;

    # prevent using `http` or `https` and server name in the redirect url
    absolute_redirect off;

    # do not use the port in the redirect url
    port_in_redirect off;

    # the folder for the Hugo output
    root /usr/share/nginx/html;

    # use `index.html` as the default page
    index index.html;

    # use the Hugo 404 page
    error_page 404 /404.html;
  }
}

Now we can change into the ./hugo folder and run fly launch to create our new app, or fly deploy to push a new release.

Because we are referencing a the HUGO_OPENGRAPH_KEY and HUGO_OPENGRAPH_SECRET environment variables at build time we need to leverage the --build-arg flag when running fly deploy.

cd hugo

# store the env variables in the context of the fly command
source .env

# Use `fly launch` with `HUGO_OPENGRAPH_KEY` and `HUGO_OPENGRAPH_SECRET` to create your Fly App
# fly launch \
#   --build-arg HUGO_OPENGRAPH_KEY=$HUGO_OPENGRAPH_KEY \
#   --build-arg HUGO_OPENGRAPH_SECRET=$HUGO_OPENGRAPH_SECRET

# Use `fly deploy` with `HUGO_OPENGRAPH_KEY` and `HUGO_OPENGRAPH_SECRET` to deploy new versions
fly deploy \
  --build-arg HUGO_OPENGRAPH_KEY=$HUGO_OPENGRAPH_KEY \
  --build-arg HUGO_OPENGRAPH_SECRET=$HUGO_OPENGRAPH_SECRET

You should now have a Hugo site being served by NGINX running on Fly.io.

If you’re using Cloudflare you will run into a “Failed to find a valid digest in the ‘integrity’ attribute for resource” if you use the “Auto Minify” feature for your JavaScript. The feature is not needed since we are using Hugo’s -minify flag when building our site.