-
Notifications
You must be signed in to change notification settings - Fork 14
Publish container image on release; Coolify catalog submission kit #145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # Coolify one-click service template (submission kit) | ||
|
|
||
| Everything needed to get Prosper202 listed in Coolify's one-click service | ||
| catalog (<https://coolify.io/services>), prepared and ready to submit. The | ||
| catalog is generated from the [`coollabsio/coolify`](https://github.com/coollabsio/coolify) | ||
| repository — listing means getting a PR merged there. | ||
|
|
||
| ## Contents | ||
|
|
||
| | File | Submits to (in coollabsio/coolify) | | ||
| |------|-------------------------------------| | ||
| | `prosper202.yaml` | `templates/compose/prosper202.yaml` | | ||
| | `svgs/prosper202.svg` | `svgs/prosper202.svg` | | ||
|
|
||
| The template mirrors the repo's `docker-compose.coolify.yaml`, except it pulls | ||
| the published image (`ghcr.io/tracking202/prosper202`) instead of building | ||
| from git — one-click services never clone the repository. | ||
|
|
||
| ## Prerequisites (in order) | ||
|
|
||
| 1. **A published container image.** The release workflow | ||
| (`.github/workflows/release.yml`, `docker-image` job) publishes | ||
| `ghcr.io/tracking202/prosper202:{version,latest}` (amd64 + arm64) on every | ||
| `vX.Y.Z` tag using the built-in `GITHUB_TOKEN` — no registry account | ||
| needed. **One manual step after the first tagged release:** the GHCR | ||
| package is created private; open the package's settings on GitHub and set | ||
| it to **Public** so anonymous `docker pull` works. | ||
| 2. **Coolify's star requirement.** The contribution guide | ||
| (<https://coolify.io/docs/get-started/contribute/service>) asks that the | ||
| service's repository have **at least 1,000 GitHub stars**. Until the repo | ||
| crosses that bar, either open a GitHub Discussion with the Coolify | ||
| maintainers making the case for an exception, or hold the submission. | ||
| Everything else here stays valid either way. | ||
|
|
||
| ## Submission checklist | ||
|
|
||
| 1. Fork `coollabsio/coolify` on GitHub. | ||
| 2. Copy `prosper202.yaml` to `templates/compose/prosper202.yaml` and | ||
| `svgs/prosper202.svg` to `svgs/prosper202.svg`. (Replace the placeholder | ||
| SVG with official vector brand art if available — the metadata header's | ||
| `logo:` line already points at the right path.) | ||
| 3. Regenerate/reference the parsed templates per their contribution guide | ||
| (`templates/service-templates.json`). | ||
| 4. **Test first**: on any Coolify instance, create a resource via | ||
| **Docker Compose Empty**, paste `prosper202.yaml` (without the metadata | ||
| comments), set a domain on the `prosper202` service, deploy, and complete | ||
| the setup wizard. | ||
| 5. Open the PR. After it merges, add the docs page | ||
| (`/docs/services/prosper202.md` in their docs) so the service appears on | ||
| the website listing. | ||
|
|
||
| ## Keeping the template in sync | ||
|
|
||
| `prosper202.yaml` is derived from `../../docker-compose.coolify.yaml`. If that | ||
| stack changes (new env vars, volumes, services), update this template in the | ||
| same commit — and after the catalog listing exists, upstream the same change | ||
| to `coollabsio/coolify`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| # documentation: https://prosper202.com | ||
| # slogan: Self-hosted PPC and affiliate conversion tracking platform (ClickServer). | ||
| # category: analytics | ||
| # tags: tracking, affiliate, ppc, analytics, marketing, conversion, clickserver | ||
| # logo: svgs/prosper202.svg | ||
| # port: 80 | ||
|
|
||
| # Ready-to-submit Coolify one-click service template for Prosper202. | ||
| # Submission target: templates/compose/prosper202.yaml in coollabsio/coolify | ||
| # (see the README next to this file for the submission checklist). | ||
| # | ||
| # Mirrors the repo's docker-compose.coolify.yaml, except it pulls the | ||
| # published image instead of building from a git checkout — one-click | ||
| # services never clone the repository. The container self-writes its | ||
| # database config from the environment on boot, so the setup wizard opens | ||
| # with the database step already completed. | ||
|
|
||
| services: | ||
| prosper202: | ||
| image: ghcr.io/tracking202/prosper202:latest | ||
| environment: | ||
| # FQDN routes the assigned domain to this service on port 80; URL is the | ||
| # same domain with the scheme, declared so Coolify generates it — the | ||
| # worker consumes it as P202_PUBLIC_ORIGIN for webhook download links. | ||
| - SERVICE_FQDN_PROSPER202_80 | ||
|
Comment on lines
+21
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Only Useful? React with 👍 / 👎.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed — this was a lesson already applied to Generated by Claude Code |
||
| - SERVICE_URL_PROSPER202 | ||
| - APP_ENV=production | ||
|
Copilot marked this conversation as resolved.
|
||
| # In-app 1-click upgrade writes to the ephemeral container filesystem; | ||
| # upgrades arrive as new image tags instead. | ||
| - P202_DISABLE_AUTO_UPGRADE=1 | ||
| - MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL:?} | ||
| - MYSQL_DATABASE=${MYSQL_DATABASE:-prosper202} | ||
| - DB_HOST=db | ||
| - MC_HOST=memcached | ||
| # REST API v3 job/idempotency state — persisted outside the docroot. | ||
| - P202_SERVER_STATE_DIR=/var/lib/prosper202/api-v3-state | ||
| # Uploaded MaxMind ISP databases — persisted outside the docroot. | ||
| - P202_GEO_DIR=/var/lib/prosper202/geo | ||
| volumes: | ||
| - prosper202-exports:/var/www/html/202-config/temp/attribution-exports | ||
| - prosper202-api-state:/var/lib/prosper202/api-v3-state | ||
| - prosper202-geo:/var/lib/prosper202/geo | ||
| depends_on: | ||
| db: | ||
| condition: service_healthy | ||
| memcached: | ||
| condition: service_started | ||
| healthcheck: | ||
| test: ["CMD", "php", "-r", "exit(@file_get_contents('http://127.0.0.1/health/') === false ? 1 : 0);"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 12 | ||
| start_period: 30s | ||
|
|
||
| db: | ||
| image: mysql:8.0 | ||
| environment: | ||
| - MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL:?} | ||
| - MYSQL_DATABASE=${MYSQL_DATABASE:-prosper202} | ||
| volumes: | ||
| - prosper202-mysql-data:/var/lib/mysql | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p\"$${MYSQL_ROOT_PASSWORD}\""] | ||
| interval: 5s | ||
| timeout: 5s | ||
| retries: 24 | ||
|
|
||
| memcached: | ||
| image: memcached:1.6-alpine | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "nc -z 127.0.0.1 11211"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 6 | ||
|
|
||
| # Polls the scheduled-jobs endpoint once a minute (it has its own lock and | ||
| # frequency tiers), replacing a host crontab. | ||
| cron: | ||
| image: alpine:3.20 | ||
| restart: unless-stopped | ||
| depends_on: | ||
| prosper202: | ||
| condition: service_started | ||
| command: > | ||
| sh -c 'while true; do | ||
| wget -q -O /dev/null http://prosper202/202-cronjobs/index.php || true; | ||
| sleep 60; | ||
| done' | ||
| healthcheck: | ||
| test: ["CMD", "true"] | ||
| interval: 30s | ||
|
|
||
| # Standalone CLI workers the HTTP cron endpoint does not cover: attribution | ||
| # export queue and API v3 sync worker every minute, snapshot rebuild hourly. | ||
| # Runs the same image as the web service, as the web user, sharing the | ||
| # export/state volumes. | ||
| worker: | ||
| image: ghcr.io/tracking202/prosper202:latest | ||
| restart: unless-stopped | ||
| user: www-data | ||
| environment: | ||
| - APP_ENV=production | ||
| - P202_DISABLE_AUTO_UPGRADE=1 | ||
| - MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL:?} | ||
| - MYSQL_DATABASE=${MYSQL_DATABASE:-prosper202} | ||
| - DB_HOST=db | ||
| - MC_HOST=memcached | ||
| - P202_SERVER_STATE_DIR=/var/lib/prosper202/api-v3-state | ||
| - P202_GEO_DIR=/var/lib/prosper202/geo | ||
| # Public origin for webhook download links (no request context in CLI). | ||
| - P202_PUBLIC_ORIGIN=${SERVICE_URL_PROSPER202:-} | ||
| volumes: | ||
| - prosper202-exports:/var/www/html/202-config/temp/attribution-exports | ||
| - prosper202-api-state:/var/lib/prosper202/api-v3-state | ||
| - prosper202-geo:/var/lib/prosper202/geo | ||
| depends_on: | ||
| db: | ||
| condition: service_healthy | ||
| memcached: | ||
| condition: service_started | ||
| command: | ||
| - bash | ||
| - -c | ||
| - | | ||
| last_rebuild=0 | ||
| while true; do | ||
| php 202-cronjobs/attribution-export.php || true | ||
| php 202-cronjobs/sync-worker.php || true | ||
| now=$$(date +%s) | ||
| if [ $$((now - last_rebuild)) -ge 3600 ]; then | ||
| php 202-cronjobs/attribution-rebuild.php || true | ||
| last_rebuild=$$now | ||
| fi | ||
| sleep 60 | ||
| done | ||
| healthcheck: | ||
| test: ["CMD", "true"] | ||
| interval: 30s | ||
|
|
||
| volumes: | ||
| prosper202-mysql-data: | ||
| prosper202-exports: | ||
| prosper202-api-state: | ||
| prosper202-geo: | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
docker-imagejob has no dependency onrelease, so both jobs run independently. When av*tag fails the version check or the release artifact build, this job can still push that commit under both its version tag andlatest, making an invalid release available to the Coolify template even though no corresponding GitHub Release was published; make image publication depend on successful release validation.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed — without the dependency, a tag failing the tag-vs-version.php check could still ship an image and move
latestwith no corresponding Release. Fixed in c3a4c32:docker-imagenowneeds: release.Generated by Claude Code