Table of Contents

About

This is a docker build for tor, the anonymizing network, using the snowflake transport plugin and designed to be ran only in-memory without requiring any storage.

Running

After building, execute:

docker run \
    -it \
    --restart=always \
    -p 9050:9050 \
    -p 9055:9055 \
    -p 9053:9053 \
    -p 7050:7050 \
    --read-only true \
    --mount type=tmpfs,destination=/run \
    wizardrysteamworks/tor

with a matching Docker compose file that can be found in the compose section.

Here is the description of ports:

Port Description
9050 tor SOCKS port
9055 tor HTTP port
7050 CheckCircuit

The container runs read-only and with the "/run" directory that stores caches being placed into RAM using tmpfs.

Dockerfile

FROM debian:stable-slim
MAINTAINER Wizardry and Steamworks <wizardry.steamworks@outlook.com>
 
# update package manager
RUN  apt-get update -y && \
     apt-get upgrade -y && \
     apt-get dist-upgrade -y && \
     apt-get -y autoremove && \
     apt-get clean
 
# install required packages
RUN apt-get install -y \
    expect \
    telnet \
    coreutils \
    bash \
    curl \
    git \
    build-essential \
    autoconf \
    automake \
    libtool \
    pkgconf \
    libevent-dev \
    libssl-dev \
    libzstd-dev \
    liblzma-dev \
    zlib1g \
    zlib1g-dev \
    supervisor \
    libssl-dev \
    libicu-dev \
    unzip
 
RUN mkdir -p /tmp/kitchen
WORKDIR /tmp/kitchen
 
# install the latest golang
RUN curl -fsSL "https://go.dev/dl/$(curl -s 'https://go.dev/VERSION?m=text' | head -1).linux-amd64.tar.gz" -o go.tar.gz && \
    tar -xzf go.tar.gz && \
    rm go.tar.gz && \
    git clone https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git && \
    cd /tmp/kitchen/snowflake/client && \
    /tmp/kitchen/go/bin/go build && \
    mkdir -p /usr/local/bin && \
    cp client /usr/local/bin/snowflake-client
 
# compile the latest tor
WORKDIR /tmp/kitchen
RUN git clone https://gitlab.torproject.org/tpo/core/tor.git && \
    cd /tmp/kitchen/tor && \
    ./autogen.sh && \
    ./configure \
        --enable-lzma \
        --enable-zstd \
        --disable-gcc-hardening \
        --disable-linker-hardening \
        --disable-manpage \
        --disable-html-manual \
        --disable-asciidoc \
        --disable-unittests && \
    make -j4 && \
    mkdir -p /usr/local/bin && \
    cp /tmp/kitchen/tor/src/app/tor /usr/local/bin/
 
# install checkcircuit
WORKDIR /tmp/kitchen
RUN curl -fsSL https://checkcircuit.grimore.org/download/linux-x64/CheckCircuit-1.0.33.4-linux-x64.zip -o checkcircuit.zip && \
    unzip checkcircuit.zip && \
    mv CheckCircuit /usr/local/bin/
 
# pivot out and remove the kitchen
WORKDIR /
RUN rm -rf /tmp/kitchen
 
# include root filesystem
ADD rootfs /
 
# remove packages that will not be used
RUN apt-get purge -y \
        curl \
        git \
        build-essential \
        autoconf \
        automake \
        libtool \
        pkgconf && \
    apt-get autoremove -y 
 
# tor required port
EXPOSE 9050 7050 9053
 
# specify the entry point
RUN chmod +x /usr/local/bin/run
ENTRYPOINT [ "/usr/local/bin/run" ]

Files

Here are the files that are placed under the rootfs filesystem path.

run

#!/usr/bin/env bash
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2025 - License: MIT            ##
###########################################################################
 
# define default parameters
[ -z "$TOR_SOCKS_PORT" ] && TOR_SOCKS_PORT='0.0.0.0:9050'
[ -z "$TOR_HTTP_TUNNEL_PORT" ] && TOR_HTTP_TUNNEL_PORT='0.0.0.0:9055'
[ -z "$TOR_DNS_PORT" ] && TOR_DNS_PORT='0.0.0.0:9053'
[ -z "$CHECK_CIRCUIT_PORT" ] && CHECK_CIRCUIT_PORT='0.0.0.0:7050'
 
# launch tor from command line
/usr/local/bin/tor \
    --Log "notice stdout" \
    --SocksPort "$TOR_SOCKS_PORT" \
    --HTTPTunnelPort "$TOR_HTTP_TUNNEL_PORT" \
    --RunAsDaemon 0 \
    --DataDirectory /run \
    --ControlPort 8050 \
    --HashedControlPassword 16:9F840FFC85EF83CE60469C431DC9FF43DB889305B7653C2CB653302594 \
    --SocksPolicy "accept *" \
    --VirtualAddrNetwork 10.192.0.0/10 \
    --AutomapHostsOnResolve 1 \
    --AutomapHostsSuffixes .exit,.onion \
    --DNSPort $TOR_DNS_PORT \
    --UseBridges 1 \
    --ClientTransportPlugin "snowflake exec /usr/local/bin/snowflake-client -log /dev/stdout" \
    --Bridge "snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://1098762253.rsc.cdn77.org/ fronts=www.cdn77.com,www.phpmyadmin.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn" \
    --Bridge "snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://1098762253.rsc.cdn77.org/ fronts=www.cdn77.com,www.phpmyadmin.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn" \
    &
 
# 0x80004005 when temporary directory is not writeable (/run should be tmpfs)
export TMPDIR=/run
# circuit checker for tor (queryable via $CHECK_CIRCUIT_PORT)
/usr/local/bin/CheckCircuit \
    -l $CHECK_CIRCUIT_PORT \
    -c 127.0.0.1:8050 \
    -p tor \
    &
 
# terminate container when any process spawned by this shell in the background terminates
for JOB in `jobs -p`; do
    (lsof -p $JOB +r 1 &>/dev/null; kill -s TERM 1) &
done
 
sleep infinity