Skip to content

tommiec/vintage-proxies

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Proxy Stack for the iMac G3

Build cryanc Build browservice

Docker Compose stack providing legacy web access for the iMac G3.

  • Macproxy — primary choice on Tiger/Aquafox; fast, plain HTML, upstream certificate validation.
  • WebOne — fallback when you want more layout/images; richer but slower.
  • Crypto Ancienne (carl) — only for OS 9/Classilla special cases; no certificate validation.
  • Browservice — server-side Chromium rendering; streams pages as JPEG frames so the iMac needs no JavaScript, TLS, or CSS support. Validated on Tiger (G3). Use it for modern sites that break with the other proxies. OS 9/Classilla not yet tested; PowerPC/m68k support is not tested upstream.
  • AdGuard Home — standalone DNS blocker; optional for the G3 and independent of the browser proxy choice.

No sensitive logins or banking through this machine. Macproxy/WebOne validate upstream certificates, but between the iMac and the NAS the traffic is local proxy traffic. carl is opportunistic compatibility, not a secure TLS solution.

Screenshots

Aquafox on the iMac G3 loading the Wikipedia iMac G3 article via Macproxy

Choice

Finding on the G3: pages load faster with Macproxy than with WebOne. Hence this order.

Macproxy, WebOne, and carl are HTTP proxies — you configure them once in the OS or browser proxy settings and then browse normally with the browser's own address bar. The proxy works invisibly in the background.

Browservice is different — do not configure it as a proxy. Instead, surf directly to http://<NAS-IP>:8083/ and type the destination URL inside the Browservice interface. You are then looking at a live Chromium browser running on the server, streamed as images to the iMac. Use it as a last resort when Macproxy and WebOne cannot handle a site.

The table below combines the recommended use, the port, and how to point the browser at it:

Use Service Port How to point the browser
Daily browsing (Safari) Macproxy 5003 HTTP proxy in the OS X network settings
More layout/images (Aquafox) WebOne 8091 HTTP proxy in Aquafox's own settings
Modern sites, last resort Browservice 8083 Open http://<NAS-IP>:8083/ directly; use its in-page address bar
OS 9 / Classilla carl 8767 HTTP proxy; no certificate validation; not for Tiger
DNS-wide ad/tracker filtering AdGuard Home Set as the DNS server in the network settings

Current deployment target: Synology DS920+ running Docker / Portainer. Other Linux Docker hosts should work, but may need adjustments for ports, capabilities, and persistent volume paths.

Platform requirement: x86_64 only. The Browservice AppImage is x86_64-only and will not run on ARM-based NAS devices (DS220j, DS420j, …) or Apple Silicon. All other services (Macproxy, WebOne, carl, AdGuard Home) are multi-arch and run on ARM without changes.

Ports

Service Current host port Internal
Macproxy 5003 5001
WebOne 8091 8080
carl 8767 8765
Browservice 8083 8080
AdGuard Home DNS 5354 (set 53 in .env for G3 use) 53
AdGuard Home setup 3080 3000
AdGuard Home admin 3001 80

Host ports are configurable via .env.

Requirements

  • Docker with Compose v2 — use docker compose (plugin), not the legacy docker-compose wrapper.
  • Linux x86_64 host — Browservice fetches an x86_64 AppImage at build time and will not run on ARM. Other services have no architecture restriction.

Usage

  1. Copy .env.example to .env and set at least PROXY_HOSTNAME to the IP or hostname of the machine running this stack.
  2. Start the stack:
    docker compose up -d --build
    carl and browservice are compiled from source on first start; allow a few minutes for the build.
  3. Configure the browser's proxy to the host IP and the relevant port (see Ports). Browservice is not a proxy — open http://<NAS-IP>:8083/ directly in the browser instead.
  4. Optional: use AdGuard Home DNS for G3-wide DNS blocking.

Portainer CE

Portainer CE cannot use the local build: flow for cryanc/carl or browservice, so the Portainer stack uses the GitHub Actions images instead:

ghcr.io/tommiec/cryanc-carl:latest
ghcr.io/tommiec/browservice:latest

See deploy/ for a pre-built-images stack and .env template. The real deployment journal can still live in a separate GitOps repository.

Forking

