Back to Dashboard

tor

0.4.9.11-alpine

Tor SOCKS proxy with relay, bridge, pluggable transport, hidden-service, and optional Nyx monitoring support. Multi-arch, SBOM-attested, daily upstream monitoring.

Trust posture

📋 SBOM ATTESTED🛡 TRIVY: 0 critical / high (advisory) · SCANNED 2026-07-10🏗 AMD64 + ARM64 🔗 2/2 deps tracked daily 🔍 REPRODUCE THESE CHECKS LOCALLY
PULLS 32
STARS 0
COVERAGE 2 variants · amd64+arm64

VERIFIABLE TRUST ARTIFACTS

Provenance

Build commit
ed67d41
Build digest
sha256:5787416f910d203b2ba9c050d7e248fadb5b8e3925ac41c03cf37ac0038df579
Index digest
sha256:7b2713213f5d0b2fa27f3c915875fbd534625ed2b28a380fcec4878d038ee295
Manifest digest (amd64)
sha256:ae60ae9b49b49d7340364faea20ea46aaabd5fc29a31570fefca249092ae089f
Manifest digest (arm64)
sha256:62d18e29c908aa9a434f7e5a256262ac4818bf9c2dc5e6096a26336a1ba7c881
SBOM attestation
34817621…
Trivy last scan
2026-07-10 20:42 UTC
Base image
Verify
gh attestation verify oci://ghcr.io/oorabona/tor:0.4.9.11-alpine --owner oorabona guide →

Security scan results

Trivy · last scan 2026-07-10

Last scan: (advisory mode — Trivy runs continue-on-error in CI; we surface findings, we do not block builds on them).

0Critical
0High
0Medium
0Low
0Info

No CRITICAL alerts at last scan (2026-07-10).

