How to set up tailscale with a fly.io?

Hello guys!

I am building an fly.io app where I have to use tailscale to assign a ip address to my machine.

I have followed the guide from tailscale (guide here) but my app instance dies after deploying.

It goes like this:

  1. I deploy my app with fly.io command
  2. The docker image gets built
  3. Fly creates a release
  4. App instance dies after 2 restarts

Logs:

2023-04-09T12:35:25Z runner[5a160520] ams [info]Starting instance
2023-04-09T12:35:25Z runner[5a160520] ams [info]Configuring virtual machine
2023-04-09T12:35:25Z runner[5a160520] ams [info]Pulling container image
2023-04-09T12:35:29Z runner[5a160520] ams [info]Unpacking image
2023-04-09T12:35:31Z runner[5a160520] ams [info]Preparing kernel init
2023-04-09T12:35:31Z runner[5a160520] ams [info]Configuring firecracker
2023-04-09T12:35:31Z runner[5a160520] ams [info]Starting virtual machine
2023-04-09T12:35:31Z app[5a160520] ams [info]Starting init (commit: 9e69c24)...
2023-04-09T12:35:31Z app[5a160520] ams [info]Preparing to run: `/bin/sh` as root
2023-04-09T12:35:31Z app[5a160520] ams [info]2023/04/09 12:35:31 listening on [fdaa:0:9e39:a7b:10e:5a16:520:2]:22 (DNS: [fdaa::3]:53)
2023-04-09T12:35:32Z app[5a160520] ams [info]Starting clean up.
2023-04-09T12:35:33Z health[5a160520] ams [warn]Health check on port 8081 is in a 'warning' state. Your app may not be responding properly. Services exposed on ports [80, 443] may have intermittent failures until the health check passes.
2023-04-09T12:35:37Z runner[5a160520] ams [info]Starting instance
2023-04-09T12:35:38Z runner[5a160520] ams [info]Configuring virtual machine
2023-04-09T12:35:38Z runner[5a160520] ams [info]Pulling container image
2023-04-09T12:35:38Z runner[5a160520] ams [info]Unpacking image
2023-04-09T12:35:38Z runner[5a160520] ams [info]Preparing kernel init
2023-04-09T12:35:39Z runner[5a160520] ams [info]Configuring firecracker
2023-04-09T12:35:39Z runner[5a160520] ams [info]Starting virtual machine
2023-04-09T12:35:39Z app[5a160520] ams [info]Starting init (commit: 9e69c24)...
2023-04-09T12:35:39Z app[5a160520] ams [info]Preparing to run: `/bin/sh` as root
2023-04-09T12:35:39Z app[5a160520] ams [info]2023/04/09 12:35:39 listening on [fdaa:0:9e39:a7b:10e:5a16:520:2]:22 (DNS: [fdaa::3]:53)
2023-04-09T12:35:40Z app[5a160520] ams [info]Starting clean up.
2023-04-09T12:35:45Z runner[5a160520] ams [info]Starting instance
2023-04-09T12:35:45Z runner[5a160520] ams [info]Configuring virtual machine
2023-04-09T12:35:45Z runner[5a160520] ams [info]Pulling container image
2023-04-09T12:35:46Z runner[5a160520] ams [info]Unpacking image
2023-04-09T12:35:46Z runner[5a160520] ams [info]Preparing kernel init
2023-04-09T12:35:46Z runner[5a160520] ams [info]Configuring firecracker
2023-04-09T12:35:46Z runner[5a160520] ams [info]Starting virtual machine
2023-04-09T12:35:46Z app[5a160520] ams [info]Starting init (commit: 9e69c24)...
2023-04-09T12:35:46Z app[5a160520] ams [info]Preparing to run: `/bin/sh` as root
2023-04-09T12:35:46Z app[5a160520] ams [info]2023/04/09 12:35:46 listening on [fdaa:0:9e39:a7b:10e:5a16:520:2]:22 (DNS: [fdaa::3]:53)
2023-04-09T12:35:47Z app[5a160520] ams [info]Starting clean up.
2023-04-09T12:35:48Z health[5a160520] ams [warn]Health check on port 8081 is in a 'warning' state. Your app may not be responding properly. Services exposed on ports [80, 443] may have intermittent failures until the health check passes.

start.sh file (bash script):

#!/bin/sh

/app/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/var/run/tailscale/tailscaled.sock &

until /app/tailscale up --authkey=${TAILSCALE_AUTHKEY} --hostname=fly-app
do
    echo "Currently connecting to tailnet"
    sleep 0.1
done
echo "tailscale started"

(PS: Neither the echo messages get printed as you can see from the logs)

Dockerfile (PS: I am running Shopify App)

FROM node:18-alpine

ARG SHOPIFY_API_KEY
ENV SHOPIFY_API_KEY=$SHOPIFY_API_KEY
EXPOSE 8081
WORKDIR /app
COPY web .
RUN npm install
RUN cd frontend && npm install && npm run build
USER root
CMD ["npm", "run", "serve", "/app/start.sh"]

#tailscale

