Static websites are great for carrying unchanging content, be it assets, images, fonts or even, as in this case, an entire site. Well, I say entire site, but if you saw my last article, you'll know I recently rebranded a Maker organization and needed to deploy a "signpost" page pointing people to the new site. I want this signpost to have a tiny footprint so it will never cost anything to deploy.
Now, the thing with Docker images is that you don't really notice the layers of OS and applications that pile up in the background. Something as notionally simple as say running Apache HTTPD will still need an OS layer under it, no matter how minimal, you put the two parts together and the image size soon builds up. And you still have to add the content.
This is where something like GoStatic comes in. It's a small, self-contained web page server which can run in a bare Docker image - no OS, just the binary. As the author points out, the official Golang images can weigh in with as much as half a gigabyte of image. For GoStatic, the image is an unchunky 6MB.
So, how do you make use of GoStatic on Fly? Let's step though it now.
One thing you need to know is that by default GoStatic uses port 8043. So add
-p 8043 to your
fly init command when you create your project. That'll route traffic to port 80 and 443 to port 8043 on the application.
❯ mkdir examplegostatic ❯ cd examplegostatic ❯ fly init examplegostatic -p 8043 Selected App Name: examplegostatic ? Select organization: Dj (dj) ? Select builder: Dockerfile (Create an example Dockerfile) New app created Name = examplegostatic Owner = dj Version = 0 Status = Hostname = <empty> Wrote config file fly.toml
We already have an index.html we want to serve, so our next stop is the Dockerfile. Delete the example contents and replace it with just two lines.
FROM pierrezemb/gostatic COPY index.html /srv/http/index.html
And we are ready to deploy! Just run
Deploying examplegostatic ==> Validating App Configuration --> Validating App Configuration done Services TCP 80/443 ⇢ 8043 Deploy source directory '/Users/dj/examplegostatic' Docker daemon available, performing local build... ==> Building with Dockerfile Using Dockerfile: /Users/dj/examplegostatic/Dockerfile Step 1/2 : FROM pierrezemb/gostatic ---> 4569615e9ed0 Step 2/2 : COPY index.html /srv/http/index.html ---> b0b723d0cb24 Successfully built b0b723d0cb24 Successfully tagged registry.fly.io/examplegostatic:deployment-1595848012 --> Building with Dockerfile done Image: registry.fly.io/examplegostatic:deployment-1595848012 Image size: 7.7 MB ==> Pushing Image The push refers to repository [registry.fly.io/examplegostatic] 77bf40a52322: Pushed 3530b7ebed24: Pushed deployment-1595848012: digest: sha256:d60567799841a4480e410acef113d33c1156eb960b94ae591931801089f61b1a size: 735 --> Done Pushing Image ==> Optimizing Image --> Done Optimizing Image ==> Creating Release Release v0 created Deploying to : examplegostatic.fly.dev Monitoring Deployment You can detach the terminal anytime without stopping the deployment 1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 passing] --> v0 deployed successfully
Once deployed, all you need to do then is
flyctl open and a browser will open and navigate to the site.
You'll also notice that this has been upgraded to an https connection. All that is left is to attach a custom domain to it and we're done.
Behind the Scenes
So, what magic is going on here? Well, the Dockerfile in GoStatic explains a lot of it.
It uses a Docker multistage build to build our server binary in the first stage. Then it starts a new stage from scratch, literally using the command
FROM SCRATCH. This says that there is no base image, just start building on top of nothing, an empty image. The rest of the GoStatic Dockerfile creates a passwd file so there are some usernames to work with and copies over the GoStatic binary.
And then it all hands over to our own Dockerfile. GoStatic serves files out of
/srv/http so we copy over our
index.html to that directory. And that's it. Everything else is managed by Fly, the build, the deployment and the upgrading to an https connection. There used to be a version of GoStatic which would handle HTTPS connections and certificates, but that functionality has been retired now servers like Caddy exist. On Fly, the lack of HTTPS support means it's simple to just let Fly take on the HTTPS work for you.
A Small Squeeze
One last tip. Fly deploys new applications with 512MB of RAM and about a quarter of a virtual CPU. It's called a
micro-2x firecracker VM. But, we're doing so little here, we could scale the VM size down. Let's look at the scale settings:
~/examplegostatic ❯ flyctl scale show Scale Mode: Standard Min Count: 0 Max Count: 10 VM Size: micro-2x
And now we can set the vm size:
~/examplegostatic ❯ flyctl scale vm micro-1x Scaled VM size to micro-1x CPU Cores: 0.12 Memory: 128 MB Price (Month): $2.670000 Price (Second): $0.000001
If you want to find out about the other VM sizes, run
flyctl platform vm-sizes.
We've got ourselves a tiny static web server and deployed it to Fly.io, and as a bonus, shrunk the VM's footprint to match it and save running costs. Enjoy!