$ fly launch --no-deploy --force-machines
The fly launch
command generates a Dockerfile
, a fly.toml
configuration and some release files into your Phoenix app. It will even set SECRET_KEY_BASE
for you.
$ fly volumes create myapp_data --size 1
The following represents the proper changes for DATABASE_PATH
:
# fly.toml
+[mounts]
+ source = "myapp_data"
+ destination = "/data"
[env]
+ DATABASE_PATH = "/data/myapp_data/my_app_prod.db"
PHX_HOST = "spicy-burrito-2702.fly.dev"
PORT = "8080"
Remove the migrate command:
# fly.toml
-[deploy]
- release_command = "/app/bin/migrate"
So how to run migrations? I invoke the release migrate function from Application.start/2
on the sage advice of @chrismccord:
# lib/my_app/application.ex
def start(_type, _args) do
# Run migrations
MyApp.Release.migrate()
children = [
#children...
]
#Supervisor...
end
create start.sh
#!/bin/bash
set -e
/app/bin/migrate
/app/bin/server
..and modify Dockerfile
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/my_app ./
+ COPY --chown=nobody:root --chmod=755 start.sh ./
USER nobody
- CMD ["/app/bin/server"]
+ CMD ["/app/start.sh"]
Tailscale docs for running on Fly.io
Create Tailscale auth key and save it as fly secret
flyctl secrets set TAILSCALE_AUTHKEY="tskey-<key>"
Dockerfile changes
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
+ FROM alpine:latest as tailscale
+ WORKDIR /app
+ ENV TSFILE=tailscale_1.38.2_amd64.tgz
+ RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && tar xzf ${TSFILE} --strip-components=1
FROM ${BUILDER_IMAGE} as builder
...
FROM ${RUNNER_IMAGE}
RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \
+ ca-certificates iptables sudo \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
+ RUN update-alternatives --set iptables /usr/sbin/iptables-legacy
+ RUN update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
...
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/my_app ./
+ COPY --from=tailscale /app/tailscaled /app/tailscaled
+ COPY --from=tailscale /app/tailscale /app/tailscale
+
+ RUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale
+
COPY --chown=nobody:root --chmod=755 start.sh ./
- USER nobody
- CMD ["/app/bin/server"]
+ CMD ["/app/start.sh"]
start.sh
#!/bin/bash
set -e
+ echo "Starting Tailscale"
+ /app/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/var/run/tailscale/tailscaled.sock &
+ /app/tailscale up --authkey=${TAILSCALE_AUTHKEY} --hostname=my_app
echo "Starting app in start.sh ..."
- /app/bin/migrate
- /app/bin/server
+ sudo -E -u nobody /app/bin/migrate
+ sudo -E -u nobody /app/bin/server
config/runtime.exs
host = System.get_env("PHX_HOST") || "example.com"
port = String.to_integer(System.get_env("PORT") || "4000")
config :my_app, MyAppWeb.Endpoint,
- url: [host: host, port: 443, scheme: "https"],
+ url: [host: host, port: port, scheme: "http"],
+ check_origin: [
+ "//#{host}:#{port}",
+ "//my_app:#{port}"
+ ],
http: [
# Enable IPv6 and bind on all interfaces.
# Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
# See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html
# for details about using IPv6 vs IPv4 and loopback vs public addresses.
ip: {0, 0, 0, 0, 0, 0, 0, 0},
port: port
],
secret_key_base: secret_key_base
fly.toml
[env]
DATABASE_PATH = "/data/my_app_data/my_app_prod.db"
- PHX_HOST = "arbitrary-fly-url-4555.fly.dev"
+ PHX_HOST = "my-device.my-tailnet-name.ts.net"
PORT = "8080"
- [[services]]
- internal_port = 8080
- processes = ["app"]
- protocol = "tcp"
- [services.concurrency]
- hard_limit = 1000
- soft_limit = 1000
- type = "connections"
- [[services.ports]]
- force_https = true
- handlers = ["http"]
- port = 80
- [[services.ports]]
- handlers = ["tls", "http"]
- port = 443