1. 28
  1. 7

    I am not sure why people tends to over engineer a simple task, such as hosting a static site. Cloudflare or other static site hosting vendors are much easier with probably lesser energy consumption.

    1. 2

      I’d argue overengineering is in the eye of the beholder, but I’m curious if there are any good ways to estimate the net energy impact of my application on various cloud services. Caddy is not particularly resource intensive, and the allocation I use on fly.io is very small, but I can still imagine it’s quite a bit less efficient than something like S3.

      On the flip side, I don’t have any experience with AWS or the other big cloud providers for personal work, and I have avoided Cloudflare for awhile now for unrelated reasons. So I’m curious if there are any particularly great high-efficiency options that fall outside those groups. Shared static hosting is probably a reasonable option to explore.

      1. 1

        I’d argue overengineering is in the eye of the beholder, but I’m curious if there are any good ways to estimate the net energy impact of my application on various cloud services. Caddy is not particularly resource intensive, and the allocation I use on fly.io is very small, but I can still imagine it’s quite a bit less efficient than something like S3.

        https://railway.app/ https://vercel.com/ https://render.com/ at least you can have GitHub Pages.

        1. 1

          If you read the article, part of the whole thrust here is that I’ve moved away from Github, so I’m not interested in platforms that require source on Github.

    2. 6

      Sweet! I did something similar to this a while ago: https://github.com/LutrisEng/nix-fly-template

      Mine was using nginx, but otherwise was pretty similar. I really love “abusing” flake apps like this to make a script that uses data files from its closure to do something stateful (importing Docker images, deploying to Fly.io, I could imagine deploying Helm charts or running a kubectl apply being doable as well).

      1. 4

        Your project was a huge inspiration for the implementation of my own site and the writing of this post! I gave your repo and Lutris a shoutout at the bottom of the post (thinking it was more of a company project than a personal one), I could mention you by name specifically since you are the only contributor?

        1. 3

          Oh neat, didn’t see the acknowledgements section! Super cool to see people taking inspiration from me! Either one works, the company as a whole is basically a one person operation anyways.

      2. 5

        Thank you for the writeup! As someone struggling to use nix for anything and glibly deciding it’s everyone else’s fault, I have some comments/questions:

        • Thank you for not using with! As a beginner with is total evil for me, because I cannot know what is defining top-level values.

        • Thank you for making me discover callPackage! This actually is a major source of issues for me. Nix is “just functions” yet somehow everyone seems to have access to weird magic that means they can get dependency injection by changing their function signature. Honestly, after reading this, the documentation, and experiencing loads of confusion from this: is it really worth doing this compared to pkgs.foo everywhere? You can still build a set from the outside when you want, and it means one less piece of “magic”

        • you had a lot of comments in your flake.nix, it would be interesting to see one extra thing defined in inputs to be able to more deeply understand how that 3-step flow actually works in practice

        • You have caddyfile = builtins.readFile ./Caddyfile; and then… I believe are injecting the text into the command line. What would building up the dockerfile look like if you wanted to add that file into the root?

        • similarly, in site.nix, you had src = ./.. Is there an easy way to define globs or the like? For example I have a static site that has a build process, so really I just want to package up built artifacts, and easily exclude certain types of files

        • I’m not 100% clear what your final flake.nix looks like here, would it be possible to put it in a gist or something?

        Sorry for the big comment wall, in any case this is super useful, as I was just yesterday trying to figure out how to move a Heroku app over and was trying (and failing) to use nix in this process

        1. 3

          Thank you for your response! Nix definitely has a learning curve, but it has slowly worked its way into almost all of my personal workflows. I’m happy to try and respond to any questions, and please let me know if I can elaborate on any of my answers to be more helpful!

          • re callPackage, I definitely don’t reach for it right away, but if I am going to include several different custom package expressions that all have different dependency sets, I’ll probably write something like this in order to make it low boilerplate to include additional packages. In cases where the packages are a little more uniform, you can make it even less boilerplate-y by just making an array of package names and dynamically importing nix files, like this. Again, this probably shouldn’t be the first thing you reach for, particularly if you only have 1-2 packages to add and you don’t expect to have more
          • here is an example of a flake that uses an input as a flake-module import
          • I think you may have pointed out a bug in this workflow! I’m accidentally just injecting the whole body of the Caddyfile into the command line, but I really need to be passing the path in the Nix store, so builtins.readFile isn’t appropriate. I’m still getting my CI/CD set up working, so I wasn’t able to test this part… I’ll probably go ahead and install Docker engine locally to be able to test this out before posting an update to fix this.
          • I don’t know of an option with globbing, but there’s nix-gitignore and nix-filter which might help you express this kind of source filtering. I’d mentioned that for my site, src includes the INPUTS to my static site generation process, and the outputs are copied to the nix store in the buildPhase.
          • the final flake is going to look like this: https://paste.ee/p/QAlaJ. if you want to see a slightly more worked example, here is the flake for my own website
        2. 2

          Wow - completely coincidentally I also moved my website from Cloudflare to Fly.io (served using Caddy) this afternoon. No Nix though :)

          1. 3

            Would you be able to say a few words on why you moved a static site away from cf ?

            1. 6

              Their (lack of) policies against hate speech.

          2. 2

            Caddyfiles look neat. Could they be the solution to how horrible it is to deploy various self-hosted apps?

            1. 2

              What interests me about Caddy is that the core configuration language is JSON and Caddyfiles convert down to JSON. There are also plugins to convert Nginx files to Caddy and so forth. It’s a powerful idea.

            2. 2

              I am migrating my website to fly.io and using caddy as webserver, nix is not currently in the architecture but will surely read this! Thanks :)

              1. 3

                I recently moved my static websites to fly.io (shameless self-plug), but using gostatic for HTTP.

                The Dockerfile I used is this:

                FROM klakegg/hugo:0.101.0-ext-onbuild AS hugo
                FROM pierrezemb/gostatic
                COPY --from=hugo /target/ /srv/http/
                

                I…I really like the simplicity of this setup – don’t mind the entire chain of CI/CD required for it to work. :D

                1. 2

                  I have played with gostatic as well, it does the job but I wanted to play around Caddy just as a mental barrier to not end up using nginx :D

                  1. 3

                    That was the exact reason I tested using Caddy, gostatic and (now) miniserve.

                    I want to setup a redirect from non-www. to www. but couldn’t figure out the matching used in Caddy before my time was up (small children). So I just went to miniserve.

                    1. 2

                      before my time was up (small children).

                      Ahah, that’s way more powerful than my mental barrier against nginx :D Miniserve seems cool, basically a python -m http.server on steroids.

              2. 2

                I followed this, made a couple of adjustments to allow hugo themes to work (feel free to include in the article if you want), and got my first fly.io site up. Thanks for that!

                If you want to use a hugo theme, nix flakes don’t support git submodules at present (was reverted), so I needed to find another way for hugo to be able to get access to the theme.

                In my hugo config.toml:

                theme = "nix-theme"
                

                In my flake.nix, I added this to inputs:

                theme.url = "github:panr/hugo-theme-terminal";
                theme.flake = false;
                

                then I pull it out in the outputs params:

                outputs = { self, flake-parts, theme, ... }:
                

                then in the per-system section, I updated devShells.default and packages.default to pass theme:

                devShells.default = import ./shell.nix { inherit pkgs theme; };
                packages.default = pkgs.callPackage ./site.nix { inherit theme; };
                

                In site.nix, I removed the installPhase and did this, instead:

                { stdenv, hugo, scour, theme }:
                
                #...
                
                buildPhase = ''
                  mkdir -p themes && ln -s ${theme} themes/nix-theme
                  scour -i favicon-original.svg -o favicon.svg
                  hugo -D -d $out
                '';
                dontInstall = true;
                

                This adds a symlink for themes/nix-theme folder pointing to the flake theme input.

                For shell.nix, here’s the file:

                { pkgs ? import <nixpkgs>, theme }:
                pkgs.mkShell {
                  buildInputs = [
                    pkgs.caddy
                    pkgs.flyctl    
                    pkgs.hugo
                    pkgs.scour
                  ];
                  srcs = [ theme ];
                  buildPhase = ''
                    mkdir -p themes && [ ! -L "themes/nix-theme" ] && ln -s ${theme} themes/nix-theme
                  '';
                  shellHook = ''
                    eval $buildPhase
                  '';
                }
                

                This last shell.nix bit allows you to play with all of this in nix develop. Since this affects one’s local filesystem, and overwriting symlinks involving the nix store will be permission denied, it tests for the presence of the themes/nix-theme symlinked directory before trying to create a symlink. From in here, running huge serve will let you develop with the hugo server. I’m not 100% sure this is the best idea, but it worked well for me tonight.

                Lastly, remember to .gitignore your dynamically built folders:

                result/
                themes/