tryzealot/zealot: a self-hosted beta app distribution server for iOS, Android, macOS, Linux and Windows builds
Self-hosted Beta App Distribution for Android, iOS, macOS, Linux and Windows apps | 开源自部署移动应用、 macOS、Linux 和 Windows 应用分发平台,提供 iOS、Android SDK、fastlane 等丰富组件库
At a glance
- What is it?
- Zealot is an MIT-licensed Rails application that hosts beta builds, reads their metadata, syncs iOS test devices and exposes a REST API plus SDKs. It is for teams that want their own OTA distribution endpoint instead of a third-party beta service.
- Who is it for?
- Adopt Zealot if you already run CI and want beta builds served from infrastructure you control, and you are willing to operate a Rails app with PostgreSQL. Skip it if you have no Ruby or container experience on the team, or if you only need to hand a single IPA to one tester once.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Zealot replaces, and who ends up running it
Beta distribution is usually the step where a CI pipeline stops being automated. The build finishes, an artifact lands somewhere, and then a human copies a link into a chat message. Zealot exists to remove that step. The README describes it as a self-hosted platform that connects to any CI system and handles the lifecycle of an app: build, distribute to testers, and push toward stores. The topics list on the repository names the integrations it targets directly: fastlane, Jenkins, GitLab, adhoc, over-the-air, and the Chinese distribution services fir and pgyer.
The audience is narrow and specific. It is a team that already has a build server and wants the distribution half of the chain to live on its own hardware. The multi-platform claim in the feature list is broad: macOS, iOS, Android (apk and aab), Windows and Linux. That breadth is the reason a single release page cannot be a thin file server. An APK, an IPA, a macOS app bundle and a Windows installer each carry different metadata, and the README's feature list says Zealot parses the metadata inside iOS and Android apps and iOS provisioning profiles. That parsing is what makes a build list searchable by bundle identifier or version rather than by filename.
One feature is worth separating from the rest. The README states that Zealot syncs iOS test device information automatically and can register new devices with the Apple Developer account in one action. That is a workflow problem specific to iOS ad hoc distribution, and it is the kind of thing a generic artifact store will never do. If your team distributes only Android, that capability is dead weight, and a simpler artifact host will do.
The architecture visible in the repository layout
Zealot is a Ruby on Rails application, and the top-level entries make that plain: app/, config/, db/, Gemfile, Gemfile.lock, Procfile, config.ru and a Rakefile. There is a Dockerfile, a docker/ directory, and deployment descriptors for Fly.io (fly.toml) and Render (render.yaml). The frontend is separate but built by the same process: package.json declares Vite, Tailwind CSS 4, daisyUI, Turbo and Stimulus, and the Dockerfile runs bin/rails vite:build during the image build. So the browser layer is not a second service you deploy; it is compiled into the Rails asset output.
The build stage of the Dockerfile gives a clear picture of the runtime dependencies. It installs build-base, libxml2, libxslt and git, then a development set that includes postgresql-dev, nodejs, npm, pnpm, imagemagick-dev, libwebp-dev, libpng-dev and tiff-dev. PostgreSQL is therefore the expected database, and ImageMagick plus the webp and png libraries are present because the application processes images. Ruby 3.4.8 on Alpine is the base image, and the file sets RUBY_YJIT_ENABLE to true.
Two details in that Dockerfile are worth flagging for anyone outside China. The build arguments REPLACE_CHINA_MIRROR, ORIGINAL_REPO_URL, MIRROR_REPO_URL, RUBYGEMS_SOURCE and NPM_REGISTRY default to mirror endpoints (mirrors.ustc.edu.cn, gems.ruby-china.com, registry.npmmirror.com) and the mirror substitution runs when REPLACE_CHINA_MIRROR is true, which is the default. Building the image from a network outside China means either overriding those arguments or accepting the extra latency of reaching Chinese mirrors. The README does not discuss this trade-off, but the default is right there in the file.
On the data side, the repository ships db/ and swagger/, so the schema and an API description are part of the source tree rather than external documentation. The README links a REST API page and separate iOS and Android SDK repositories, plus a fastlane plugin repository. That is the integration surface: an HTTP API for anything custom, native SDKs for app-side checks, and a fastlane action for pipelines that already use fastlane.
Installing Zealot and uploading a first build
The README does not inline installation steps. It points to https://zealot.ews.im/docs/self-hosted for the self-hosted guide and links a Docker image at ghcr.io/tryzealot/zealot. The repository itself carries a Dockerfile, a docker/ directory, config.env and deployment descriptors for Fly.io and Render, so a container is the intended path. The exact compose file is not part of the repository files available here, so the steps below stop at the image and the environment file rather than inventing a service definition.
Configuration is environment-driven. The repository root contains config.env, and the Dockerfile sets RAILS_ENV to production and BUNDLE_APP_CONFIG under /app. Read config.env in the tag you deploy and supply the values your deployment needs; the README does not enumerate the keys, so treat the file as the source of truth rather than a blog post. PostgreSQL is required, since the build stage installs postgresql-dev.
Once the container is up, the first real use is an upload. The README advertises a REST API, and the repository contains swagger/ describing it. The pattern is to authenticate, then post an artifact; the API page at https://zealot.ews.im/docs/developer-guide/api is where the concrete request shape lives. After the upload, the web interface should show the build with parsed metadata, and the release page becomes the OTA link you hand to testers.
For pipelines, the fastlane plugin at github.com/tryzealot/fastlane-plugin-zealot is the intended hook. The README lists it as one of the developer components alongside the iOS and Android SDKs, so a lane that already builds and signs an app can add an upload step without shell scripting against the HTTP API.
If you want to look before installing, the README publishes a demo at https://tryzealot.ews.im with the accounts [email protected] and [email protected], both using the password ze@l0t. The README warns that demo data is reinitialized daily and that uploaded apps carry no liability for the operators.
Where Zealot is the wrong choice
The first limitation is operational weight. This is a Rails application with a PostgreSQL dependency, an asset build step, background processing implied by the Procfile, and image processing libraries in the container. That is a normal production service, not a static file server. A team that wants to drop an IPA behind nginx and call it distribution will find Zealot heavier than the problem.
The second is the iOS device registration feature. It is genuinely useful, but it depends on credentials for the Apple Developer account and on the device sync path working. The README describes the capability and does not describe what happens when the Apple side rejects a registration, or how to recover a device that was registered but never appears. Anyone relying on that workflow should treat the failure path as undocumented until they read the user guide.
The third is documentation depth in the README itself. The feature list is a list of capabilities, not a manual. Installation, API shapes and user workflows all live on the external docs site. If that site is unreachable or lags the release you deployed, the README will not save you. The self-hosted guide is the only install path named.
The fourth is the build-time mirror default described earlier. It is a real constraint for teams outside China, and it is buried in Dockerfile arguments rather than mentioned in the README.
Finally, consider the scope. Zealot is for teams distributing to testers and toward stores. If your only need is a signed download link for one person, or you have no CI system at all, the integration surface (REST API, SDKs, fastlane plugin) is value you will never collect.
Zealot against a generic artifact host or a hosted beta service
The nearest alternative in kind is a general artifact repository such as a Nexus or Artifactory instance, or simply object storage with signed URLs. Those solve storage and access control well. They do not parse an IPA for its bundle identifier, they do not read an Android manifest, and they cannot register an iOS device with Apple. The difference is not storage versus distribution; it is whether the server understands what an app build is. Zealot's feature list is built around that understanding, and that is the whole reason to run it instead of a bucket.
The other alternative is a hosted beta distribution service, the category the repository's own topics gesture at with fir and pgyer. Those remove the operational burden entirely: no PostgreSQL, no container, no upgrades. The trade is that your builds, your tester list and your device identifiers live on someone else's infrastructure, and the terms can change without your involvement. Zealot's answer is that you run it. The cost of that answer is everything in the previous section.
A third comparison is the CI system's own artifact storage. Jenkins, GitLab and the rest can attach build outputs to a job. That works until you need a stable install page, device management, or a build history that testers can browse without CI credentials. Zealot is the layer above CI, not a replacement for it, and the README frames it that way: connect your CI, then distribute.
Upgrades, maintenance and the MIT licence
The repository is not archived, and the last push was on 2026-09-08. Recent releases are 6.2.2 on 2026-07-25, 6.2.1 on 2026-07-23 and 6.2.0 on 2025-12-18. The gap between 6.2.0 and 6.2.1 is roughly seven months, which is worth noting when planning an upgrade cadence: point releases have arrived in bursts, not on a fixed schedule. The CHANGELOG.md at the repository root is the place to read before moving between versions.
Upgrade cost is dominated by the database and the asset pipeline. The image builds Vite assets at build time and the application expects PostgreSQL, so a version bump means pulling the new image, letting migrations run, and confirming the frontend build matches. Pinning a tag such as 6.2.2 and reading the changelog for the range you cross is the conservative approach. The README does not document a rollback procedure, so a database backup before the upgrade is the only safety net the repository files support.
Licensing is straightforward: the project is MIT, and the README links the LICENSE file on the develop branch. MIT permits commercial and private use, modification and redistribution, with the licence and copyright notice retained. That is a permissive arrangement, and it is a different posture from hosted services whose terms you accept rather than read. This is a description of the licence text, not legal advice; if the distribution of your own app involves other agreements, those are separate questions.
One thing the repository files do not settle is the long-term maintenance model. The README lists donation channels (Afdian, GitHub Sponsors, Buy Me A Coffee), which suggests a project sustained by its maintainer and users rather than a company. That is not a defect, but it is a fact to weigh when the distribution endpoint for your releases depends on it.
Editorial conclusion
Adopt Zealot if you already run CI and want beta builds served from infrastructure you control, and you are willing to operate a Rails app with PostgreSQL. Skip it if you have no Ruby or container experience on the team, or if you only need to hand a single IPA to one tester once. Before committing, verify that the amd64 or arm64 image for release 6.2.2 starts against your PostgreSQL, that your chosen third-party login provider (Feishu, GitLab, GitHub, Google, LDAP or OIDC) is actually configured, and that the REST API endpoints you plan to call exist in the swagger directory of the tag you deploy.
Frequently asked questions
What is tryzealot/zealot?
It is a self-hosted beta app distribution platform for Android, iOS, macOS, Linux and Windows builds, written in Ruby on Rails and released under the MIT licence. The README describes it as connecting to any CI system and automating the lifecycle of an app through build and distribution.
How do I install Zealot?
The README points to the self-hosted guide at https://zealot.ews.im/docs/self-hosted and publishes a Docker image at ghcr.io/tryzealot/zealot. The repository also contains a Dockerfile, a docker/ directory, config.env and deployment descriptors for Fly.io and Render.
Which platforms does Zealot support for app distribution?
The feature list names macOS, iOS, Android (apk and aab), Windows and Linux. The README also states that Zealot parses metadata from iOS and Android apps and from iOS provisioning profiles.
Can Zealot register iOS test devices automatically?
The README states that Zealot syncs iOS test device information automatically and allows one-click registration of new devices to the Apple Developer account. The failure path for a rejected registration is not described in the README.
Does Zealot provide a REST API and SDKs?
Yes. The README links a REST API page, separate iOS and Android SDK repositories, and a fastlane plugin repository. The repository also contains a swagger/ directory describing the API.
What licence does Zealot use?
The project is MIT licensed, and the README links the LICENSE file on the develop branch. That permits commercial and private use, modification and redistribution provided the licence and copyright notice are retained.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tryzealot-zealot)