To publish your own images after forking:

  1. Push any change to cryanc/ or browservice/ — GitHub Actions builds and publishes ghcr.io/<your-username>/cryanc-carl:latest and ghcr.io/<your-username>/browservice:latest.
  2. Go to your GitHub profile → Packages, open each package, and set it to Public. GHCR packages default to private; the NAS cannot pull them without authentication.
  3. Update the two image names in deploy/compose.yaml to match your username.

Browser Configuration on the iMac

This section gives the step-by-step proxy settings for Macproxy and WebOne; see Choice for which service to use when. Browservice is not a proxy and is covered separately in Browservice.

Do not browse to the proxy URL itself. WebOne will show a "looped connection" page if you do — that just means it is reachable.

Replace <NAS-IP> in the steps below with the IP address or hostname of the machine running this stack (e.g. 192.168.1.10).

Aquafox on Tiger

  1. Open Aquafox → Preferences → Advanced → Network → Settings.
  2. Choose Manual proxy configuration.
  3. Set HTTP Proxy to <NAS-IP>, port 5003.
  4. Set SSL Proxy also to <NAS-IP>, port 5003, or use the option "Use this proxy server for all protocols" if it is visible in your build.
  5. Under No Proxy for, set at least localhost, 127.0.0.1, <NAS-IP>.
  6. Test with http://frogfind.com/ or https://example.com/.

Use WebOne as a fallback by temporarily setting the same fields to port 8091. Do not use carl in Aquafox.

Safari / System Proxy on Tiger

Safari uses the OS X network settings:

  1. System Preferences → Network → active interface (Ethernet) → Proxies tab.
  2. Check Web Proxy (HTTP) and set server <NAS-IP>, port 5003 for Macproxy, or 8091 for WebOne.
  3. Check Secure Web Proxy (HTTPS) too with the same server and port.
  4. Under bypass/exceptions, set at least <NAS-IP>.
  5. Save/apply and surf to a normal site, not to the proxy itself.

For Safari use the same port choice: Macproxy 5003, WebOne 8091. Do not use carl for Safari/Aquafox.

Browservice

Browservice runs a full Chromium instance on the server and streams the rendered page as JPEG frames over HTTP to the client browser. The iMac sends only mouse/keyboard events and receives images — no JavaScript execution, no TLS handshake, no modern CSS parsing happens on the G3 side.

Use it when Macproxy or WebOne cannot render a page you actually need. Validated on Tiger (G3, Safari/Aquafox). OS 9/Classilla not yet tested.

Browser configuration for Browservice

Do not add Browservice to the proxy settings. Open http://<NAS-IP>:8083/ directly in Safari or Aquafox as a regular URL. Browservice presents its own start page with an address bar; type the destination URL there. All rendering happens on the server — Safari only receives images and sends back mouse/keyboard events.

Updating Browservice

Browservice fetches the latest AppImage from the official GitHub Releases at Docker build time. To update:

  1. Edit browservice/Dockerfile (bump a comment or the base image) and push to main.
  2. GitHub Actions rebuilds and publishes ghcr.io/tommiec/browservice:latest.
  3. Watchtower pulls the new image and restarts the container.

Docker notes

Browservice uses Chromium/CEF. The chrome-sandbox binary is set to root-owned mode 4755 in the Dockerfile so the SUID sandbox can run as the non-root browservice user. The compose file grants SYS_ADMIN and sets seccomp=unconfined because Synology DSM disables unprivileged user namespaces and Docker's default seccomp profile blocks some Chromium syscalls. Do not add no-new-privileges:true to Browservice; it blocks the setuid bit. Browservice keeps its runtime home inside the container; no host bind mount is needed unless we later decide to preserve browser sessions, cache, or installed fonts across container replacement. Do not run this proxy on an internet-exposed host without additional network-level protection.

GPU hardware acceleration is deliberately disabled (--disable-gpu, --disable-features=Vulkan). The DS920+ has an Intel UHD 600 that could be passed through via devices: [/dev/dri:/dev/dri], but the J4125 CPU handles software rendering fine for a single-user proxy, and sharing the GPU with DSM's own transcoding services (Plex, Video Station) introduces contention. If rendering becomes a bottleneck with heavier use, GPU passthrough is a viable next step: add the device, set the correct video group GID in the Dockerfile, and remove the disable flags.

AdGuard Home DNS on the G3

