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.h](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