Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!


Shells Virtual Desktop
BMail.ag - Secure Email Service
Server.net
CPLicense.net
VPS Server
Buy VPN
Vultr
VMs for AI
HostDare
ReliableSite White-Label Dedicated Hosting for Resellers
InterServer VPS
BMail.ag - Secure Email Service
Best VPN
High-Performance Bare Metal Server Solutions
Karvl.com
Server Mania Cloud Hosting
DataWagon Hosting
AlphaVPS Hosting
Evoxt.com
Clouvider
VPS Hosting with NVMe
Residential IPs in the US & 4G Mobile Proxies in EU & US with Unlimited Bandwidth
ReliableSite White-Label Dedicated Hosting for Resellers
Rabisu - Hosting Solutions
Shells Virtual Desktop
New on LowEndTalk? Please Register and read our Community Rules.

All new Registrations are manually reviewed and approved, so a short delay after registration may occur before your account becomes active.

Webtunnel and Snowflake Tor Bridge Setup - Ansible Playbooks Inside

olokeoloke Member, Host Rep

Hello,

After posting in another thread, some people were curious about my Tor bridge setup. I currently run over 10 tor bridges on various idlers I have.

Around a year ago I wrote two ansible playbooks to help me deploy and manage those a bit easier and also make sure I did not make any manual mistake during configuration.

webtunnel

The playbook is basically the adaptation of steps from official wiki page with some minor improvements and also a script that helps getting the bridge line after Tor daemon starts successfully.

The webtunnel bridge works basically by tunneling Tor traffic via HTTPS web server. For the client to be able to connect, you need to provide the domain and secret url on which reverse proxy is listening. Ideally, the connection should look as if someone was just visiting your website - the traffic is encrypted with TLS so censors are not able to see what the client does on there. most of the time