AdGuard Home is included as a standalone DNS service. It is not wired into the proxy containers: proxy choice stays in the browser, DNS choice stays in OS X Network settings.

To use it from the G3:

  1. Set ADGUARD_DNS_PORT=53 in .env before starting the stack. Standard DNS clients use port 53; the default 5354 is only a collision-safe startup value.
  2. Start the stack and finish the setup wizard at http://<NAS-IP>:3080/.
  3. In the wizard, keep DNS listening on internal port 53. Use internal port 80 for the admin UI if you want to reach it at http://<NAS-IP>:3001/ after setup.
  4. On Tiger: System Preferences → Network → active interface → DNS tab. Add <NAS-IP> as the DNS server.

This filters DNS for all G3 traffic. It does not change which proxy the browser uses.

Post-install: Retro Light filtering

Treat AdGuard Home as a light DNS filter for the G3, not as an aggressive adblock setup. The goal is fewer tracker, ad, metrics, and pixel requests while keeping old sites usable.

In the setup wizard:

  • Keep DNS listening on internal port 53.
  • Keep the admin UI on internal port 80 so it remains reachable at http://<NAS-IP>:3001/.
  • Use your normal LAN resolver or router as upstream DNS. For a NAS in a server VLAN behind a router or firewall, this is usually the gateway or resolver for that server network.
  • Use plain DNS upstreams first. DoH/DoT is not needed for this use case.

In Filters -> DNS blocklists, start small:

AdGuard DNS filter
https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt

HaGeZi Multi LIGHT
https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/light.txt

If that is stable but still lets too much tracking through, replace HaGeZi LIGHT with:

HaGeZi Multi NORMAL
https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/normal.txt

Avoid stacking aggressive Pro, Ultimate, gambling, social, annoyance, or cookie lists at first. They are more likely to break old browsing than to help the G3.

Recommended DNS settings:

  • Protection: on.
  • Blocking mode: NXDOMAIN.
  • Blocked response TTL: 3600.
  • Cache size: 64 MB or higher.
  • Optimistic cache: on, if available.
  • Minimum TTL: 300.
  • Maximum TTL: 86400.
  • Safe Search, parental control, and browsing security: off for the first test round.

Only add custom filtering rules when the query log shows they are still needed:

||googletagmanager.com^
||google-analytics.com^
||doubleclick.net^
||googlesyndication.com^
||facebook.net^
||connect.facebook.net^
||scorecardresearch.com^
||hotjar.com^
||newrelic.com^
||sentry.io^
||segment.io^

Do not broadly block shared infrastructure such as gstatic.com, Cloudflare, Akamai, Fastly, or common JavaScript CDNs. That usually breaks more pages than it speeds up.

Final check: open Query Log in AdGuard Home, filter on the G3 IP, and browse with Aquafox/Macproxy. If you see little or no traffic from the G3, the browser path is probably resolving DNS inside the proxy container instead. In that case AdGuard still filters direct G3 traffic, but proxy-side DNS filtering needs a separate decision.

References:

Alternatives and Candidates for Later