Top advisories (upstream, advisory)

    → Full report via gh api — see Verify Images.

    Explore

    Available variants

    TagSize (amd64) Build status
    0.4.9.11-alpine default20.5MB OK
    0.4.9.11-alpine-monitoring36.2MB OK
    Build lineagesha256:
    Build Lineage
    Build Digest sha256:5787416f910d203b2ba9c050d7e248fadb5b8e3925ac41c03cf37ac0038df579
    Base Image
    OS_IMAGE_TAG latest
    TOR_VERSION 0.4.9.11
    LYREBIRD_VERSION 0.8.1
    NYX_VERSION 2.1.0
    Package summary n/a — runtime parsed
    Recent changes n/a — runtime parsed
    Build history n/a — runtime fetched
    Dependency health all up to date

    Dependency Health

    all up to date
    2/2 dependencies monitored
    Up-to-date dependencies
    LYREBIRD_VERSION 0.8.1 NYX_VERSION 2.1.0

    Documentation

    README

    Tor — SOCKS Proxy, Relay, Bridge, and Hidden-Service Container

    Docker Pulls Docker Image Size GHCR GitHub Stars

    Tor with a secure default control-port setup: SOCKS on 9050, cookie authentication for local control, Lyrebird for pluggable transports, and an optional Nyx monitoring flavor.

    Why this image

    The Tor Docker landscape already has several images, each making a different trade-off:

    Image Strength Gap
    dperson/torproxy Most widely pulled Unmaintained since 2021
    peterdavehello/tor-socks-proxy Actively updated No arm64 on latest; a healthcheck bug has been open since 2023
    dockur/tor Full feature breadth — relay, exit, bridge, hidden-service, Lyrebird, Nyx No SBOM/CVE scanning; ships PASSWORD=password as a control-port default, and its own compose example maps that port to the host
    leplusorg/docker-tor Clear supply-chain documentation Deliberately SOCKS5-only — no relay, bridge, or hidden-service support

    This image is the combination none of them cover: dockur’s feature breadth, wrapped in this fleet’s supply-chain pipeline (multi-arch builds, a Sigstore-attested SBOM, a Trivy scan on every image, daily upstream version tracking) — with a control port that is loopback-bound and cookie-authenticated by default, never a shipped password.

    Verify this image

    Every build ships a Sigstore-signed SBOM and a full Trivy scan — verify them yourself, no login required:

    gh attestation verify oci://ghcr.io/oorabona/tor:latest --owner oorabona
    

    Full walkthrough (SBOM payload, Trivy findings, multi-arch manifest inspection, upstream dependency tracking) → https://oorabona.github.io/docker-containers/verify-images/

    Platforms

    • amd64 - x86_64 systems
    • arm64 - ARM 64-bit systems

    Tags

    • latest, 0.4.9.11-alpine - Tor + Lyrebird
    • latest-monitoring, 0.4.9.11-alpine-monitoring - Tor + Lyrebird + Nyx + py3-stem

    Lyrebird is the Tor Project’s pluggable-transport binary, the maintained successor to obfs4proxy. It disguises Tor traffic as something else — plain-looking TLS, depending on the transport — so a bridge stays usable on networks where Tor’s normal traffic pattern is blocked or fingerprinted. It’s installed in every tag; it does nothing unless a mounted torrc sets a ClientTransportPlugin or ServerTransportPlugin line.

    Nyx is a terminal UI for a running Tor process — live bandwidth graphs, circuit and connection listings, log tailing — talking to Tor over the control port via the Python stem library. It’s the standard monitor endorsed by the Tor Project and the only widely known tool of its kind, but it’s effectively dormant upstream: no PyPI release since 2019, no GitHub commit since 2022 (stem, its own dependency, last changed in 2024). It stays in this fleet as an opt-in flavor rather than the default for that reason — Alpine still packages and patches it, this pipeline’s own Trivy scan covers it on every build regardless of upstream release cadence, and it’s only reachable via docker exec, never a network-exposed service.

    Versioning

    Tor, Lyrebird, and Nyx are installed from Alpine packages. The image records the actual installed package versions in /usr/local/share/tor/package-versions.env.

    Lyrebird and Nyx remain tracked against upstream releases as an advisory traceability signal. A PR such as LYREBIRD_VERSION: 0.8.1 -> 0.9.0 means upstream released a new version and Alpine should be checked; merging that PR updates the declared signal, but the running image changes only after Alpine repackages and the image is rebuilt.

    Basic SOCKS Proxy

    docker run -d \
      --name tor \
      -p 127.0.0.1:9050:9050 \
      -v tor-data:/var/lib/tor \
      ghcr.io/oorabona/tor:latest
    

    This publishes SOCKS on host loopback only. Broader host-interface exposure should be an explicit operator choice, paired with appropriate network controls.

    Use socks5h://, not plain socks5://, when the client supports it:

    curl --proxy socks5h://127.0.0.1:9050 https://check.torproject.org/api/ip
    

    The h means hostname resolution happens through Tor. Many clients using plain socks5:// resolve DNS locally before connecting to the proxy, which leaks the destination hostname outside the Tor circuit.

    Configuration

    Simple Environment Path

    The image generates a minimal torrc when /etc/tor/torrc is absent, empty, or contains only whitespace/comments.

    Variable Default Effect
    SOCKS_BIND 0.0.0.0 SOCKS listen address inside the container
    SOCKS_PORT 9050 SOCKS listen port
    EXIT_NODES unset Comma-separated country codes rendered as Tor {cc} entries
    EXCLUDE_EXIT_NODES unset Comma-separated country codes to avoid
    PASSWORD_FILE unset Optional Docker-secret file for external control authentication, pre-hashed or plaintext
    CONTROL_PORT_BIND 127.0.0.1 Control port bind address; non-loopback requires PASSWORD_FILE
    CONTROL_PORT 9051 Control port listen port
    CHECK false When true, healthcheck verifies Tor exit status through check.torproject.org

    Default control access uses CookieAuthentication 1 and binds ControlPort 127.0.0.1:9051. The image does not expose the control port.

    The default healthcheck first verifies that the Tor process is alive. For the generated simple torrc path it also confirms the configured SOCKS listener is open; for mounted torrc deployments it does not assume SOCKS exists. Set CHECK=true only when readiness must confirm a working SOCKS circuit through check.torproject.org.

    Opt-In External Control

    For password-authenticated external control, set PASSWORD_FILE to a Docker secret and bind CONTROL_PORT_BIND deliberately. The recommended secret content is a pre-hashed Tor control password in 16:<58 hex characters> HashedControlPassword format, generated outside the container, for example with tor --hash-password on a trusted host or a throwaway container. The entrypoint uses that value directly and never handles the plaintext.

    For compatibility, PASSWORD_FILE may also contain a plaintext password. In that path the entrypoint hashes it at startup with tor --hash-password; Tor does not provide stdin or file input for this operation, so the plaintext is briefly visible in that helper process’s argv inside the container PID namespace.

    Generating the password file (one-shot):

    # One-shot: hash a password using the same image, nothing persists
    docker run --rm ghcr.io/oorabona/tor:latest \
      tor --hash-password 'correct horse battery staple' \
      | awk '/^16:/ {print; exit}' > control_password_hash
    
    # Long-running container: opt in to external control with that hash
    docker run -d \
      --name tor \
      -p 127.0.0.1:9050:9050 \
      -p 127.0.0.1:9051:9051 \
      -v "$PWD/control_password_hash:/run/secrets/tor_control_password:ro" \
      -e PASSWORD_FILE=/run/secrets/tor_control_password \
      -e CONTROL_PORT_BIND=0.0.0.0 \
      -v tor-data:/var/lib/tor \
      ghcr.io/oorabona/tor:latest
    

    CONTROL_PORT_BIND=0.0.0.0 is the address Tor binds inside the container — Docker can only forward a published port to an address the process is actually listening on there. The -p 127.0.0.1:9051:9051 publish is what actually restricts host reachability to loopback; without PASSWORD_FILE set, the entrypoint refuses to start rather than open an unauthenticated control port on anything wider than the container’s own loopback.

    Mounted torrc Path

    For relay, bridge, exit, and hidden-service deployments, mount a full torrc:

    docker run -d \
      --name tor-relay \
      -p 127.0.0.1:9050:9050 \
      -p 9001:9001 \
      -v "$PWD/torrc:/etc/tor/torrc:ro" \
      -v tor-data:/var/lib/tor \
      ghcr.io/oorabona/tor:latest
    

    When /etc/tor/torrc contains at least one non-comment directive, it owns Tor’s behavior-affecting configuration. The container supplies only DataDirectory, PidFile, and Log through Tor’s defaults file. If simple environment variables are also set, startup logs a warning because those variables have no effect in this mode.

    Relay Example

    Minimal relay torrc:

    Nickname ExampleRelay
    ContactInfo admin@example.com
    ORPort 9001
    ExitRelay 0
    SocksPort 0
    

    Publish 9001 for relay and bridge mode. Without an inbound ORPort mapping, other Tor nodes cannot reach the relay even if the process starts cleanly.

    Monitoring Flavor

    Run the monitoring tag, then attach Nyx from inside the container:

    docker run -d \
      --name tor \
      -p 127.0.0.1:9050:9050 \
      -v tor-data:/var/lib/tor \
      ghcr.io/oorabona/tor:latest-monitoring
    
    docker exec -it tor nyx
    

    Or with Compose:

    services:
      tor:
        image: ghcr.io/oorabona/tor:latest-monitoring
        cap_drop:
          - ALL
        security_opt:
          - no-new-privileges:true
        ports:
          - "127.0.0.1:9050:9050"
        volumes:
          - tor-data:/var/lib/tor
        restart: unless-stopped
    
    volumes:
      tor-data:
    
    docker compose up -d
    docker compose exec tor nyx
    

    Nyx runs as the tor user and reads /var/lib/tor/control_auth_cookie; no password is generated or printed in the default path. It’s a terminal application, not a background metrics exporter — there is no dashboard or scrape endpoint to point Prometheus at. Each nyx session is a live, interactive view for as long as the terminal stays attached.

    Persistence

    /var/lib/tor is optional for a disposable SOCKS proxy and required for identity-bearing modes:

    • relay fingerprint continuity
    • bridge identity continuity
    • hidden-service private keys and .onion address continuity

    The data directory is fixed at /var/lib/tor; persist it by mounting a named volume or bind mount at that path.

    The entrypoint warns when a mounted torrc defines HiddenServiceDir or ORPort and /var/lib/tor does not look like a mounted volume. This is a best-effort heuristic; the absence of the warning is not proof that persistence is configured correctly.

    Named Docker volumes are prepared by the root-to-tor startup path. If /var/lib/tor is a bind mount and the container is not started with --user 0, pre-own the host directory as uid 100 so the tor user can write it.

    Security

    • Runs as the named tor user by default
    • Uses Tor cookie authentication by default
    • Binds the control port to loopback by default
    • Does not declare EXPOSE 9051
    • Does not ship a default control password

    Runtime Hardening

    services:
      tor:
        image: ghcr.io/oorabona/tor:latest
        cap_drop:
          - ALL
        security_opt:
          - no-new-privileges:true
        ports:
          - "127.0.0.1:9050:9050"
        volumes:
          - tor-data:/var/lib/tor
        restart: unless-stopped
    
    volumes:
      tor-data:
    

    Relay mode still does not need extra Linux capabilities when using an unprivileged ORPort such as 9001.

    Building

    Build all variants, including the monitoring flavor, through the normal variant pipeline:

    ./make build tor
    

    License

    MIT