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