Update article, images
parent
16b4af073c
commit
49c0d757e7
Binary file not shown.
After Width: | Height: | Size: 392 KiB |
Binary file not shown.
After Width: | Height: | Size: 403 KiB |
|
@ -1,22 +1,22 @@
|
|||
+++
|
||||
title = "diy code hosting with gitea and fly.io"
|
||||
date = "2022-08-07"
|
||||
updated = "2022-08-08"
|
||||
updated = "2022-08-21"
|
||||
[taxonomies]
|
||||
tags = ["git", "gitea", "fly.io"]
|
||||
+++
|
||||
|
||||
## Setting the scene
|
||||
## Setting the Scene
|
||||
Inspired by the [Give Up Github campaign](https://sfconservancy.org/GiveUpGitHub/), I recently decided I wanted to spin up my own instance of [Gitea](https://gitea.io/). There are free (as in beer), free (as in freedom), public instances of Gitea and other FOSS-leaning code forges, but self-hosted Gitea struck me as a nice way to take even a bit more ownership over my own code.
|
||||
|
||||
I maintain a small PC running in my home as a server for a few services running via Proxmox, but I am really dissatisfied with my workflows for managing that box lately (picture SSHing into LXC containers and manually editing systemd configurations... yuck). I recently read a couple of different articles singing the praises of [Fly.io](https://fly.io/), a platform as a service (PaaS) that replicates most of the good parts of the classic Heroku developer experience. Further enticed by their ample free tier, I took the plunge and created a Fly.io account.
|
||||
|
||||
## Getting started
|
||||
## Getting Started
|
||||
First things first: in order to interact with Fly.io, we primarily use the `flyctl` command line tool. It's available from a variety of sources:
|
||||
```bash
|
||||
# Nix
|
||||
nix-shell -p flyctl
|
||||
nix-env -iA nixpkgs.flyctl
|
||||
nix-shell --packages flyctl
|
||||
nix-env --install --attr nixpkgs.flyctl
|
||||
|
||||
# macOS
|
||||
brew install flyctl
|
||||
|
@ -39,7 +39,7 @@ flyctl auth signup
|
|||
flyctl auth login
|
||||
```
|
||||
|
||||
## Configuring apps with `flyctl`
|
||||
## Configuring Apps with `flyctl`
|
||||
In order to avoid even the appearance of disorganization, we'll start off with a git repository for tracking our Fly.io configurations:
|
||||
```bash
|
||||
mkdir fly-apps; cd fly-apps
|
||||
|
@ -126,7 +126,7 @@ flyctl open
|
|||
|
||||
Now you can register your account! If you want to keep your Gitea instance private, uncomment the last line in the `env` section and rerun `flyctl deploy` after registering.
|
||||
|
||||
## Bonus round: configuring your custom domain with Fly.io
|
||||
## Bonus Round: Configuring Your Custom Domain with Fly.io
|
||||
Some, like myself, will not be satisfied accessing their Gitea instances with a `.fly.dev` URL. Thankfully, Fly.io makes it a breeze to configure a secure custom domain with the help of [LetsEncrypt](https://letsencrypt.org/).
|
||||
|
||||
Fly.io and `flyctl` seem to offer tooling for managing your domains and DNS records entirely within the Fly.io system, but I personally didn't explore this route, as my own domains and DNS records are managed elsewhere. Whatever you use to manage your own domains and DNS, you will need to create two records for your domain name corresponding with the IPv4 and IPv6 addresses of the application:
|
||||
|
@ -140,9 +140,43 @@ v6 dead:beef:1::a:a global 2022-07-03T04:39:19Z
|
|||
Create an A record for the v4 address, and an AAAA record for the v6 address. With those records in place, `flyctl` can automatically perform the necessary setup with LetsEncrypt to secure your domain:
|
||||
```bash
|
||||
flyctl certs add git.mat.services
|
||||
flyctl open
|
||||
```
|
||||
|
||||
Now open up your custom domain and revel in your new code hosting powers.
|
||||
Now it's time to revel in your new code hosting powers.
|
||||
|
||||
### The First Push (or, 256MB just isn't enough sometimes)
|
||||
With everything now set up, let's go ahead and kick the tires on our new Gitea installation. We can push our `fly-apps` repository to Gitea as a test! Create a new blank repository on Gitea with an appropriate name, then add that as a remote for your local repo:
|
||||
```bash
|
||||
git remote add origin git@gitea-mat-services.fly.dev:mat/fly-apps.git
|
||||
```
|
||||
|
||||
And now it's as simple as one command!
|
||||
```bash
|
||||
git push --set-upstream origin main
|
||||
Enumerating objects: 3, done.
|
||||
Counting objects: 100% (3/3), done.
|
||||
Writing objects: 100% (3/3), 195 bytes | 195.00 KiB/s, done.
|
||||
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
|
||||
remote:
|
||||
remote: Gitea: Internal Server Error
|
||||
Gitea: Internal error
|
||||
To git.mat.services:mat/foobar.git
|
||||
! [remote rejected] main -> main (pre-receive hook declined)
|
||||
error: failed to push some refs to 'git.mat.services:mat/foobar.git'
|
||||
```
|
||||
|
||||
Uh. Hm. I just got an email saying a Fly.io instance ran out of memory and crashed. Let's peek at our Fly.io dashboards:
|
||||
|
||||
![Fly.io memory dashboard](fly-io-memory-dashboard.png)
|
||||
|
||||
That doesn't look so great. It seems like Gitea idles just under the amount of memory we have with a default instance size, and operations like `git push` can bump it over the threshold to an out-of-memory error. Let's check out the "Scale" section of the dashboard, and increase the memory allotment for this VM:
|
||||
|
||||
![Fly.io VM scale interface](fly-io-scale-vm.png)
|
||||
|
||||
I have been running my Gitea install on a 512MB instance since the first day I started using it, which seems to be plenty of headroom for personal use. If you open up your Gitea installation to the public and it starts to get popular, you might end up needing to scale up further.
|
||||
|
||||
It's worth noting that scaling up to 512 MB means you will start accruing a Fly.io balance, but thus far this has never been more than a $2 monthly bill for me. If that's too steep for you, consider that Fly.io doesn't (at the time of this writing) charge for monthly bills below $5, or else check out some of the competing PaaS options out there.
|
||||
|
||||
### Acknowledgements
|
||||
- [Thank you to Xe Iaso for xer blog post on Fly.io that inspired me to try it in the first place!](https://xeiaso.net/blog/fly.io-heroku-replacement)
|
|
@ -0,0 +1,103 @@
|
|||
+++
|
||||
title = "hosting a static site on fly.io with nix and caddy"
|
||||
date = "2022-08-20"
|
||||
draft = true
|
||||
[taxonomies]
|
||||
tags = ["static-site", "nix", "caddy", "fly.io"]
|
||||
+++
|
||||
|
||||
## Motivation
|
||||
So, [you've ditched Github and friends](https://sfconservancy.org/GiveUpGitHub/), [set up your own Gitea instance](./gitea-on-fly-io), and there's just one (read: at least one) thing left for you to take care of—that snazzy static site you had up on Github Pages.
|
||||
|
||||
### Pages and Static Site Hosting
|
||||
I can remember how empowering it felt when I finally realized how much utility Github had packed into the Pages product. I went through a gleeful week or more of churning out Vue.js templates and half-baked styles for several different sites, all the while starry-eyed with how easy Pages made the deployment process. Eventually I migrated some of my work, including my static sites, to Gitlab, which has a virtually identical offering. I was quietly pleased with the ease of use afforded by both options.
|
||||
|
||||
Fast forward to today, and my migration away from Github and Gitlab has me once again pondering the question of an easy-to-use static site host. The tech industry has left us spoiled for choice here. Aside from Pages products from code hosting platforms, the major cloud infrastructure providers all have their own take on static site hosting. Companies like Netlify, Vercel, and Render offer a lot to hobbyist developers in terms of static hosting resources, with some going even further to provide Serverless-style "Functions-as-a-Service" products.
|
||||
|
||||
Some of these options were ruled out by requiring source code to be hosted on Github and friends, while others were much more heavyweight than what my requirements demanded. I was also motivated by an urge to consolidate: I already had projects running on Fly.io, as well as some important configuration and infrastructure on DigitalOcean, which made me hesitant to bring another third party into the mix.
|
||||
|
||||
As you may have guessed from the title, my ultimate decision was to take inspiration from [a Fly.io tutorial document](https://fly.io/docs/getting-started/static/) explaining how to deploy a very simple vanilla HTML site on Fly using a Go-powered webserver. I'm going to expand on their design a bit by introducing two major components: [Nix](https://nixos.org), to give us the power to build our site with whatever static site generator (or other build process) we want to use; and [Caddy](https://caddyserver.com), to give us a more flexible and extensible platform for actually serving the content.
|
||||
|
||||
For the purposes of this article, we'll assume you already have your static site ready to go. Whether you're writing pure HTML by hand, or using a cutting-edge Javascript framework that renders down to static resources, you'll be able to package it up with Nix and serve it with Caddy using Fly.io.
|
||||
|
||||
## Before You Deploy: Nix
|
||||
Much like static site hosts, static site **generators** are everywhere, and it seems like one of those things where people have particularly strong opinions on what workflow fits them best. Some people eschew a "generator" entirely and chain more purpose-built tools together to achieve the perfect bespoke output. Whatever your personal choice on generating the content for your static site, it helps to have a sort of "universal interface" to actually kick off the build process. Github and Gitlab have their own custom Continuous Integration/Continuous Delivery systems where the build for the site can be configured. Makefiles can declare a set of commands to run in a generic way, but they don't help us pull in dependencies from the outside. Dockerfiles are not only generic, but also provide some primitives to make it easy to fetch any buildtime dependencies we need. Nix, a declarative package manager, is another option that we can use to specify our build AND dependencies, without requiring us to actually make a container. Nix also provides stronger guarantees around reproducibility and hermeticity than Docker. I already use Nix flakes for virtually all of my personal work, so that's how we'll specify our build step.
|
||||
|
||||
Nix is a very powerful tool, but it can be intimidating to use, and I've encountered many people saying that the documentation is too sparse to be useful. I'll keep the Nix details minimal, and try to include enough explanation for what we're doing that even unfamiliar readers can follow along, but I would encourage anyone who wants some more background on Nix and Nix flakes to check out [these](https://xeiaso.net/blog/nix-flakes-1-2022-02-21) [posts](https://xeiaso.net/blog/nix-flakes-2-2022-02-27) from Xe Iaso's blog.
|
||||
|
||||
If you don't already have Nix installed, we'll start with that:
|
||||
```bash
|
||||
# macOS
|
||||
sh <(curl -L https://nixos.org/nix/install)
|
||||
|
||||
# Linux multi-user install (recommended by Nix)
|
||||
sh <(curl -L https://nixos.org/nix/install) --daemon
|
||||
|
||||
# Linux single-user install (required when using SELinux)
|
||||
# also Windows via WSL2
|
||||
sh <(curl -L https://nixos.org/nix/install) --no-daemon
|
||||
|
||||
# Docker
|
||||
docker run -it nixos/nix
|
||||
```
|
||||
|
||||
Next up, we'll enable Nix flakes as a feature, since they are still disabled by default. You can do this the easy way, by editing one of `~/.config/nix/nix.conf` or `/etc/nix/nix.conf` (if you're using a multi-user install, you'll also need to restart `nix-daemon`):
|
||||
```conf
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
|
||||
If you enjoy pain, you can do this the hard way by remembering to type this at the beginning of all your Nix commands, or setting an alias:
|
||||
```bash
|
||||
# one off
|
||||
nix --experimental-features 'nix-command flakes' build
|
||||
# sort of consistent but also not really
|
||||
alias nix=nix --experimental-features 'nix-command flakes'
|
||||
```
|
||||
|
||||
Now we can mosey on over to our site source. You might already be managing the source with Git, but if not, let's do that now:
|
||||
```bash
|
||||
cd site
|
||||
git init
|
||||
# Be careful not to commit anything secret! Git will keep a record of it
|
||||
git add important/stuff but/no/secrets
|
||||
git commit -m "TODO: pithy quip about starting a new endeavor"
|
||||
```
|
||||
|
||||
Nix flakes require you to be using some form of source control that Nix understands, which means (to my understanding) either Git or Mercurial. Everything tracked by source control will end up going into the Nix store, so be doubly sure that you haven't committed any secrets, tokens, or manifestos that you don't want leaking out.
|
||||
|
||||
We finally have all the foundations in place to put our site's source into a flake. We can get a fresh flake by using the default template:
|
||||
```bash
|
||||
nix flake init
|
||||
```
|
||||
|
||||
This will leave us with the following:
|
||||
```nix
|
||||
{
|
||||
description = "A very basic flake";
|
||||
outputs = { self, nixpkgs }: {
|
||||
packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
|
||||
defaultPackage.x86_64-linux = self.packages.x86_64-linux.hello;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Hmm. Well that's a VERY basic flake. It's also seemingly out of date, as the latest advice I've seen recommends `packages.${system}.default` over `defaultPackage.${system}`. Let's scrap that and pull in a template from the [`flake-utils`](https://github.com/numtide/flake-utils), a very popular recommendation for taming boilerplate and glue code while authoring flakes.
|
||||
```bash
|
||||
rm flake.nix
|
||||
nix flake init --template github:numtide/flake-utils#simple-flake
|
||||
```
|
||||
|
||||
This template will create *three* files: `flake.nix`, `shell.nix`, and `overlay.nix`. Technically, we could squish this all into a single `flake.nix` file, but breaking it down like this will help to separate our concerns and keep things focused.
|
||||
|
||||
### `shell.nix`: Reproducible Development Environment
|
||||
|
||||
|
||||
### `overlay.nix`: Reproducible Site Build
|
||||
|
||||
### `flake.nix`: External Interface
|
||||
|
||||
## Serving: Caddy
|
||||
|
||||
## Deploying: Fly.io
|
||||
|
||||
## Bonus Round: Configure Everything in Nix
|
|
@ -23,11 +23,16 @@
|
|||
pname = "personal-site";
|
||||
version = "2022-08-13";
|
||||
src = ./.;
|
||||
nativeBuildInputs = with pkgs; [ scour zola ];
|
||||
nativeBuildInputs = with pkgs; [ pngquant scour zola ];
|
||||
configurePhase = ''
|
||||
mkdir -p "themes/${themeName}"
|
||||
cp -r ${theme}/* "themes/${themeName}"
|
||||
scour -i static/image/_favicon-original.svg -o static/image/favicon.svg
|
||||
scour -i static/image/_favicon.svg -o static/image/favicon.svg
|
||||
for image in content/**/_*.png static/image/**.png; do
|
||||
path=$(dirname $image)
|
||||
file=$(basename $image)
|
||||
pngquant --quality 90-99 -f -o "$path/''${file:1}"
|
||||
done
|
||||
'';
|
||||
buildPhase = "zola build";
|
||||
installPhase = "cp -r public $out";
|
||||
|
|
|
@ -193,4 +193,9 @@ time {
|
|||
// Post list
|
||||
li.post-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
// Rounded image
|
||||
img {
|
||||
border-radius: 5px;
|
||||
}
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in New Issue