diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f589242..eb69767 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,10 @@ on: jobs: test: - runs-on: ubuntu-latest + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 339e98b..cce1add 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,10 @@ jobs: goarch: amd64 - goos: darwin goarch: arm64 + - goos: windows + goarch: amd64 + - goos: windows + goarch: arm64 steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 @@ -54,15 +58,23 @@ jobs: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} run: | - go build -ldflags "-X main.version=${{ steps.version.outputs.version }}" -o ublproxy . + EXT="" + if [ "${{ matrix.goos }}" = "windows" ]; then EXT=".exe"; fi + go build -ldflags "-X main.version=${{ steps.version.outputs.version }}" -o "ublproxy${EXT}" . - name: Archive - run: tar czf "ublproxy-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" ublproxy + run: | + BASENAME="ublproxy-${{ matrix.goos }}-${{ matrix.goarch }}" + if [ "${{ matrix.goos }}" = "windows" ]; then + zip "${BASENAME}.zip" ublproxy.exe + else + tar czf "${BASENAME}.tar.gz" ublproxy + fi - uses: actions/upload-artifact@v4 with: name: ublproxy-${{ matrix.goos }}-${{ matrix.goarch }} - path: "ublproxy-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" + path: "ublproxy-${{ matrix.goos }}-${{ matrix.goarch }}.*" release: needs: binaries @@ -90,7 +102,9 @@ jobs: name: ${{ steps.version.outputs.version }} prerelease: ${{ steps.version.outputs.prerelease == 'true' }} generate_release_notes: true - files: "*.tar.gz" + files: | + *.tar.gz + *.zip docker: needs: test diff --git a/DECISIONS.md b/DECISIONS.md index 4a440ed..aaf05c0 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -91,4 +91,5 @@ - 2026-03-01 m+git@andri.dk — Added portal UI screenshots to landing page. 4 PNGs (setup wizard, dashboard, activity feed, subscriptions) captured via Playwright with mocked API responses. Displayed in 2x2 grid "See it in action" section between Features and Architecture. Screenshots are served as static assets from `web/`. - 2026-03-02 m+git@andri.dk — Portal HTTPS cert now cached with expiration, matching leaf cert behavior. Previously, `startPortalHTTPS` generated the portal cert once at startup and baked it into `tls.Config.Certificates` — after 24h of uptime it expired, causing TLS errors for the portal, PAC file, and all proxy traffic routed through the HTTPS port. Fix: `Cache.GetPortalCert()` caches the portal cert with a 24h `expiresAt` and regenerates on demand. `startPortalHTTPS` uses `tls.Config.GetCertificate` callback instead of a static cert. Transparent mode was unaffected (already called `PortalCert()` per-connection). - 2026-03-02 m+git@andri.dk — TLS handshake failure circuit breaker for automatic cert-pin detection. When a host accumulates 3 TLS handshake failures within 10 minutes, the proxy auto-switches it to passthrough (no MITM) for 1 hour. After the TTL expires, a single failure re-trips the breaker immediately (`prevTripped` flag) to avoid repeated breakage. `RecordSuccess` clears all state when a MITM handshake succeeds, proving the host is not pinned. Portal host and IPs are excluded — they can never be auto-passthrough'd. Events are logged at warn level and recorded in the activity feed as `auto-passthrough`. Works in both explicit and transparent proxy modes. No CLI flags; all thresholds hardcoded. In-memory only; resets on restart. +- 2026-03-02 m+git@andri.dk — Added Windows binaries (amd64, arm64) to the release workflow. No source code changes needed — all Go code, dependencies, and the pure-Go SQLite driver are cross-platform. Windows archives use `.zip` instead of `.tar.gz`. CI tests now run on `windows-latest` alongside `ubuntu-latest`. Transparent proxy mode requires platform-specific firewall configuration (outside ublproxy's scope) but the proxy itself runs identically. - 2026-03-02 m+git@andri.dk — SEO and Open Graph improvements for landing page. Added `og:image` (1200x630 PNG matching the CRT/terminal aesthetic), `og:site_name`, Twitter Card meta tags, canonical URL, SVG favicon, and JSON-LD `SoftwareApplication` structured data. OG image source is `web/og-image.html` — a standalone HTML file screenshotted via Playwright to `web/og-image.png`. Keeps the image regenerable from source. diff --git a/QUICK_START.md b/QUICK_START.md index de23554..fab0c4a 100644 --- a/QUICK_START.md +++ b/QUICK_START.md @@ -7,6 +7,13 @@ go build -o ublproxy . ./ublproxy ``` +On Windows: + +```powershell +go build -o ublproxy.exe . +.\ublproxy.exe +``` + ## Run with Docker ```bash diff --git a/web/index.html b/web/index.html index 1c4c83f..b4d2a10 100644 --- a/web/index.html +++ b/web/index.html @@ -30,7 +30,7 @@ "description": "A self-hosted HTTPS proxy with full Adblock Plus filter support, cosmetic filtering, per-user passkeys, and transparent proxy mode. Block ads at the HTTP layer, not just DNS.", "url": "https://andrioid.github.io/ublproxy/", "applicationCategory": "NetworkApplication", - "operatingSystem": "Linux, macOS", + "operatingSystem": "Linux, macOS, Windows", "license": "https://github.com/andrioid/ublproxy/blob/main/LICENSE.md", "downloadUrl": "https://github.com/andrioid/ublproxy/releases", "screenshot": "https://andrioid.github.io/ublproxy/portal-dashboard.png", @@ -1336,11 +1336,15 @@ td:first-child {

Binary

-

Download a pre-built binary for your platform. Available for Linux and macOS on amd64 and arm64.

+

Download a pre-built binary for your platform. Available for Linux, macOS, and Windows on amd64 and arm64.

$ tar xzf ublproxy-linux-amd64.tar.gz
$ ./ublproxy
+
+ # Windows (zip archive)
+ > ublproxy.exe +
Download from Releases →