Skip to content
jinqians edited this page Oct 6, 2026 · 2 revisions

Moved here from the README | Wiki home | 中文

Image: jinqians/snell-server

Tags

Tag Version Notes
latest Snell v5.0.1 Pinned to the v5 channel, never auto-jumps to v6
v4 Snell v4.1.1 Latest in the v4 channel
v5 Snell v5.0.1 Latest in the v5 channel
v6 Snell v6.0.0rc2 Latest in the v6 channel (pre-release)
v4.0.0 v4.0.1 v4.1.0 v4.1.1 Snell v4 Pinned versions
v5.0.0 v5.0.1 Snell v5 Pinned versions
v6.0.0b1 … v6.0.0b4 v6.0.0rc v6.0.0rc2 Snell v6 Pinned pre-releases

Architectures: v4 / v5 ship amd64, arm64, armv7; v6 has no upstream armv7 build, so amd64 and arm64 only.

Alpine hosts: first put the docker service in the default runlevel as described in Enabling Docker on Alpine, otherwise dockerd won't start after a reboot and every container goes offline.

docker run

a. Snell only

The container runs as the unprivileged user nobody (uid 65534), so a mounted config directory must be writable by it, or the entrypoint can't generate the config. Run once before starting: mkdir -p ./snell-config && chown -R 65534:65533 ./snell-config

docker run -d --name snell-server \
  --restart unless-stopped \
  -p 6160:6160/tcp \
  -p 6160:6160/udp \
  -e SNELL_VER=v5 \
  -e SNELL_PORT=6160 \
  -v ./snell-config:/etc/snell \
  jinqians/snell-server:v5

# print the client config
docker logs snell-server

b. Snell + ShadowTLS v3

The Snell backend stays on 127.0.0.1 inside the container, so there is no need to publish 6160.

docker run -d --name snell-shadowtls \
  --restart unless-stopped \
  -p 8443:8443/tcp \
  -e SNELL_VER=v5 \
  -e SNELL_PORT=6160 \
  -e SNELL_LISTEN_HOST=127.0.0.1 \
  -e SHADOWTLS_ENABLE=1 \
  -e SHADOWTLS_PORT=8443 \
  -e SHADOWTLS_SNI=www.microsoft.com \
  -v ./snell-config:/etc/snell \
  jinqians/snell-server:v5

docker logs snell-shadowtls

c. Deploying Snell v6

v6 needs SNELL_MODE; see Snell v6-only options for what the values mean. Use the :v6 tag and SNELL_VER=v6 — both are required.

docker run -d --name snell-v6 --restart unless-stopped \
  -p 6160:6160/tcp -p 6160:6160/udp \
  -e SNELL_VER=v6 \
  -e SNELL_PORT=6160 \
  -e SNELL_MODE=default \
  -e SNELL_DNS_IP_PREFERENCE=default \
  -v ./snell-config:/etc/snell \
  jinqians/snell-server:v6

docker logs snell-v6

Docker Compose:

services:
  snell:
    image: jinqians/snell-server:v6
    container_name: snell-v6
    restart: unless-stopped
    ports:
      - "6160:6160/tcp"
      - "6160:6160/udp"
    environment:
      - SNELL_VER=v6
      - SNELL_PORT=6160
      - SNELL_MODE=default              # default / unshaped / unsafe-raw
      - SNELL_DNS_IP_PREFERENCE=default # default / prefer-ipv4 / prefer-ipv6 / ipv4-only / ipv6-only
      # - SNELL_DNS=1.1.1.1,8.8.8.8
    volumes:
      - ./snell-config:/etc/snell

Common combinations (full table in Recommended combinations):

-e SNELL_MODE=default   -e SNELL_DNS_IP_PREFERENCE=default      # general use
-e SNELL_MODE=unshaped  -e SNELL_DNS_IP_PREFERENCE=default      # clean link, ~10% more throughput
-e SNELL_MODE=default   -e SNELL_DNS_IP_PREFERENCE=ipv4-only    # VPS without IPv6 egress
-e SNELL_MODE=default   -e SNELL_DNS_IP_PREFERENCE=ipv6-only    # IPv6-only VPS

The log prints the client config with mode filled in — the client's mode must match:

Snell = snell, 1.2.3.4, 6160, psk = xxx, version = 6, mode = unshaped, reuse = true, tfo = true

⚠️ Changing v6 options later: environment variables only apply when the config file is first generated. Once snell-server.conf exists in the mounted directory, changing SNELL_MODE and restarting does nothing — the container says so in its log. Two ways to actually change it:

# Option 1: edit the config file (keeps the PSK, recommended)
sed -i 's/^mode = .*/mode = unshaped/' ./snell-config/snell-server.conf
docker restart snell-v6

# Option 2: delete it and let the container regenerate (PSK changes — update clients)
rm ./snell-config/snell-server.conf
docker restart snell-v6

d. Switching Snell versions

Change both the image tag and SNELL_VER. Deleting the old config regenerates the PSK; keeping it reuses the existing one:

