ci: publish multi-arch image to GHCR; move status port to 4733

GitHub Actions builds linux/amd64 and linux/arm64 on every push to main and
pushes a single :latest tag to ghcr.io, so the container can be run without
cloning or building. Tests gate the publish step.
This commit is contained in:
Aculix Technologies committed 2026-08-14 14:36:18 +05:30
1 parent b70968d259
commit 77bda09049
6 files changed
+103 -11

No files matched your search

+1 -1
View File
@@ -45,7 +45,7 @@ CURRENCY=₹
# ── Runtime ───────────────────────────────────────────────────────────────────
STATE_PATH=./state.json # Docker image defaults this to /data/state.json
PORT=8080 # status endpoint (--loop mode only)
PORT=4733 # status endpoint (--loop mode only)
# Routes only the site checks through a SOCKS5 proxy; notifications stay direct.
# Needed on datacenter hosts, whose IPs the site's WAF is likely to block.
+49
View File
@@ -0,0 +1,49 @@
name: docker
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: docker-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm test
publish:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
# QEMU lets this amd64 runner build the arm64 half of the manifest.
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
+1 -1
View File
@@ -8,7 +8,7 @@ COPY src/ src/
ENV STATE_PATH=/data/state.json
VOLUME /data
EXPOSE 8080
EXPOSE 4733
# --env-file-if-exists so the container works with plain env vars when no .env is mounted.
CMD ["node", "--env-file-if-exists=.env", "src/index.js", "--loop"]
+47 -6
View File
@@ -1,5 +1,7 @@
# ticket-monitoring
[![docker](https://github.com/aculix/ticket-monitoring/actions/workflows/docker.yml/badge.svg)](https://github.com/aculix/ticket-monitoring/actions/workflows/docker.yml)
Watches [district.in](https://www.district.in) showtimes and sends a max-priority push to your
phone the second tickets go on sale for the movie, date, format and cinema you care about.
@@ -36,18 +38,53 @@ Shows added later still get through.
The [ntfy app](https://ntfy.sh/#subscribe-phone) on your phone, and either Docker or Node.js 22+.
## Quick start with Docker
## Quickest start: run the published image
A prebuilt image is published to GitHub Container Registry on every push to `main`, for both
`linux/amd64` and `linux/arm64`. It runs as-is on a normal server, an Apple Silicon Mac or a
Raspberry Pi, with nothing to clone and nothing to build.
Grab [`.env.example`](.env.example), save it as `.env`, fill it in using "Finding your IDs" below,
then:
```bash
docker run -d --name ticket-monitoring \
--restart unless-stopped \
--env-file .env \
-p 4733:4733 \
-v ticket-monitoring-data:/data \
ghcr.io/aculix/ticket-monitoring:latest
```
```bash
docker logs -f ticket-monitoring
```
You want to see `tick: closed failures: 0` scrolling past once a minute.
The volume is what stops it re-alerting you about shows it already found, so keep it around across
restarts. Drop the `-p` flag if you don't want the status endpoint reachable. To update, pull the
image again and recreate the container:
```bash
docker pull ghcr.io/aculix/ticket-monitoring:latest
docker rm -f ticket-monitoring # then re-run the docker run command above
```
Only `:latest` is published, so that's always the current build of `main`.
## Quick start with Docker Compose
Handy if you'd rather keep the config in a file you can edit in place:
```bash
git clone https://github.com/aculix/ticket-monitoring.git
cd ticket-monitoring
cp .env.example .env # edit it, see "Finding your IDs" below
docker compose up -d --build
docker compose up -d # add --build to build locally instead of pulling
docker compose logs -f
```
You want to see `tick: closed failures: 0` scrolling past once a minute.
## Quick start without Docker
```bash
@@ -110,17 +147,21 @@ Everything is environment variables. `.env` is only a convenient place to put th
| `CURRENCY` | `₹` | Price prefix |
| `EXPIRY_UTC` | *auto* | When to retire. Defaults to local midnight after `TARGET_DATE`. |
| `STATE_PATH` | `./state.json` | Where dedupe state lives, `/data/state.json` in Docker |
| `PORT` | `8080` | Status endpoint |
| `PORT` | `4733` | Status endpoint |
| `PROXY_URL` | | SOCKS5 proxy for the site checks, see below |
## Status endpoint
While running continuously it serves JSON on `PORT`:
While running continuously it serves JSON on `PORT`, which defaults to 4733:
- `/` gives you state, `lastTick` and `proxied`
- `/?force=1` adds a live check right now, with no notifications and no state changes
- `/healthz` returns `{"ok":true}`
```bash
curl -s localhost:4733/ | jq
```
Watch `lastTick.at`. If it's more than a couple of minutes old, the loop is stuck.
## Troubleshooting
+4 -2
View File
@@ -1,11 +1,13 @@
services:
monitor:
# Pulls the prebuilt multi-arch image. Run `docker compose up --build` instead
# to build from this checkout; the result gets tagged with the same name.
image: ghcr.io/aculix/ticket-monitoring:latest
build: .
image: ticket-monitoring
container_name: ticket-monitoring
restart: unless-stopped
env_file: .env
ports:
- "8080:8080" # status endpoint; drop this line to keep it private
- "4733:4733" # status endpoint; drop this line to keep it private
volumes:
- ./data:/data # state survives restarts, so you aren't re-alerted
+1 -1
View File
@@ -55,7 +55,7 @@ export function loadConfig() {
// runtime
statePath: process.env.STATE_PATH || "./state.json",
port: num("PORT", 8080),
port: num("PORT", 4733),
proxyUrl: process.env.PROXY_URL || "",
dispatcher: null, // set by attachProxy() when PROXY_URL is present
};