The requirements for webtunnel:

  • a free 80 and 443 port or nginx already running on 443
    This playbook assumes no web server is running. You could add a new vhost manually if you already have nginx configured and running. It did not work for me with Caddy for some reason (i didn't investigate further, and also no one seems to be running Caddy for webtunnel).

  • a subdomain
    A CNAME record you can delegate to this bridge.

  • small VPS running Debian
    ~512MB RAM should be enough - just needs Tor daemon and nginx. It should be able to run on other distros as well, but the playbook would need some adaptation.

playbook.yml

- name: Install and configure Tor WebTunnel Bridge on Debian
  hosts: tor_bridge
  become: yes
  tasks:
    - name: Update and upgrade system packages
      ansible.builtin.apt:
        update_cache: yes
        upgrade: dist
        autoremove: yes
        autoclean: yes

    - name: Install required dependencies for Tor and WebTunnel
      ansible.builtin.apt:
        name:
          - apt-transport-https
          - gnupg2
          - curl
          - socat
          - nginx
          - cron
        state: present

    - name: Stop service nginx
      ansible.builtin.systemd_service:
        name: nginx
        state: stopped

    - name: Download and save Tor GPG key to custom keyring
      ansible.builtin.shell:
        cmd: wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/null
        creates: /usr/share/keyrings/deb.torproject.org-keyring.gpg
      become: yes
      tags: tor_repo[1][3]

    - name: Set permissions for Tor GPG key
      ansible.builtin.file:
        path: /usr/share/keyrings/deb.torproject.org-keyring.gpg
        mode: '0644'
        owner: root
        group: root
      become: yes
      tags: tor_repo[1][3]

    - name: Add Tor Project repository
      ansible.builtin.apt_repository:
        repo: 'deb [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] https://deb.torproject.org/torproject.org trixie main'
        state: present
      tags: tor_repo[3]

    - name: Install Tor from Tor Project repository
      ansible.builtin.apt:
        name: tor
        state: present
      tags: tor_repo[3]

    - name: Install Tor Keyring from Tor Project repository
      ansible.builtin.apt:
        name: deb.torproject.org-keyring
        state: present
      tags: tor_repo[3]

    - name: Download WebTunnel binary
      ansible.builtin.get_url:
        url: "{{ webtunnel_url }}"
        dest: /usr/local/bin/webtunnel
        mode: '0755'
      tags: webtunnel_download[2]

    - name: Update Apparmor configuration for Tor to allow WebTunnel
      ansible.builtin.lineinfile:
        path: /etc/apparmor.d/system_tor
        insertafter: '  \/var\/lib\/tor\/\*\* r,'
        line: '  /usr/local/bin/webtunnel ix,'
        state: present
      notify: Reload Apparmor

    - name: Installing acme
      ansible.builtin.shell:
        cmd: wget -O - https://get.acme.sh | sh -s email={{ letsencrypt_email }}
      become: yes

    - name: Setting up acme
      ansible.builtin.shell:
        cmd: /root/.acme.sh/acme.sh --issue --force --standalone --domain {{ domain }}
      become: yes

    - name: Configure Nginx for WebTunnel
      ansible.builtin.copy:
        dest: /etc/nginx/sites-available/default
        content: |                 
          server {
              listen [::]:443 ssl http2;
              listen 443 ssl http2;
              server_name {{ domain }};
              #ssl on;
              
              # you can place a dummy website here, or just leave it to 404
              root /var/www/new_site;

              # certificates generated via acme.sh
              ssl_certificate /root/.acme.sh/{{ domain }}_ecc/fullchain.cer;
              ssl_certificate_key /root/.acme.sh/{{ domain }}_ecc/{{ domain }}.key;

              ssl_session_timeout 15m;

              ssl_protocols TLSv1.2 TLSv1.3;

              ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

              ssl_prefer_server_ciphers off;

              ssl_session_cache shared:MozSSL:50m;
              #ssl_ecdh_curve secp521r1,prime256v1,secp384r1;
              ssl_session_tickets off;

              add_header Strict-Transport-Security "max-age=63072000" always;
              
              # Reverse proxy to Tor daemon
              location = /{{ random_string }} {
                  proxy_pass http://127.0.0.1:15000;
                  proxy_http_version 1.1;

                  ### Set WebSocket headers ###
                  proxy_set_header Upgrade $http_upgrade;
                  proxy_set_header Connection "upgrade";

                  ### Set Proxy headers ###
                  proxy_set_header        Accept-Encoding   "";
                  proxy_set_header        Host            $host;
                  proxy_set_header        X-Real-IP       $remote_addr;
                  proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
                  proxy_set_header        X-Forwarded-Proto $scheme;
                  add_header              Front-End-Https   on;

                  proxy_redirect     off;
                  access_log  off;
                  error_log off;
              }

          }

        owner: root
        group: root
        mode: '0644'
      notify: Reload Nginx

    - name: Create Tor configuration for WebTunnel bridge
      ansible.builtin.blockinfile:
        path: /etc/tor/torrc
        block: |
          BridgeRelay 1
          ORPort 127.0.0.1:auto
          AssumeReachable 1
          ServerTransportPlugin webtunnel exec /usr/local/bin/webtunnel
          ServerTransportListenAddr webtunnel 127.0.0.1:15000
          ServerTransportOptions webtunnel url=https://{{ domain }}/{{ random_string }}
          ExtORPort auto
          ContactInfo <{{ contact_email }}>
          Nickname {{ nickname }}
          SocksPort 0
          Log notice file /var/log/tor/notices.log
          {% if make_bridge_private | default(false) %}
          PublishServerDescriptor 0
          BridgeDistribution none
          {% else %}
          PublishServerDescriptor 1
          {% endif %}
        state: present
      notify: Restart Tor

    - name: Ensure Tor service is enabled and started
      ansible.builtin.systemd:
        name: tor.service
        enabled: yes
        state: started

    - name: Write get bridge line script
      ansible.builtin.template:
        src: get-bridge-line.sh.j2
        dest: /opt/get-bridge-line.sh
        owner: root
        group: root
        mode: '0755'
      become: yes

  handlers:
    - name: Reload Apparmor
      ansible.builtin.systemd:
        name: apparmor
        state: reloaded

    - name: Reload Nginx
      ansible.builtin.systemd:
        name: nginx
        state: reloaded

    - name: Stop Nginx
      ansible.builtin.systemd:
        name: nginx
        state: stopped

    - name: Restart Tor
      ansible.builtin.systemd:
        name: tor.service
        state: restarted

get-bridge-line.sh.j2 - I adapted this script from the obfs4 docker image. It really helps piece together the bridge line to use.

#!/usr/bin/env bash
#
# This script extracts the pieces that we need to compile our bridge line.
# This will have to do until the following bug is fixed:
# <https://gitlab.torproject.org/tpo/core/tor/-/issues/29128>

TOR_LOG=/var/log/tor/notices.log

if [ ! -r "$TOR_LOG" ]
then
    echo "Cannot read Tor's log file ${TOR_LOG}. This is a bug."
    exit 1
fi

fingerprint=$(grep "Your Tor server's identity key *fingerprint is" "$TOR_LOG" | \
    sed "s/.*\([0-9A-F]\{40\}\)'$/\1/" | \
    tail -1)

imaginaryaddr=$(grep 'Registered server transport' "$TOR_LOG" | sed -E "s/.*?(\[[0-9a-f:]*\]:443)'$/\\1/gm" | \
    tail -1)

WEBTUNNEL_URL=https://{{ domain }}/{{ random_string }}
echo "webtunnel ${imaginaryaddr} ${fingerprint} url=${WEBTUNNEL_URL}"

hosts.ini

[all:vars]
letsencrypt_email="[email protected]"
contact_email="youremail at example [dot] com"  # email for contact, can be slightly obfuscated if you do not wish to receive spam (it's listed publicly)
webtunnel_url="https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/webtunnel/-/jobs/1316181/artifacts/raw/build/amd64-linux/server"  # webtunnel server binary - needs changing to the most recent artifact from time to time

[tor_bridge]
subdomain.example.com domain=subdomain.example.com nickname=bridgename random_string=yoursecreturl # make_bridge_private=true

Replace:

  • letsencrypt_email and contact_email with your actual email you want to use for bridge in both places
  • your subdomain in domain - clients will connect to it
  • nickname - that's the name your bridge will be listed as
  • random_string - secret URL for reverse proxy to Tor

There is one more parameter I implemented, make_bridge_private - if you don't want the bridge to be listed publicly (rather send someone who asks you directly for example), you can set it to true.

Lastly, there's somewhat of non-ideal solution - I'm just grabbing the most recent build from gitlab build artifacts instead of manual compilation. This saves on compile time but needs you to update the job id if you want to perform an update. I think I will change that in the future.

How to check it is working

After successfully executing the playbook, the easiest way is to get bridge line and test for yourself:

$ sudo /opt/get-bridge-line.sh 
webtunnel [2001:db8:272b:3cc6:66df:4d41:6895:cbcf]:443 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA url=https://subdomain.example.com/yoursecreturl

Tor Browser should be able to bootstrap with this.

You can also check the Tor logs, every day it will print out the usage stats:

Mar 03 06:27:35.000 [notice] Heartbeat: Tor's uptime is 13 days 12:00 hours, with 102 circuits open. I've sent 119.61 GB and received 122.25 GB. I've received 44378 connections on IPv4 and 0 on IPv6. I've made 180822 connections with IPv4 and 0 with IPv6.

Lastly, you should be able to find your bridge on Tor metrics site, either looking by bridge name or the hash. It can take a few hours for it to appear there.

There you can also see the bridge distribution method assigned to your bridge. In the first few days/weeks it can be None (this means your bridge is not distributed yet), but later should change to something like Settings, Telegram, Email or HTTPS.

disclaimer: sometimes the Tor daemon may be attacked and as a consequence unable to bootstrap. It happened to me a couple times that Tor was consistently using 100% CPU. There are some malicious malicious/non-functional guard relays on the network which sometimes prevent daemon from bootstraping. Usually restart solves this (since the daemon chooses different guard from a set).

snowflake

Snowflake architecture is very different. Since it was initially designed to work as just a website one can open to help others (later chrome extension), it doesn't actually need the Tor daemon running in the background. Instead it makes connections over widely adopted WebRTC protocol and forwards them via websocket to backend Snowflake Server owned by The Tor Foundation (snowflake-01.torproject.net). Their server is responsible to actually connect users to Tor relays and gain access to the network.

There is also a concept of "Broker" - a server which helps Clients find Bridges (Proxies). It is set by default to snowflake-broker.torproject.net, but you may use other ones by providing -broker parameter as argument to snowflake-proxy. Beware that will require your clients to also change their broker server.

You can learn more about the technical concepts in the wiki or this page from the original author published back in 2017.

A snowflake bridge (proxy) is arguably a bit easier to set up.
You will need:

  • direct internet connection
    No NAT - at least on some ports. From my experience, port forwarding does not work too well with snowflake. It's true snowflake can work even behind NATed environments however its helpfulness is pretty limited there, I was barely able to get anyone to connect to my proxy running behind NAT.

  • small VPS running Debian (same as for webtunnel)
    You do not need Tor daemon running, however Snowflake proxy itself is pretty memory heavy (can use 200-300MB by itself). I would recommend having at least 512MB RAM.

---
- name: Deploy Tor Snowflake Proxy
  hosts: snowflake_bridges
  become: true
  vars:
    snowflake_user: snowflake
    snowflake_home: /var/lib/snowflake
    snowflake_repo: https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
    snowflake_bin_dir: /usr/local/bin
    port_range_width: 200

  tasks:
    - name: Install build dependencies
      ansible.builtin.apt:
        name:
          - acl
          - git
          - golang
          - build-essential
        state: present
        update_cache: yes

    - name: Create snowflake system user
      ansible.builtin.user:
        name: "{{ snowflake_user }}"
        system: yes
        home: "{{ snowflake_home }}"
        create_home: yes
        shell: /usr/sbin/nologin

    - name: Check if Snowflake service already exists
      ansible.builtin.stat:
        path: /etc/systemd/system/snowflake-proxy.service
      register: service_file

    - name: Extract existing port range (if service exists)
      ansible.builtin.shell: |
        grep -oP 'ephemeral-ports-range \K[0-9]+:[0-9]+' /etc/systemd/system/snowflake-proxy.service
      register: existing_ports
      when: service_file.stat.exists
      changed_when: false

    - name: Generate random port range (if fresh install)
      ansible.builtin.set_fact:
        generated_start: "{{ 36000 | random(start=32000) }}"
      when: not service_file.stat.exists

    - name: Set final port range variable
      ansible.builtin.set_fact:
        snowflake_port_range: >-
          {{ existing_ports.stdout 
             if (service_file.stat.exists and existing_ports.stdout | length > 0) 
             else (generated_start | string + ':' + (generated_start | int + port_range_width) | string) }}

    - name: Display active port range
      ansible.builtin.debug:
        msg: "Snowflake Proxy will run on UDP ports: {{ snowflake_port_range }}"

    - name: Create build directory
      ansible.builtin.file:
        path: "{{ snowflake_home }}/src"
        state: directory
        owner: "{{ snowflake_user }}"
        group: "{{ snowflake_user }}"
        mode: '0755'

    - name: Clone Snowflake repository
      ansible.builtin.git:
        repo: "{{ snowflake_repo }}"
        dest: "{{ snowflake_home }}/src/snowflake"
        version: main
        depth: 1
        force: yes
      become_user: "{{ snowflake_user }}"
      register: git_clone

    - name: Build Snowflake Proxy binary
      ansible.builtin.command:
        cmd: go build -o {{ snowflake_home }}/snowflake-proxy
        chdir: "{{ snowflake_home }}/src/snowflake/proxy"
      environment:
        GOCACHE: "{{ snowflake_home }}/.cache/go-build"
      become_user: "{{ snowflake_user }}"
      when: git_clone.changed
      register: go_build

    - name: Clean Go build cache
      ansible.builtin.command:
        cmd: go clean -cache
      environment:
        GOCACHE: "{{ snowflake_home }}/.cache/go-build"
      become_user: "{{ snowflake_user }}"
      when: go_build.changed

    - name: Install binary to system path
      ansible.builtin.copy:
        src: "{{ snowflake_home }}/snowflake-proxy"
        dest: "{{ snowflake_bin_dir }}/snowflake-proxy"
        remote_src: yes
        mode: '0755'
        owner: root
        group: root
      notify: Restart Snowflake

    - name: Create Systemd Service file
      ansible.builtin.copy:
        dest: /etc/systemd/system/snowflake-proxy.service
        content: |
          [Unit]
          Description=Tor Snowflake Proxy
          After=network.target

          [Service]
          Type=simple
          User={{ snowflake_user }}
          ExecStart={{ snowflake_bin_dir }}/snowflake-proxy -capacity {{ port_range_width//2 }} -ephemeral-ports-range {{ snowflake_port_range }}
          Restart=on-failure
          RestartSec=10

          # Hardening
          CapabilityBoundingSet=CAP_NET_BIND_SERVICE
          AmbientCapabilities=CAP_NET_BIND_SERVICE
          NoNewPrivileges=yes
          PrivateTmp=yes
          ProtectSystem=strict
          ProtectHome=yes

          [Install]
          WantedBy=multi-user.target
      notify: Restart Snowflake

    - name: Enable and start Snowflake service
      ansible.builtin.systemd:
        name: snowflake-proxy
        state: started
        enabled: yes
        daemon_reload: yes

  handlers:
    - name: Restart Snowflake
      ansible.builtin.systemd:
        name: snowflake-proxy
        state: restarted
        daemon_reload: yes

You can specify how many ports to allocate to snowflake port_range_width: 200. Playbook is designed to randomly pick N consecutive ones but you may change that using the -ephemeral-ports-range parameter. The number of simultaneously connected clients is N/2 at maximum.

The playbook will clone and compile Snowflake proxy from the official repository. This may take a few minutes of 100% utilized CPU.

How to check it is working

Snowflake daemon will periodically print out the statistics in the system log:

$ sudo journalctl -xeu snowflake-proxy
 In the last 1h0m0s, there were 17 completed successful connections. Traffic Relayed ↓ 367858 KB (102.18 KB/s), ↑ 29148 KB (8.10 KB/s).
 In the last 1h0m0s, there were 17 completed successful connections. Traffic Relayed ↓ 415168 KB (115.32 KB/s), ↑ 23925 KB (6.65 KB/s).
 In the last 1h0m0s, there were 13 completed successful connections. Traffic Relayed ↓ 429052 KB (119.18 KB/s), ↑ 17835 KB (4.95 KB/s).
 In the last 1h0m0s, there were 7 completed successful connections. Traffic Relayed ↓ 958863 KB (266.35 KB/s), ↑ 52831 KB (14.68 KB/s).
 In the last 1h0m0s, there were 18 completed successful connections. Traffic Relayed ↓ 282815 KB (78.56 KB/s), ↑ 23143 KB (6.43 KB/s).
 In the last 1h0m0s, there were 11 completed successful connections. Traffic Relayed ↓ 118503 KB (32.92 KB/s), ↑ 20306 KB (5.64 KB/s).
 In the last 1h0m0s, there were 13 completed successful connections. Traffic Relayed ↓ 146744 KB (40.76 KB/s), ↑ 12292 KB (3.41 KB/s).
 In the last 1h0m0s, there were 16 completed successful connections. Traffic Relayed ↓ 132514 KB (36.81 KB/s), ↑ 15211 KB (4.23 KB/s).
 In the last 1h0m0s, there were 14 completed successful connections. Traffic Relayed ↓ 249259 KB (69.24 KB/s), ↑ 39897 KB (11.08 KB/s).

How much help/traffic to expect

It depends. I will mention the exact reasons below, however some of my bridges never really gained traction, while others were using 100s of GBs per day. It's pretty hard to predict which one will perform well.
To better monitor how much my bridges actually do, I wrote a small eBPF program to monitor traffic on snowflake ports (or 443 in case of webtunnel). It measures how much traffic is coming from a given network on specific day and sends the data to a central server for visualization purposes.

Those are some stats from past 28 days:

image
as you may notice, not every Tor bridge user comes from a censored country

Additional notes

Last but not least - beware your bridges may get blocked and loose their clients over time. Some may never even get many clients in the first place. It usually works like this - firewalls can adapt and seeing a spike of traffic to particular website/IP address/IP range with no clear purpose, it will most likely get automatically dropped some time. It's an endless game of cat and mouse. Additionally remember that no amount of bridges will help when the entire country is cut off from the internet.
The distribution method is not perfect either, relays can be discovered and there's in fact a project actively doing that just to show how flawed the process currently is.

There are some good videos on how this currently works and how censors tried to block bridges in the past:

37C3 - Tor censorship attempts in Russia, Iran, Turkmenistan
Feds try Censoring Tor, Accidentally take down Microsoft Azure

Comments

  • allthemtingsallthemtings Member, Megathread Squad

    Instructions unclear ive ended up in a local titty bar in romania, is this normal?

  • MurvMurv Member, Megathread Squad

    @allthemtings said:
    Instructions unclear ive ended up in a local titty bar in romania, is this normal?

    Send location

  • Love you!

    Thanked by 3oloke forest admax
  • @Murv said:

    @allthemtings said:
    Instructions unclear ive ended up in a local titty bar in romania, is this normal?

    Send location

    Please send in text, do not send in co-ordination.

    Thanked by 2oloke Murv
  • sh97sh97 Member, Host Rep

    merci beaucoup monsieur olok

  • RubbenRubben Member

    can I use this to watch gay porn

  • Thank you! Well written <3

    Thanked by 2oloke forest
  • NekoparaNekopara Member

    now i only need time to read AND understand it :lol: defintely going to try setup some snowflakes this weekend

    Thanked by 2nghialele forest
  • DecicusDecicus Member

    Wow this is a lot of words

  • @Murv said: Send location

    No.

    Thanked by 1oloke
  • @Rubben said: can I use this to watch gay porn

    No.

    Thanked by 1oloke
  • MurvMurv Member, Megathread Squad

    @JohnFilch123 said:

    @Murv said: Send location

    No.

    image

    Thanked by 2oloke forest
  • barbarzabarbarza Member
    Thanked by 2Murv oloke
  • conceptconcept Member

    Ansible is great for setting up multiple servers at once. Also using the Tor config file does give you more control. I find the docker container setup is pretty easy to use.

    Thanked by 1oloke
  • dbadudedbadude Member

    omg so much work, off the grid is so much easier.

    Thanked by 1oloke
  • forestforest Member

    @oloke said: You do not need Tor daemon running, however Snowflake proxy itself is pretty memory heavy (can use 200-300MB by itself). I would recommend having at least 512MB RAM.

    Are you sure? That's just the allocated virtual memory. The RSS (which is the amount of memory it actually uses) is typically under 50 MiB, whereas Tor often likes nearly 1 GiB of RSS.

  • olokeoloke Member, Host Rep

    @forest said:

    @oloke said: You do not need Tor daemon running, however Snowflake proxy itself is pretty memory heavy (can use 200-300MB by itself). I would recommend having at least 512MB RAM.

    Are you sure? That's just the allocated virtual memory. The RSS (which is the amount of memory it actually uses) is typically under 50 MiB, whereas Tor often likes nearly 1 GiB of RSS.

    Hmm, I'm pretty sure it always required around 200MB RAM by itself. At least that's what my experience was.

    $ ps aux --sort=-rss | head -n2
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    snowfla+    1369  1.5 10.8 1960884 219648 ?      Ssl  Mar01  57:02 /usr/local/bin/snowflake-proxy -capacity 100 -ephemeral-ports-range ...:...
    

    and another one:

    $ ps aux --sort=-rss | head -n2
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    snowfla+  328674  2.6 21.6 2034756 214800 ?      Ssl  Feb24 284:55 /usr/local/bin/snowflake-proxy -capacity 100 -ephemeral-ports-range ...:...
    
    Thanked by 1nghialele
  • forestforest Member

    @oloke said:

    @forest said:

    @oloke said: You do not need Tor daemon running, however Snowflake proxy itself is pretty memory heavy (can use 200-300MB by itself). I would recommend having at least 512MB RAM.

    Are you sure? That's just the allocated virtual memory. The RSS (which is the amount of memory it actually uses) is typically under 50 MiB, whereas Tor often likes nearly 1 GiB of RSS.

    Hmm, I'm pretty sure it always required around 200MB RAM by itself. At least that's what my experience was.

    $ ps aux --sort=-rss | head -n2
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    snowfla+    1369  1.5 10.8 1960884 219648 ?      Ssl  Mar01  57:02 /usr/local/bin/snowflake-proxy -capacity 100 -ephemeral-ports-range ...:...
    

    and another one:

    $ ps aux --sort=-rss | head -n2
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    snowfla+  328674  2.6 21.6 2034756 214800 ?      Ssl  Feb24 284:55 /usr/local/bin/snowflake-proxy -capacity 100 -ephemeral-ports-range ...:...
    

    What version of Snowflake are you using? The one in Debian stable is very outdated (2.5.1-1+b16), but the one in Debian testing is newer (2.10.1-1+b1).

    root@forest-maxko-1-za:~# ps -C snowflake-proxy -o rss,cmd
      RSS CMD
    28680 /usr/bin/snowflake-proxy -outbound-address [REDACTED]
    

    That is similar to all the others I run, and the traffic I get is similar to what you get:

    root@forest-maxko-1-za:~# journalctl --no-pager --no-hostname -b -u snowflake-proxy -n 10 -g 'In the last'
    Mar 04 00:46:19 snowflake-proxy[974]: 2026/03/04 00:46:19 In the last 1h0m0s, there were 10 completed connections. Traffic Relayed ↓ 9529 KB (2.65 KB/s), ↑ 2456 KB (0.68 KB/s).
    Mar 03 23:46:19 snowflake-proxy[974]: 2026/03/03 23:46:19 In the last 1h0m0s, there were 11 completed connections. Traffic Relayed ↓ 13575 KB (3.77 KB/s), ↑ 2032 KB (0.56 KB/s).
    Mar 03 22:46:19 snowflake-proxy[974]: 2026/03/03 22:46:19 In the last 1h0m0s, there were 18 completed connections. Traffic Relayed ↓ 21472 KB (5.96 KB/s), ↑ 3475 KB (0.97 KB/s).
    Mar 03 21:46:19 snowflake-proxy[974]: 2026/03/03 21:46:19 In the last 1h0m0s, there were 14 completed connections. Traffic Relayed ↓ 77248 KB (21.46 KB/s), ↑ 6648 KB (1.85 KB/s).
    Mar 03 20:46:19 snowflake-proxy[974]: 2026/03/03 20:46:19 In the last 1h0m0s, there were 14 completed connections. Traffic Relayed ↓ 176744 KB (49.10 KB/s), ↑ 14052 KB (3.90 KB/s).
    Mar 03 19:46:19 snowflake-proxy[974]: 2026/03/03 19:46:19 In the last 1h0m0s, there were 20 completed connections. Traffic Relayed ↓ 129224 KB (35.90 KB/s), ↑ 8141 KB (2.26 KB/s).
    Mar 03 18:46:19 snowflake-proxy[974]: 2026/03/03 18:46:19 In the last 1h0m0s, there were 20 completed connections. Traffic Relayed ↓ 57287 KB (15.91 KB/s), ↑ 4998 KB (1.39 KB/s).
    Mar 03 17:46:19 snowflake-proxy[974]: 2026/03/03 17:46:19 In the last 1h0m0s, there were 15 completed connections. Traffic Relayed ↓ 123213 KB (34.23 KB/s), ↑ 11540 KB (3.21 KB/s).
    Mar 03 16:46:19 snowflake-proxy[974]: 2026/03/03 16:46:19 In the last 1h0m0s, there were 12 completed connections. Traffic Relayed ↓ 54992 KB (15.28 KB/s), ↑ 9496 KB (2.64 KB/s).
    Mar 03 15:46:19 snowflake-proxy[974]: 2026/03/03 15:46:19 In the last 1h0m0s, there were 16 completed connections. Traffic Relayed ↓ 39465 KB (10.96 KB/s), ↑ 8968 KB (2.49 KB/s).
    
    Thanked by 1oloke
  • olokeoloke Member, Host Rep

    @forest said:

    @oloke said:

    @forest said:

    @oloke said: You do not need Tor daemon running, however Snowflake proxy itself is pretty memory heavy (can use 200-300MB by itself). I would recommend having at least 512MB RAM.

    Are you sure? That's just the allocated virtual memory. The RSS (which is the amount of memory it actually uses) is typically under 50 MiB, whereas Tor often likes nearly 1 GiB of RSS.

    Hmm, I'm pretty sure it always required around 200MB RAM by itself. At least that's what my experience was.

    $ ps aux --sort=-rss | head -n2
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    snowfla+    1369  1.5 10.8 1960884 219648 ?      Ssl  Mar01  57:02 /usr/local/bin/snowflake-proxy -capacity 100 -ephemeral-ports-range ...:...
    

    and another one:

    $ ps aux --sort=-rss | head -n2
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    snowfla+  328674  2.6 21.6 2034756 214800 ?      Ssl  Feb24 284:55 /usr/local/bin/snowflake-proxy -capacity 100 -ephemeral-ports-range ...:...
    

    What version of Snowflake are you using? The one in Debian stable is very outdated (2.5.1-1+b16), but the one in Debian testing is newer (2.10.1-1+b1).

    snowflake-proxy 2.11.0 (e6b36224)
    
    snowflake-proxy 2.11.0 (7afd18e5)
    

    Compiled from source exactly as in the playbook.

    Thanked by 1forest
  • forestforest Member
    edited March 4

    That's interesting. I wonder why it's using so much RSS. Perhaps setting the custom ephemeral port range rather than letting it choose did something strange? It's by far the lightest daemon I run.

    Btw, you can make the Tor daemon also use less memory if you switch it to use jemalloc2! I always do:

    apt -y install jemalloc2
    systemctl edit --stdin [email protected] << EOF
    [Service]
    Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
    EOF
    systemctl restart tor
    

    That reduces memory fragmentation and reduces RSS by replacing glibc's malloc (ptmalloc3) with jemalloc2. Perhaps that would also help with snowflake-proxy.

    Thanked by 1oloke
Sign In or Register to comment.