Skip to content

toralf/tor-relays

Repository files navigation

StandWithUkraine

A stack to deploy public and private Tor bridges or Snowflake proxies

Quick start

To setup a new Tor public bridge at an existing recent Debian system (i.e. with the hostname my_bridge), do

  1. clone this repo

    git clone https://github.com/toralf/tor-relays.git
    cd ./tor-relays
  2. create seeds (and keep them secret):

    cat <<EOF >> secrets/local.yaml
    ---
    seed_address: "$(base64 < /dev/urandom | tr -d '+/=' | head -c 32)"
    seed_metrics: "$(base64 < /dev/urandom | tr -d '+/=' | head -c 32)"
    seed_tor_port: "$(base64 < /dev/urandom | tr -d '+/=' | head -c 32)"
    
    EOF
    
    chmod 400 secrets/local.yaml
  3. add my_bridge to the group tor in the ./inventory:

    ---
    tor:
      hosts:
        my_bridge:
          bridge_distribution: "any"
          tor_port: 12345
  4. deploy it

    ./site-setup.yaml --limit my_bridge
  5. get its data:

    ./site-info.yaml --limit my_bridge
    grep my_bridge ~/tmp/*

Details

The deployment is made by Ansible. See the section Metrics below how to scrape runtime metrics. The Ansible role expects a seed_address value to configure a relyable randomized ipv6 address at a Hetzner system (at IONOS a proposed one is only displayed). For Tor servers is the DDoS solution of torutils used. For other systems a set of firewall rules provide basic protection.

The MyFamily value (i.e. for the host group server_test) can be created by:

./site-info.yaml --limit server_test --tags wellknown

echo -e "---\nmy_family: $(grep -v '#' ~/tmp/server_rsa-fingerprint.txt | xargs | tr ' ' ',')" > ./inventory/group_vars/server_test.yaml

Additional software

To deploy additional software, define (i.e. for a Quassel server) it like:

hosts:
  my_system:
    additional_ports:
      - "4242"
    additional_software:
      - "quassel-core"

Compiling the Linux kernel, Tor, Lyrebird or Snowflake from source

As default HEAD (of branch main) is taken. A dedicated branch can be defined by the variable <...>_git_version. Furthermore <...>_patches can provide additional patches (as URLs) to be applied on top.

Metrics

If a Prometheus server is configured (e.g. prometheus_server: "1.2.3.4") then inbound traffic from its ip to the local metrics port is allowed by a firewall rule. An Nginx is used to encrypt the metrics data transfer on transit, using the certificate of the self-signed CA (to be generated once before). This CA key has then to be presented to the Prometheus to enable the TLS traffic.

Configure a randomly choosen metrics_port (using seed_metrics similar to seed_address) to expose metrics at https://address:metrics_port/metrics-node|snowflake|tor:

snowflake:
  vars:
    metrics_port: "{{ range(16000,60999) | random(seed=seed_metrics + inventory_hostname + ansible_facts.default_ipv4.address + ansible_facts.default_ipv6.address) }}"
    snowflake_metrics: true

A Prometheus node exporter is deployed by defining prometheus_node_exporter: true.

For more Prometheus config examples and Grafana dashboards take a look at this repository.

Misc

The value targets (used in the Prometheus server config file) can be created e.g. by:

./site-info.yaml --tags metrics-port
sort ~/tmp/*_metrics_port | xargs -n 10 | sed -e 's,$,"],' -e 's, ,"\, ",g' -e 's,^,- targets: [",'

The scripts under ./bin work for the Hetzner Cloud API only.

To create there a new VPS with the hostname my_bridge in the project my_project, do:

hcloud context use my_project
./bin/create-server.sh my_bridge

The script ./bin/update-dns.sh expects unbound as a local DNS resolver, configured for the appropriate project:

include: "/etc/unbound/hetzner-<project>.conf"

(hcloud uses the term "context" for a project)

Links