FROM alpine:latest as tailscale
WORKDIR /app
ENV TSFILE=tailscale_1.38.4_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && \
  tar xzf ${TSFILE} --strip-components=1
COPY . ./


# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM alpine:latest
RUN apk update && apk add ca-certificates iptables ip6tables && rm -rf /var/cache/apk/*

# Copy binary to production image
COPY --from=tailscale /app/start.sh /app/start.sh
COPY --from=tailscale /app/tailscaled /app/tailscaled
COPY --from=tailscale /app/tailscale /app/tailscale
RUN mkdir -p /var/run/tailscale
RUN mkdir -p /var/cache/tailscale
RUN mkdir -p /var/lib/tailscale

(PS: Dockerfile gets built successfully)

I am not really sure why my app dies after deployment.

Thanks!

Your Dockerfile is using a multi-stage build, but your CMD is on the first stage so it doesn’t do anything. You need to move it to the final stage.

If you have Docker installed, building and running the image locally will probably give you a better debugging experience.

The multi-stage stuff doesn’t look right to me and will probably need some rethinking: the first stage does stuff with Node, but the final stage ignores the first stage and only copies files from the “tailscale” stage, so the final image won’t contain Node or your web app. I suggest switching to a single-stage build; I don’t know why the Tailscale guide uses a multi-stage build, it seems like overkill.

Hi @tom93 !

Thanks for your answer. I moved now the CMD command to the final stage, as you have mentioned.

But when I run it there occurs an error with permission denied:

2023-04-09T16:23:25.874 runner[aab240a8] ams [info] Starting instance
2023-04-09T16:23:25.990 runner[aab240a8] ams [info] Configuring virtual machine
2023-04-09T16:23:25.998 runner[aab240a8] ams [info] Pulling container image
2023-04-09T16:23:29.099 runner[aab240a8] ams [info] Unpacking image
2023-04-09T16:23:31.928 runner[aab240a8] ams [info] Preparing kernel init
2023-04-09T16:23:32.426 runner[aab240a8] ams [info] Configuring firecracker
2023-04-09T16:23:32.617 runner[aab240a8] ams [info] Starting virtual machine
2023-04-09T16:23:32.972 app[aab240a8] ams [info] Starting init (commit: 9e69c24)...
2023-04-09T16:23:33.009 app[aab240a8] ams [info] Preparing to run: `/app/start.sh npm run serve` as root
2023-04-09T16:23:33.015 app[aab240a8] ams [info] [ 0.126116] Kernel panic - not syncing: AttermissionDenied, message: "Permission denied" })

My updated Dockerfile:

FROM node:18-alpine

ARG SHOPIFY_API_KEY
ENV SHOPIFY_API_KEY=$SHOPIFY_API_KEY
EXPOSE 8081
WORKDIR /app
COPY web .
RUN npm install
RUN cd frontend && npm install && npm run build


#tailscale

FROM alpine:latest as tailscale
WORKDIR /app
ENV TSFILE=tailscale_1.38.4_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && \
  tar xzf ${TSFILE} --strip-components=1
COPY . ./


# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM alpine:latest
RUN apk update && apk add ca-certificates iptables ip6tables && rm -rf /var/cache/apk/*

# Copy binary to production image
COPY --from=tailscale /app/start.sh /app/start.sh
COPY --from=tailscale /app/tailscaled /app/tailscaled
COPY --from=tailscale /app/tailscale /app/tailscale
RUN mkdir -p /var/run/tailscale
RUN mkdir -p /var/cache/tailscale
RUN mkdir -p /var/lib/tailscale

CMD ["/app/start.sh", "npm", "run", "serve"]

Make sure start.sh has the execute permission bit set (if your host is Unix-like, use chmod +x start.sh locally; or put that in the Dockerfile using RUN after the COPY); you can check the permissions using ls -l start.sh.

And the last line of start.sh should be "$@" in order to run the command given in the arguments (npm run serve).

I expect you’ll then get an error saying “npm: command not found”, because of the multi-stage issue I mentioned. Rewriting as a single-stage Dockerfile should be relatively easy (delete/reorder lines).

Hi @tom93 !

That sounds great!

Could you maybe rewrite the Dockerfile for me because I honestly don’t know how to write code for a docker file?

Thanks!

Well, I think Tailscale’s guide is needlessly complicated, so I’ll give you a simplified version.

Start from your app’s original Dockerfile, and insert Tailscale’s commands (apk/wget/tar/mkdir) near the top:

FROM node:18-alpine

WORKDIR /app

# https://tailscale.com/kb/1132/flydotio/ (simplified)
RUN apk update && apk add ca-certificates iptables ip6tables && rm -rf /var/cache/apk/*
ENV TSFILE=tailscale_1.38.4_amd64.tgz
RUN wget https://pkgs.tailscale.com/stable/${TSFILE} && \
  tar xzf ${TSFILE} --strip-components=1
RUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale

ARG SHOPIFY_API_KEY
...

CMD ["/app/start.sh", "npm", "run", "serve"]

You already have start.sh, just don’t forget to add the line "$@" to the end of start.sh.

1 Like

It worked!

Thanks!

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.