TechEarl

Tor Bridges Explained: obfs4, Snowflake, and meek (with Setup)

When your ISP or country blocks Tor, bridges and pluggable transports keep you connected. Compares obfs4, Snowflake, and meek, how to add each to torrc, and how to get fresh bridge lines from bridges.torproject.org or by email.

Ishan KarunaratneIshan Karunaratne⏱️ 9 min readUpdated
When ISPs block Tor, use bridges. Compares obfs4, Snowflake, and meek pluggable transports, how to add each to torrc, and how to get fresh bridge lines.

Tor bridges are unlisted entry relays. The public guard set is published in the Tor consensus, which makes blocking trivial: an ISP just drops traffic to those IPs. Bridges aren't published, so they survive most blocks. Pluggable transports take it further by also disguising what Tor traffic looks like on the wire (obfs4 makes it random bytes, Snowflake makes it WebRTC, meek makes it HTTPS to a major CDN). Below is when to reach for each transport, the working torrc for all three, and how to refresh bridge lines when one gets burned.

When you actually need bridges

You need bridges when:

  • The Tor consensus IPs are blocked at your network edge (corporate firewall, country-level filter, hotel Wi-Fi).
  • Direct connection to 9001/tcp to the public Tor relays gets reset.
  • You can reach https://www.torproject.org only via tricks like DNS-over-HTTPS or another VPN.

You don't need bridges when:

  • Plain Tor works. Bridges add latency for no benefit.
  • You're trying to hide from a country adversary that sees your traffic patterns. Bridges protect against IP-list blocks, not from a state-level adversary running deep packet inspection — for those, you also need a pluggable transport (obfs4 minimum) and likely a residential network upstream.

Pluggable transport comparison

TransportLooks likeNetwork frictionBest for
obfs4Random bytes, no recognizable protocolLow latency, low CPUStandard censorship circumvention, the default first choice
SnowflakeWebRTC (browser P2P video traffic)Moderate latency, can drop mid-sessionCountries with aggressive obfs4 blocking (Iran, Russia recent) — uses volunteer browsers as proxies
meekHTTPS to a major CDN (Azure, Google, AWS)High latency, expensive for the networkLast resort when obfs4 and Snowflake both blocked; uses CDN domain fronting
webtunnelHTTPS to an ordinary websiteLow latency, hard to distinguish from regular HTTPSNewer transport; growing adoption since 2023

obfs4 is the daily-driver. Snowflake is the fallback when obfs4 IPs themselves are getting block-listed. meek is heavy and only useful when both above are dead.

Step 1: install the transports

The transports are separate binaries. On Debian/Ubuntu:

bash
sudo apt install obfs4proxy
# Snowflake is a separate package on recent releases:
sudo apt install snowflake-client

On macOS Homebrew:

bash
brew install obfs4proxy
brew install snowflake

On Fedora/RHEL:

bash
sudo dnf install obfs4
sudo dnf install snowflake-client

After install, locate the binaries — you'll need their paths for ClientTransportPlugin:

bash
which obfs4proxy
# /usr/bin/obfs4proxy

which snowflake-client
# /usr/bin/snowflake-client

Step 2: get fresh bridge lines

Three ways to get a bridge line, in increasing order of operational friction:

bridges.torproject.org (web)

Open https://bridges.torproject.org/options/ and pick a transport. The page returns three bridge lines per request. Refresh every 24 hours for a different set; the pool rotates to make bulk discovery harder.

If bridges.torproject.org is itself blocked (it often is in heavy-censorship countries), use one of the moat backends:

bash
# Via the moat-direct backend
curl https://moat.torproject.org/circumvention/api/v1/builtin

Email to bridges@torproject.org

If web requests are blocked entirely, email a request:

  • From: a Gmail, Riseup, or Outlook account (anti-abuse filter; other providers may be ignored)
  • To: bridges@torproject.org
  • Body: get transport obfs4 (or snowflake, meek-azure)

You get an auto-reply within a minute or two containing fresh bridge lines.

Built-in Tor Browser bridges

Tor Browser ships with a small set of "default bridges" hardcoded for first-time users. They're widely known and increasingly blocked in heavily-censored networks, but they're a fine starting point for testing your setup. Find them in the Tor Browser's torrc-defaults file inside the bundle.

Step 3: configure torrc

The pattern is identical across transports: enable bridges, point Tor at the transport binary, paste bridge lines.

obfs4 example torrc

text
UseBridges 1
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy

# Replace these with bridge lines from bridges.torproject.org
Bridge obfs4 192.0.2.10:443 0123456789ABCDEF0123456789ABCDEF01234567 cert=AAAA... iat-mode=0
Bridge obfs4 192.0.2.11:443 9876543210FEDCBA9876543210FEDCBA98765432 cert=BBBB... iat-mode=0
Bridge obfs4 198.51.100.5:443 ABCDEFFEDCBA0123ABCDEFFEDCBA01234567ABCD cert=CCCC... iat-mode=0

Three bridges is the right number: enough redundancy for one going down, low enough not to hammer volunteer infrastructure. Don't paste twenty — pick three.

Snowflake example torrc