docker rm -f snell-server
rm -f ./snell-config/snell-server.conf     # skip this to keep the current PSK

docker run -d --name snell-server \
  --restart unless-stopped \
  -p 6160:6160/tcp -p 6160:6160/udp \
  -e SNELL_VER=v6 -e SNELL_PORT=6160 -e SNELL_MODE=default \
  -v ./snell-config:/etc/snell \
  jinqians/snell-server:v6

e. Building images locally

./docker/build-docker-images.sh                      # all channels and versions
USE_BUILDX=1 PUSH=1 ./docker/build-docker-images.sh  # multi-arch build and push

Docker Compose

Snell only — create compose.yml:

services:
  snell:
    image: jinqians/snell-server:v5
    container_name: snell-server
    restart: unless-stopped
    ports:
      - "6160:6160/tcp"
      - "6160:6160/udp"
    environment:
      - SNELL_VER=v5
      - SNELL_PORT=6160
      # - SNELL_PSK=your_psk         # random on first start if unset
      # - SNELL_SERVER_IP=1.2.3.4    # auto-probed if unset
      # - SNELL_NODE_NAME=HK         # node name in the printed config
    volumes:
      - ./snell-config:/etc/snell

Snell + ShadowTLS:

services:
  snell-shadowtls:
    image: jinqians/snell-server:v5
    container_name: snell-shadowtls
    restart: unless-stopped
    ports:
      - "8443:8443/tcp"
    environment:
      - SNELL_VER=v5
      - SNELL_PORT=6160
      - SNELL_LISTEN_HOST=127.0.0.1
      - SHADOWTLS_ENABLE=1
      - SHADOWTLS_PORT=8443
      - SHADOWTLS_SNI=www.microsoft.com
    volumes:
      - ./snell-config:/etc/snell

Common commands:

docker compose up -d                  # start
docker compose logs snell-shadowtls   # client config
docker compose down                   # stop and remove

Viewing the client config

The first container start (when the config is generated) prints a Surge-ready config to the log — no manual assembly. Later restarts don't print the PSK in plain text:

docker logs snell-server              # started with docker run
docker compose logs snell-shadowtls   # started with docker compose

Example output:

==============================================================
  Snell 客户端配置 (Surge 格式)
==============================================================
  服务器          : 1.2.3.4
  端口            : 8443
  PSK             : duBN4HXibFaJejO2LC61/A==
  Snell 版本      : 5
  ShadowTLS       : v3, SNI = www.microsoft.com
  ShadowTLS 密码  : vwiOI52JPMPYhpTA/n/BKQ==
  Snell 后端端口  : 6160 (仅容器内监听)
--------------------------------------------------------------
Snell = snell, 1.2.3.4, 8443, psk = duBN4HXibFaJejO2LC61/A==, version = 5, reuse = true, tfo = true, shadow-tls-password = vwiOI52JPMPYhpTA/n/BKQ==, shadow-tls-sni = www.microsoft.com, shadow-tls-version = 3
--------------------------------------------------------------

The same content is written to the mounted volume:

cat ./snell-config/client-config.txt      # client config
cat ./snell-config/snell-server.conf      # server config
cat ./snell-config/shadowtls-password     # ShadowTLS password
  • The server address comes from an automatic public-IP probe; on failure a placeholder is printed — set SNELL_SERVER_IP to override.
  • The port shown is the container's listening port; replace it if the host maps a different one.
  • The first start's log contains the PSK and ShadowTLS password — do not share it publicly; later restarts don't log the PSK.
  • You can always view the full client config with docker exec <container> cat /etc/snell/client-config.txt.

Environment variables

Common

Variable Default Description
SNELL_VER follows image tag Config mode: v4 / v5 / v6
SNELL_PORT 6160 Snell listening port
SNELL_PSK random Snell PSK
SNELL_LISTEN_HOST 0.0.0.0 Listen address; use 127.0.0.1 with ShadowTLS
SNELL_IPV6 true v4 option; mapped to dns-ip-preference on v6 (false → ipv4-only)
SNELL_TFO true v4 option, not written for v5 / v6

Snell v6 only

Variable Default Description
SNELL_MODE default default / unshaped / unsafe-raw — must match the client
SNELL_DNS_IP_PREFERENCE follows SNELL_IPV6 default / prefer-ipv4 / prefer-ipv6 / ipv4-only / ipv6-only
SNELL_DNS unset Custom DNS servers, comma-separated

ShadowTLS

Variable Default Description
SHADOWTLS_ENABLE 0 Set to 1 to enable ShadowTLS v3
SHADOWTLS_PORT 8443 Public ShadowTLS port
SHADOWTLS_PASSWORD random Stored at /etc/snell/shadowtls-password
SHADOWTLS_SNI www.microsoft.com TLS camouflage SNI

Client config output

Variable Default Description
SNELL_NODE_NAME Snell Node name in the printed config
SNELL_SERVER_IP auto-probed Server address (IP or domain) to print
SNELL_IP_LOOKUP 1 Set to 0 to skip the public-IP probe

Clone this wiki locally