Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@ name: Publish
# per Docker convention (git tag `v1.0.0` -> docker tag `1.0.0`); `:latest`
# auto-attaches via the default `latest=auto` flavor of `type=semver`.
#
# Every release is built twice from the same Dockerfile: the default image, and a
# `-fonts` flavor built with `CAMOUFOX_KEEP_SPOOFED_OS_FONTS=1` so the spoofed
# Windows/macOS font bundles stay in the image (+~891MB). The pool spoofs those
# OSes per browser, so rendered output (screenshots, MHTML) from the default image
# shows tofu for any non-Linux fingerprint; the `-fonts` flavor is for callers who
# consume rendered output rather than HTML.
#
# Lives separately from publish-nightly.yml (main branch pushes) and
# publish-baseline.yml (baseline runtime pushes). `v*-baseline` is
# intentionally excluded so a baseline-only release doesn't also push
# `:X.Y.Z`/`:latest` — publish-baseline.yml owns that path.
#
# Tag contract:
# - push `v*` -> :X.Y.Z + :latest
# - push `v*` -> :X.Y.Z + :latest, and :X.Y.Z-fonts + :latest-fonts
# - push `v*-baseline` -> nothing here (excluded)
# - push `main` -> nothing here (handled by publish-nightly.yml)

Expand All @@ -37,6 +44,8 @@ jobs:
needs: verify
strategy:
matrix:
platform: [linux/amd64, linux/arm64]
flavor: [default, fonts]
include:
- platform: linux/amd64
runner: ubuntu-latest
Expand Down Expand Up @@ -82,8 +91,10 @@ jobs:
push: true
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true
cache-from: type=gha,scope=trawl-release-${{ matrix.platform }}
cache-to: type=gha,scope=trawl-release-${{ matrix.platform }},mode=max
cache-from: type=gha,scope=trawl-release-${{ matrix.flavor }}-${{ matrix.platform }}
cache-to: type=gha,scope=trawl-release-${{ matrix.flavor }}-${{ matrix.platform }},mode=max
build-args: |
CAMOUFOX_KEEP_SPOOFED_OS_FONTS=${{ matrix.flavor == 'fonts' && '1' || '0' }}
secrets: |
GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}

Expand All @@ -95,14 +106,17 @@ jobs:

- uses: actions/upload-artifact@v7
with:
name: digests-release-${{ env.PLATFORM_PAIR }}
name: digests-release-${{ matrix.flavor }}-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

merge:
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
flavor: [default, fonts]
permissions:
contents: read
packages: write
Expand All @@ -115,7 +129,7 @@ jobs:
- uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-release-*
pattern: digests-release-${{ matrix.flavor }}-*
merge-multiple: true

- uses: docker/login-action@v4
Expand All @@ -130,6 +144,9 @@ jobs:
id: meta
with:
images: ${{ env.IMAGE }}
# The fonts build carries a `-fonts` suffix on every tag, `:latest` included
# (`onlatest=true`), so it never shadows the default image's tags.
flavor: ${{ matrix.flavor == 'fonts' && 'suffix=-fonts,onlatest=true' || '' }}
tags: |
# Versioned release tag: git tag v1.0.0 → docker tag 1.0.0 (strips the v prefix,
# per Docker convention; type=ref would mirror the v through). type=semver also
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Publish a `-fonts` flavor of every release image (`:X.Y.Z-fonts`, `:latest-fonts`) built with `CAMOUFOX_KEEP_SPOOFED_OS_FONTS=1`, so callers who consume `screenshot` output can pull an image whose spoofed Windows/macOS font bundles are present instead of building one.

## [1.5.0] - 2026-09-04

