├── .github └── workflows │ └── apk.yaml ├── .gitmodules ├── Dockerfile ├── Makefile ├── README.md └── custom_server.patch.tpl /.github/workflows/apk.yaml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | jobs: 4 | apk: 5 | runs-on: ubuntu-latest 6 | container: 7 | image: ghcr.io/${{ github.repository }} 8 | credentials: 9 | username: ${{ github.actor }} 10 | password: ${{ secrets.CR_PAT }} 11 | steps: 12 | - uses: actions/checkout@v3 13 | with: 14 | submodules: true 15 | - name: make apk 16 | env: 17 | TAILSCALE_SERVER: ${{ secrets.TAILSCALE_SERVER }} 18 | run: | 19 | make patch 20 | make apk 21 | - name: save apk artifact 22 | uses: actions/upload-artifact@v3 23 | with: 24 | name: apk 25 | path: tailscale-android/tailscale-debug.apk 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tailscale-android"] 2 | path = tailscale-android 3 | url = git@github.com:tailscale/tailscale-android.git 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tailscale-android 2 | 3 | RUN apt-get install -y patch gettext-base 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docker patch apk 2 | 3 | ANDROID_REPO := tailscale-android/ 4 | PATCHFILES := custom_server.patch 5 | DOCKER_TAG := tailscale-android 6 | 7 | docker: 8 | docker build -t $(DOCKER_TAG) $(ANDROID_REPO) && \ 9 | docker build -t $(DOCKER_TAG)-builder -f Dockerfile . 10 | 11 | $(PATCHFILES): 12 | envsubst '$$TAILSCALE_SERVER' < $@.tpl > $@ 13 | patch -d $(ANDROID_REPO) -p1 < $@ 14 | 15 | patch: $(PATCHFILES) 16 | 17 | apk: 18 | make -C $(ANDROID_REPO) tailscale-debug.apk 19 | 20 | clean: 21 | rm -f $(PATCHFILES) 22 | git -C $(ANDROID_REPO) reset --hard 23 | git -C $(ANDROID_REPO) clean -dfx 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### tailscale android builder 2 | 3 | This repo will build the tailscale android client with a custom server url 4 | using github actions. 5 | 6 | ### Usage: 7 | 8 | 1. Fork this repo 9 | 2. Configure secrets for github actions: 10 | 11 | * `CR_PAT`: personal access token with read access to ghcr 12 | * `TAILSCALE_SERVER`: FQDN of tailscale server: e.g. https://controlplane.tailscale.com 13 | 14 | 3. Build the "builder image" for the apk: 15 | 16 | ``` 17 | make docker 18 | ``` 19 | 20 | 4. Push the builder image to ghcr: 21 | 22 | ``` 23 | docker tag tailscale-android-builder ghcr.io//tailscale-android-builder 24 | docker push ghcr.io//tailscale-android-builder 25 | ``` 26 | 27 | 5. Trigger a workflow run in github actions. The apk will be stored as an 28 | artifact of the build. Recommend deleting the artifact after downloading 29 | from github if it is public, as this will contain your personal control 30 | plane server fqdn. 31 | 32 | ### versioning: 33 | 34 | The tailscale-android repo is a submodule. Update the submodule commit sha to 35 | the target release and push to recreate a new apk. 36 | -------------------------------------------------------------------------------- /custom_server.patch.tpl: -------------------------------------------------------------------------------- 1 | diff --git a/cmd/tailscale/backend.go b/cmd/tailscale/backend.go 2 | index 966689d..d258147 100644 3 | --- a/cmd/tailscale/backend.go 4 | +++ b/cmd/tailscale/backend.go 5 | @@ -136,8 +136,11 @@ func newBackend(dataDir string, jvm *jni.JVM, appCtx jni.Object, store *stateSto 6 | 7 | func (b *backend) Start(notify func(n ipn.Notify)) error { 8 | b.backend.SetNotifyCallback(notify) 9 | + prefs := ipn.NewPrefs() 10 | + prefs.ControlURL = "$TAILSCALE_SERVER" 11 | return b.backend.Start(ipn.Options{ 12 | - StateKey: "ipn-android", 13 | + StateKey: "ipn-android", 14 | + UpdatePrefs: prefs, 15 | }) 16 | } 17 | 18 | --------------------------------------------------------------------------------