all repos — site @ 3fac106e08eb23cea87856e45a861dc0769ace74

source for my site, found at icyphox.sh

pages/blog/honk-fly.md (view raw)

  1---
  2template:
  3slug: honk-fly
  4title: Honkin' on the Fly
  5subtitle: Running honk on fly.io
  6date: 2022-05-25
  7---
  8
  9For those unaware -- first of all, how? it's literally everywhere --
 10[fly.io](https://fly.io) is the new platform-as-a-service du jour. The
 11idea is to give them a Dockerfile (or a pre-built image, or just generic
 12applications in [a bunch of
 13languages](https://fly.io/docs/getting-started/#language-guides)), and
 14they run it for you on servers across the globe. Firecracker microVMs,
 15WireGuard, and some other neat tech. Understandably, this gets the
 16average Hacker News-type (me), excited. And I'd been meaning to switch
 17my fediverse instance over to
 18[honk](https://humungus.tedunangst.com/r/honk) -- a stateful Go
 19application using sqlite[^1]. And the fly.io folks [really like
 20sqlite](https://fly.io/blog/all-in-on-sqlite-litestream/). The stars
 21have aligned.
 22
 23[^1]: Written by [tedu](https://honk.tedunangst.com/u/tedu). He's a cool
 24      guy who runs and hacks OpenBSD. The honk source is a fun read.
 25
 26I trust that you can figure out the initial setup bits like logging in
 27to the dashboard and giving them your credit card info and praying that
 28they don't run you a bill of $5000 because you somehow blew through
 29their free allowance resources. As I understand it, Fly "auto-scales",
 30so this scenario isn't unlikely -- however, [they do offer some
 31leniency](https://news.ycombinator.com/item?id=31392497). Luckily, the
 32chances of me turning into a fedi-influencer (_fedifluencer_?) overnight
 33are rather slim.
 34
 35## setup
 36
 37They want a Dockerfile, so let's give them one.
 38
 39```dockerfile
 40FROM golang:1.18-alpine AS builder
 41RUN apk add sqlite-dev build-base mercurial
 42
 43WORKDIR /tmp/src
 44RUN hg clone https://humungus.tedunangst.com/r/honk 
 45RUN cd honk && make
 46
 47FROM alpine:latest
 48RUN apk add sqlite sqlite-dev
 49
 50COPY local /tmp/local
 51COPY memes /tmp/memes
 52COPY emus /tmp/emus
 53
 54WORKDIR /opt
 55COPY --from=builder /tmp/src/honk/honk /bin/
 56COPY --from=builder /tmp/src/honk/views views/
 57COPY start /bin
 58
 59ENV HONK_DATA_DIR "/opt/data"
 60ENV HONK_VIEWS_DIR "/opt/"
 61
 62CMD ["/bin/start"]
 63```
 64
 65Not too much going on here -- we pull latest tip, build honk, copy the
 66`local` directory containing our `local.css` (custom styles); the
 67`memes` directory containing, well, memes (PNGs and GIFs); and the
 68`emus` directory containing emoji (used as `:filename:`). These will
 69then be copied into the Fly volume later on by the `start` script. Kinda
 70gross, but whatever.
 71
 72And the `start` script:
 73
 74```sh
 75#!/bin/sh
 76
 77run() {
 78    cp -R /tmp/memes/* "$HONK_DATA_DIR"/memes/
 79    cp -R /tmp/memes/* "$HONK_DATA_DIR"/emus/
 80    cp -R /tmp/local/* "$HONK_DATA_DIR"/views/
 81
 82    honk -datadir "$HONK_DATA_DIR" -viewdir "$HONK_VIEWS_DIR"
 83}
 84
 85# first time setup
 86if [ ! -f "$HONK_DATA_DIR/honk.db" ]; then
 87    honk init <<-EOF
 88    $HONK_USERNAME
 89    $HONK_PASSWORD
 90    $HONK_ADDRESS
 91    $HONK_SERVER_NAME
 92    EOF
 93fi
 94
 95run
 96```
 97
 98This simply copies our stuff from the container into the volume, and
 99launches honk. If the honk database doesn't yet exist, we run `honk
100init` and set it up. These environment variables are configured in the
101`fly.toml` file:
102
103```toml
104app = "honk"
105
106kill_signal = "SIGINT"
107kill_timeout = 5
108processes = []
109
110[mounts]
111  source = "honkstore"
112  destination = "/opt/data"
113
114[env]
115  HONK_USERNAME = "icy"
116  HONK_ADDRESS = "0.0.0.0:8080"
117  HONK_SERVER_NAME = "h.icyphox.sh"
118
119[experimental]
120  allowed_public_ports = []
121  auto_rollback = true
122
123[[services]]
124  http_checks = []
125  internal_port = 8080
126  processes = ["app"]
127  protocol = "tcp"
128  script_checks = []
129
130  [services.concurrency]
131    hard_limit = 50
132    soft_limit = 20
133    type = "connections"
134
135  [[services.ports]]
136    force_https = true
137    handlers = ["http"]
138    port = 80
139
140  [[services.ports]]
141    handlers = ["tls", "http"]
142    port = 443
143
144  [[services.tcp_checks]]
145    grace_period = "1s"
146    interval = "15s"
147    restart_limit = 0
148    timeout = "2s"
149```
150
151The `fly.toml` gets generated when you first run `fly launch`. The only
152bits I've added are the `env` and `mounts` sections. Notice that
153`HONK_PASSWORD` is missing, and for good reason -- Fly has support for
154secrets, which can be created quite handily using:
155
156```sh
157$ flyctl secrets set HONK_PASSWORD="$(pw -s honk)"
158```
159
160## deploy
161
162The only thing left to do is to provision our volume for persistence,
163and we're off to the races:
164
165```sh
166$ flyctl volumes create honkstore --region maa
167        ID: vol_1g67340omkm4ydxw
168      Name: honkstore
169       App: honk
170    Region: maa
171      Zone: aed0
172   Size GB: 10
173 Encrypted: true
174Created at: 21 May 22 16:07 UTC
175
176$ flyctl deploy
177```
178
179## post-deploy
180
181I like having pretty usernames. In this case, I want to drop the `h.`
182subdomain and have it look like this: `icy@icyphox.sh`. To do this, we
183simply set the `masqname` key in the database to our desired
184hostname[^2]:
185
186```sh
187$ honk setconfig 'masqname' 'icyphox.sh'
188```
189
190[^2]: Had to setup a custom domain for this: https://fly.io/docs/app-guides/custom-domains-with-fly/
191
192And at `icyphox.sh`, we setup a redirect to `h.icyphox.sh` at the
193`/.well-known/webfinger` path. I did this [via
194Netlify](https://github.com/icyphox/site/commit/4bbc8335481a0466d7c23953b0f6057f97607ed1);
195you can do it however, as long as the query parameters are preserved.
196Read more about webfingers and other thingamabobs
197[here](https://docs.joinmastodon.org/spec/webfinger/).
198
199I did a bunch more like custom CSS, avatars etc. but I'll leave that as
200homework for you
201([honk(8)](https://humungus.tedunangst.com/r/honk/m/honk.8) is mandatory
202reading!).
203
204## thoughts
205
206**On Fly**: I think it's neat. Rough edges? Sure. My [deploy was stuck
207in
208`pending`](https://community.fly.io/t/app-stuck-in-pending-in-maa-region/5280);
209I had to delete it and re-create it for it to start working again. I
210lost my data in the process because volumes are attached to apps.
211Perhaps I should've waited and the problem would've fixed itself. Who
212knows? 
213
214And that's the eternal problem with PaaS -- there's a layer of
215abstraction that you can't ever pierce. You can't truly know what the
216problem was unless they publish a post-mortem (or don't). Anyway, in
217this case I'll just chalk it up to teething issues.
218
219Is it easier than simply building it on a server and running `nohup
220./honk &` and calling it a day[^3]? Not really. It's more fun, I guess.
221
222[^3]: Yes that's actually how I run a bunch of my services, including
223      [forlater.email](https://forlater.email)!
224
225**On honk**: It's refreshing. I liked running Pleroma + Soapbox (I still
226do, haven't killed it yet), but it always felt alien to me. I didn't
227understand the code, didn't enjoy having to upgrade Elixir/Erlang OTP
228whatever, `mix.deps get` blah blah; a single Go binary + sqlite + HTML
229templates speaks to me.
230
231Go follow me at [icy@icyphox.sh](https://h.icyphox.sh/u/icy). It's why I
232even wrote this post. Not that I can see it, honk doesn't have those
233ego-numbers.
234
235You can find all the source code to deploy honk yourself here:
236https://git.icyphox.sh/honk