### Changed
Expand Down
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,24 +330,29 @@ Tier 4: Residential proxy ──── success ──→ cache + return (15–45
| `docker-compose.minimal.yml` | Scraper only, no Redis |
| `docker-compose.prod.yml` | Production: `restart: always`, memory limit, healthcheck |

## Docker images (one GHCR package, two tags)
## Docker images (one GHCR package, three tags)

| Image tag | Built from | Runtime | Use case |
| ---------------------------------- | ------------------------------ | ----------------------------- | ---------------------------------------------------------- |
| `ghcr.io/germondai/trawl:latest` | `apps/api/Dockerfile` | Bun 1.4.0 (modern, AVX2) | Default — modern Linux amd64/arm64 |
| `ghcr.io/germondai/trawl:baseline` | `apps/api/Dockerfile.baseline` | Bun 1.4.0 baseline (no AVX2) | Older CPUs / older kernels (Synology NAS, J4125, Atom-era) |
| Image tag | Built from | Runtime | Use case |
| -------------------------------------- | ------------------------------ | ----------------------------- | ---------------------------------------------------------- |
| `ghcr.io/germondai/trawl:latest` | `apps/api/Dockerfile` | Bun 1.4.0 (modern, AVX2) | Default — modern Linux amd64/arm64 |
| `ghcr.io/germondai/trawl:latest-fonts` | `apps/api/Dockerfile` | Bun 1.4.0 (modern, AVX2) | Same image built with `CAMOUFOX_KEEP_SPOOFED_OS_FONTS=1` — for `screenshot` consumers (+~891 MB) |
| `ghcr.io/germondai/trawl:baseline` | `apps/api/Dockerfile.baseline` | Bun 1.4.0 baseline (no AVX2) | Older CPUs / older kernels (Synology NAS, J4125, Atom-era) |

Both tags live on the same `ghcr.io/germondai/trawl` package — they share the registry but use different Dockerfile sources. Pick whichever tag fits your hardware:
All tags live on the same `ghcr.io/germondai/trawl` package — they share the registry but differ in Dockerfile source or build arguments. Pick whichever tag fits your hardware and output:

```yaml
# Modern hardware (most users)
image: ghcr.io/germondai/trawl:latest

# Rendered output: the pool spoofs Windows/macOS per browser, and the default image
# drops those font bundles, so screenshots of a non-Linux fingerprint render as tofu.
image: ghcr.io/germondai/trawl:latest-fonts

# Older CPUs without AVX2 / Synology / older kernels
image: ghcr.io/germondai/trawl:baseline
```

Synology note: many Synology NAS units (DSM 7.x on J4125 / older hardware) ship kernel 4.4.x, which Bun's modern runtime can't fully handle. Standard Bun requires kernel 5.1+ (5.6+ recommended); the baseline build degrades gracefully down to kernel 3.10. The `:baseline` tag is published for that case — **confirmed working** on a Synology DS920+ (Celeron J4125, DSM 7.3.2, kernel 4.4.302): the container starts cleanly, `/health` reports healthy, and it solves live Cloudflare challenges via `/v1` (see [#1](https://github.com/germondai/trawl/issues/1)). Published by independent GitHub Actions workflows: pushing `v1.5.0` creates `:1.5.0`, `:latest`, `:1.5.0-baseline`, and `:baseline`; pushing `main` creates `:nightly` and `:nightly-<sha>`.
Synology note: many Synology NAS units (DSM 7.x on J4125 / older hardware) ship kernel 4.4.x, which Bun's modern runtime can't fully handle. Standard Bun requires kernel 5.1+ (5.6+ recommended); the baseline build degrades gracefully down to kernel 3.10. The `:baseline` tag is published for that case — **confirmed working** on a Synology DS920+ (Celeron J4125, DSM 7.3.2, kernel 4.4.302): the container starts cleanly, `/health` reports healthy, and it solves live Cloudflare challenges via `/v1` (see [#1](https://github.com/germondai/trawl/issues/1)). Published by independent GitHub Actions workflows: pushing `v1.5.0` creates `:1.5.0`, `:latest`, `:1.5.0-fonts`, `:latest-fonts`, `:1.5.0-baseline`, and `:baseline`; pushing `main` creates `:nightly` and `:nightly-<sha>`.

## Releases & versioning

Expand Down
4 changes: 3 additions & 1 deletion apps/docs/deployment/standalone.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ docker build \
-t trawl .
```

This adds approximately 891 MB to the image. Other build arguments pin or validate bundled
This adds approximately 891 MB to the image. Every release is also published prebuilt this way as
`ghcr.io/germondai/trawl:<version>-fonts` / `:latest-fonts`, so a `screenshot` consumer does not
need to build locally. Other build arguments pin or validate bundled
dependencies and normally should not be overridden: `UBO_VERSION`, `UBO_AMO_FILE_ID`, `UBO_SHA256`,
`GEOLITE_CITY_MIN_BYTES`, and (for the baseline image) `BUN_VERSION`.

Expand Down