text
UseBridges 1
ClientTransportPlugin snowflake exec /usr/bin/snowflake-client

# The IP in a snowflake Bridge line is symbolic — actual traffic
# routes via WebRTC through a volunteer browser, then to the relay.
Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72

Snowflake also accepts an inline configuration with custom relays, but the default works. The 56-character fingerprint is the destination relay, not the WebRTC peer.

meek example torrc

text
UseBridges 1
ClientTransportPlugin meek_lite exec /usr/bin/obfs4proxy

# meek-azure: domain-fronts through Azure CDN. The "front" is the
# externally visible HTTPS server name; "url" is the actual meek endpoint.
Bridge meek_lite 192.0.2.2:2 BE776A53492E1E044A26F17306E1BC46A55A1625 url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com utls=HelloRandomizedALPN

meek is the heaviest transport. Don't use it unless obfs4 and Snowflake are both failing. The Tor Project has been deprecating meek backends over time as CDN providers stop accepting domain fronting.

Mixing transports

You can include multiple transports in one torrc — Tor tries them in order:

text
UseBridges 1
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy
ClientTransportPlugin snowflake exec /usr/bin/snowflake-client

Bridge obfs4 192.0.2.10:443 0123456789ABCDEF... cert=AAAA... iat-mode=0
Bridge obfs4 192.0.2.11:443 9876543210FEDCBA... cert=BBBB... iat-mode=0
Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62...

Tor falls back to Snowflake if all the obfs4 bridges are unreachable. This is the resilient setup if you're operating in a network where obfs4 occasionally gets burned but Snowflake keeps working.

Step 4: reload and verify

bash
sudo systemctl reload tor
# or
sudo pkill -HUP tor

# Watch the logs to see which bridges connect
sudo tail -f /var/log/tor/notices.log

You're looking for lines like:

code
[notice] Bootstrapped 75% (enough_dirinfo): Loaded enough directory info to build circuits
[notice] Bootstrapped 100% (done): Done

If you see repeated failed to find Tor or cannot connect to bridge errors, your bridge lines may be burned. Get fresh ones from bridges.torproject.org and replace.

Operational tips

Don't reuse the same three bridges forever. Active censorship operations probe and block bridge IPs over weeks-to-months. Rotate every couple of months even if your current set still works.

Don't share bridge lines publicly. A bridge that ends up in a public gist gets onto block lists within days. If you want to help others, point them at bridges.torproject.org or the email backend.

Test your setup from a hostile-ish network if you can. Bridges that work fine from your home Wi-Fi might fail from a corporate or hotel network with deeper filtering. A cheap VPS in the country you're trying to circumvent is a good way to validate.

Single-onion clients can't use bridges. If you're running a single-onion hidden service (see v3 hidden service setup), the service side doesn't benefit from bridge routing — it routes through normal guards. Bridges help only the client side.

Running your own obfs4 bridge

If you want to give back, running an obfs4 bridge is straightforward and uses minimal bandwidth:

text
# /etc/tor/torrc (bridge-side)
BridgeRelay 1
ORPort 9001
ServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy
ServerTransportListenAddr obfs4 0.0.0.0:443
ExtORPort auto

ContactInfo your-email@example.com
Nickname myobfs4bridge

After running for a few hours, the bridge registers with the Tor BridgeDB and starts handing out to clients. Don't be discouraged by low traffic — bridges are deliberately distributed across many users, so any single bridge sees only a fraction of the load.

FAQ

See also

TagsTORBridgesobfs4SnowflakemeekPluggable TransportsCensorship CircumventionPrivacyAnonymity
Share
Ishan Karunaratne

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years across software, Linux systems, DevOps, and infrastructure — and a more recent focus on AI. Currently Chief Technology Officer at a tech startup in the healthcare space.

Keep reading

Related posts

Use grep -C 3 'pattern' file to print 3 lines before and after each match. The -A, -B, -C context flags, the -- group separator, asymmetric context, recursive search, and BSD vs GNU grep differences.

How to Show Lines Before and After a grep Match (Context)

grep -C 3 'pattern' file prints the matching line plus 3 lines on each side. The three context flags (-A after, -B before, -C both), how the -- group separator works between match blocks, asymmetric context, recursive context search, and the macOS BSD vs GNU differences that bite.

Use find -size +100M to list files larger than 100 megabytes. Unit suffixes (c/k/M/G), +/- sign convention, combine with sort -rn to surface the biggest files on disk, and BSD vs GNU rendering differences.

How to Find Files Larger Than a Size with find -size

find . -size +100M lists every file larger than 100 megabytes. The unit suffixes (c, k, M, G), the +/- sign convention, how to combine with sort to find the biggest files on disk, the BSD vs GNU divergence for printing sizes, and the wc -c trick for byte-exact thresholds.

Validate a US phone number with regex. Practical pattern, stricter NANP pattern, JavaScript / Python / PHP examples, what it lets through, common mistakes, and a test table.

How to Validate a US Phone Number with Regex

Validate a US phone number with regex. The practical pattern, a stricter NANP version, runnable examples in JavaScript, Python, and PHP, what it still lets through, common mistakes, and a test table.