Not part of the current stack, but documented for later evaluation.

  • retro-proxy (https://github.com/DrKylstein/retro-proxy) — an HTTPS→HTTP transcoding proxy in Node.js, with conversion/compression options and an allowed.txt to skip transcoding per site. Functionally in the same category as Macproxy/WebOne, but a Node/Yarn build rather than a ready-made Docker image, so it would need its own container and a G3 test before adoption. BSD-3-Clause.

carl / cryanc — protocol notes

Carl is not a standard HTTP CONNECT proxy. It uses a socat/inetd model: each incoming TCP connection forks a carl process that reads a raw HTTP request from stdin and writes the response to stdout. Carl handles the TLS negotiation to the upstream server on behalf of the client.

This means:

  • Classilla / OS 9: sends a full GET http://example.com/ HTTP/1.0 to the proxy — exactly what carl expects. TLS is transparent to the browser.
  • Modern browsers (Safari, Firefox, curl with HTTPS): send CONNECT example.com:443 HTTP/1.1 — carl does not understand CONNECT and exits with status 1. Socat logs child exited with status 1. This is expected.

Verifying carl from a modern machine

Check the port is open:

nc -z <NAS-IP> 8767 && echo "open"

Test plain HTTP (not HTTPS) through carl:

curl --proxy http://<NAS-IP>:8767 http://neverssl.com/

HTTPS through carl cannot be tested from a modern client — that requires a browser like Classilla that does not use CONNECT.

Notes

  • Use carl only for OS 9/Classilla; modern browsers must use Macproxy or WebOne.
  • Do not bind these proxies unprotected to the internet; they have no authentication. Keep them on your LAN.

Update Model

This repository defines how the stack is built and which images it uses. It does not run an updater by itself. In production, a deployment layer such as Watchtower, Portainer, a scheduled docker compose pull, or another GitOps runner decides when to pull newer images and restart containers.

Component Image source Update source Notes
AdGuard Home adguard/adguardhome:latest Upstream image registry App/config data persists in the AdGuard volume. Review release notes before major upgrades.
WebOne u306060/webone:latest Upstream Docker image Image packaging follows the WebOne Docker image maintainer; config format can change between versions.
Macproxy Classic rdmark/macproxy:latest Upstream Docker image Pull the upstream image to update.
cryanc/carl ghcr.io/tommiec/cryanc-carl:latest in deploy mode; local build in root compose This repository's GitHub Actions Rebuilt only when cryanc/** or its workflow changes.
Browservice ghcr.io/tommiec/browservice:latest in deploy mode; local build in root compose This repository's GitHub Actions + upstream Browservice AppImage fetched at build time Rebuilt only when browservice/** or its workflow changes. A normal container pull does not fetch a newer AppImage unless this repo has rebuilt the image first.

With plain Docker Compose, update registry-backed images with:

docker compose pull
docker compose up -d

For the root development compose, cryanc/carl and Browservice are local builds. Use docker compose up -d --build after changing their Dockerfiles.

For the pre-built deploy compose, cryanc/carl and Browservice update only after GitHub Actions publishes new GHCR images:

cryanc/carl:

  1. Edit cryanc/Dockerfile (or bump CRYANC_REF to pin a specific upstream commit/tag).
  2. Push to main — GitHub Actions rebuilds and publishes the image.
  3. Pull the new image and restart: docker compose pull cryanc && docker compose up -d cryanc.
  4. Test at least https://example.com/ and the OS 9/Classilla case carl is meant for. Confirm working only after a short G3 test, not just because the container starts.

Browservice:

  1. Edit browservice/Dockerfile (or bump a comment/base image to force a rebuild).
  2. Push to main — GitHub Actions fetches the current upstream AppImage and publishes ghcr.io/tommiec/browservice:latest.
  3. Pull the new image and restart: docker compose pull browservice && docker compose up -d browservice.
  4. Test the Browservice start page and at least one simple HTTPS site before calling it healthy.

The cryanc container runs as a non-root user, with no-new-privileges, without extra Linux capabilities, and with a simple TCP healthcheck on the internal CARL_PORT.

Credits

This repository is a Docker Compose wrapper. All the actual proxy, browser, and DNS work is done by upstream projects — credits and thanks go to their authors and contributors:

Project Author / maintainer Repository / image License note
Macproxy Classic rdmark https://github.com/rdmark/macproxy_classic BSD-3-Clause
WebOne WebOne Development Team https://github.com/atauenis/webone WebOne custom permissive license; notify users about traffic changes/security implications
WebOne Docker image u306060 / way5 u306060/webone, https://github.com/way5/docker-webone Docker image packaging for WebOne
Crypto Ancienne (carl) Cameron Kaiser https://github.com/classilla/cryanc Upstream repository does not publish standard license metadata; review upstream terms before redistributing modified builds
Browservice Topi Talvitie https://github.com/ttalvitie/browservice MIT
AdGuard Home AdGuard Team https://github.com/AdguardTeam/AdGuardHome GPL-3.0
HaGeZi DNS blocklists hagezi https://github.com/hagezi/dns-blocklists GPL-3.0

The MIT license in this repository applies to this wrapper's compose files, Dockerfiles, and documentation. It does not relicense upstream software or container images.

AI usage

AI was used as a sounding board for Docker, Compose and troubleshooting decisions. The architecture, implementation, validation and maintenance are mine.

About

Docker Compose proxy stack for vintage Mac browsing (iMac G3, Mac OS 9, Tiger)

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors