How to Run Tor Bridge with obfs4 on VPS
Set up one cheap VPS as an obfs4 Tor bridge with torrc, port and firewall settings, log lines wey confirm e work, plus how users go get your bridge.
Wetin Tor bridge be, and why e dey exist
Tor bridge na entry point into Tor network wey dem no publish im address for public relay list. Dem dey call dat list consensus. Na signed document wey anybody fit download, and censor fit download am too. To block Tor from dat list no hard; fetch consensus, then drop every address wey dey inside am for border. Bridges dey exist because published list na the weak point. Dem dey give bridge addresses out small-small, so no single request go hand over the complete set.
Address wey no dey listed na only half of the solution. Deep packet inspection (DPI), wey dey classify traffic by wetin dey inside am instead of address, fit recognise Tor connection from the shape of im TLS (transport layer security) handshake. Censor wey no get any list still fit see say “this one resemble Tor” and drop the connection. Pluggable transport dey remove that signal. E wrap Tor stream inside another format for client side, and your bridge unwrap am.
obfs4 na the transport wey most bridges dey run. E turn the stream into bytes wey no get header or fixed handshake, so DPI no get pattern to match. E still authenticate the client. The cert= value inside bridge line na cryptographic key wey client must prove say e hold before bridge go answer at all. This one dey stop active probing: censor wey connect to your address to test whether e dey speak Tor no go get reply, and e no go learn anything.
Wetin pluggable transport you suppose run?
- obfs4 need one VPS, two TCP ports, and no domain name. Na the easiest useful thing wey you fit run, and na wetin this guide dey talk about.
- WebTunnel dey hide the connection inside normal HTTPS traffic wey go one real website. Tor Project list the requirements as static IPv4 address, domain wey you control, working web server like NGINX or Apache, valid TLS certificate, and at least 1 GB RAM, with 4 GB recommended. E good for networks where random-looking traffic by itself dey look suspicious, because country wey allow only small web browsing still dey allow HTTPS.
- Snowflake na different kind contribution. Volunteers dey run short-lived WebRTC proxies, so the entry points dey change all the time and censor no get stable address to block. You no dey operate bridge for am. You dey run proxy, and e no need fixed address.
Start with obfs4. Later, you fit add WebTunnel bridge for second address: if you run both for one IP, blocking one address go stop both.
Wetin running a bridge go cost you?
The data behind this chart
[
{
"label": "Bridge, minimum",
"min_upstream_mbit": 1
},
{
"label": "Guard or middle relay, minimum",
"min_upstream_mbit": 10
},
{
"label": "Guard or middle relay, recommended",
"min_upstream_mbit": 16
}
]As of August 2026, Tor Project dey ask bridge for at least 1 Mbit/s upstream and downstream bandwidth. Dem dey ask guard or middle relay for 10 Mbit/s, and 16 Mbit/s dey recommended. These na published requirements, no be measurements. New bridge usually dey far below its own minimum for weeks. The same requirements page dey ask relay for at least 100 GByte outbound traffic every month. The smallest plans already cover this, so read wetin small VPS really cost every month before you size anything bigger.
The abuse surface small, and na this part people dey get wrong. Bridge na the first hop. Traffic wey dey leave your server go another Tor relay, e no go ever go website wey user choose. Your IP address no go ever appear for stranger web log as source of request, so complaint mail wey exit relay operators dey handle no go reach here. Still check your provider acceptable use policy, because some hosts dey treat any Tor service as special case.
One thing you no suppose do: convert existing public relay to bridge for the same address. Tor Project advice for that case na to change "IP address, name and fingerprint", because old address don already dey for consensus wey censors download. Bridge wey be public relay last week na bridge wey already dey blocklist.
Uptime matter pass speed. Relay requirements talk say "if your relay is not running for more than 2 hours a day its usefulness is limited", and bridge dey worse than relay for this matter, because each client get one address and no fallback. Restart go disconnect every user wey dey use am. Set up TCP port check for Uptime Kuma against obfs4 port, so you go know the day e stop to answer.
Tor Project repository from Tor install
Distribution packages dey lag, and bridge na security software wey suppose stay current. Add the project own repository first.
sudo apt update
sudo apt install -y apt-transport-https gnupg wget lsb-release
wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | sudo tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/nullNow write the source file. The Suites: line suppose contain your release codename, so read am from the system instead of typing am from memory.
sudo tee /etc/apt/sources.list.d/tor.sources >/dev/null <<EOF
Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: $(lsb_release -cs)
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpg
EOF
sudo apt update
sudo apt install -y tor deb.torproject.org-keyring obfs4proxyIf apt update report say repository no get Release file for your codename, Tor Project no carry that release. Delete /etc/apt/sources.list.d/tor.sources, run sudo apt update again, and install the tor package wey your distribution ship. Everything below remain the same.
The obfs4proxy package come from Debian and Ubuntu themselves (version 0.0.14 for Debian 13, as of August 2026). Confirm where the binary land, because na the path go enter the config:
command -v obfs4proxy || command -v lyrebirdUpstream rename the project to lyrebird, so newer package fit install /usr/bin/lyrebird instead. Use whichever path that command print.
Set bridge for /etc/tor/torrc
BridgeRelay 1
ORPort 8443
ServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy
ServerTransportListenAddr obfs4 0.0.0.0:9443
ExtORPort auto
ContactInfo you@example.com
Nickname PickANickname
BridgeDistribution anyEvery line for there get one failure wey attach to am, so handle dem one after another.
BridgeRelay 1 dey tell tor make e send descriptor go bridge authority instead of public consensus. Na this one line dey make relay stay unlisted.
ORPort na the real Tor port. E must dey reachable from internet, because tor dey test am and e no go publish descriptor until the test pass.
ServerTransportPlugin dey give tor command wey e go run. tor dey start obfs4proxy as child process and dey communicate with am through pipe, so obfs4proxy no get service unit of e own and e no dey show for systemctl status.
ServerTransportListenAddr dey fix the port wey obfs4proxy go listen on. If you leave this line out, obfs4proxy go pick free port when e start, and e fit pick different port after most restarts. This one mean say every bridge line wey you don share go point to port wey nothing dey listen on. Those clients go get refused connection and stop trying.
ExtORPort auto dey open extended ORPort, wey obfs4proxy dey use as loopback channel to return completed connections to tor together with client address. The Tor Project setup guide dey include am for every bridge, because without am the transport no fit report that address to tor.
ContactInfo and Nickname both dey public. Use address wey you go dey read, because na through am The Tor Project go reach you about broken bridge. Pick nickname wey no identify you if you prefer stay quiet.
BridgeDistribution dey choose which distributor go give users your address. The accepted values na https, email, telegram, settings, none and any. Use any for your first bridge and allow the system decide. Use none for private bridge wey you dey share yourself; this one keep the address completely out of public distribution.
Why port choice matter
No use 9001 for both ports. Tor Project talk this one directly, because 9001 na the traditional ORPort and censors dey scan internet for am. The two ports must also different from each other, because tor and obfs4proxy each bind their own listener.
The strongest obfs4 port na 443. Outbound 443 dey open for almost every restricted network, and long connection to am go look like normal web session. Binding below 1024 need one extra step, because obfs4proxy no dey run as root:
sudo setcap cap_net_bind_service=+ep /usr/bin/obfs4proxy
sudo systemctl edit tor@.service tor@default.serviceAdd these two lines for each editor wey open:
[Service]
NoNewPrivileges=noThe capability by itself no enough. systemd's NoNewPrivileges dey stop process from gaining any privilege wey its parent no get, and file capability na exactly that, so obfs4proxy no fit bind 443 while this setting dey on.
If you prefer skip that step, choose ordinary high port and write am down. Any port wey you choose, no change the obfs4 port later. Bridge line dey tie address, port, fingerprint and certificate together, so every copy wey already dey inside user's browser go stop work immediately the port move.
Open the ports for both firewalls
sudo ufw allow 8443/tcp
sudo ufw allow 9443/tcp
sudo ufw statusBoth ports need make dem open, and most providers dey run another firewall for their control panel wey ufw no know anything about. Rule wey dey exist for the box but no dey for the panel go create bridge wey nobody fit reach and wey no dey publish descriptor. If any part of this still new to you, the ufw rules wey fresh VPS need and wetin listening port really mean for Linux explain am. As you dey do that, lock down SSH with keys and hardened sshd config. Bridge wey no list for box wey use password SSH still be box wey use password SSH.
Start am, then read the log
sudo systemctl enable --now tor.service
sudo systemctl restart tor.service
sudo journalctl -e -u tor@defaultDebian and Ubuntu dey ship two units. tor.service na small wrapper, while tor@default.service na the process wey dey do the work. Na why journalctl -u tor dey look almost empty, while the log wey you need dey under tor@default.
Two lines show say e work:
Self-testing indicates your ORPort is reachable from the outside. Excellent. Publishing server descriptor.
Registered server transport 'obfs4' at '0.0.0.0:9443'The first one mean say reachability test pass, and the descriptor reach the bridge authority. If e no ever show, something between the internet and your server dey drop traffic to the ORPort. The second line must show the port wey you configure. If e show different port, tor no apply ServerTransportListenAddr. The usual cause na transport name wey no match: e must read obfs4 for both directives.
Confirm say the two listeners dey exist:
sudo ss -lntp | grep -E 'tor|obfs4|lyrebird'Wetin be my bridge line?
obfs4proxy dey write one template inside tor data directory:
sudo cat /var/lib/tor/pt_state/obfs4_bridgeline.txtThat directory belong to tor user and e get mode 700, so if you no use sudo, you go get Permission denied. The file get one line for this format:
Bridge obfs4 <IP ADDRESS>:<PORT> <FINGERPRINT> cert=<CERTIFICATE> iat-mode=0Replace <IP ADDRESS> with your server public address, <PORT> with the obfs4 port, no be the ORPort, and <FINGERPRINT> with the identity fingerprint wey tor write inside its data directory:
sudo cat /var/lib/tor/fingerprint
sudo cat /var/lib/tor/hashed-fingerprintThe first file get your nickname and the identity fingerprint wey suppose dey inside bridge line. The second one get the hashed fingerprint. Na this one you paste inside Relay Search to check whether your bridge dey run and roughly how many clients dey reach am. You no fit use the two interchangeably. If bridge line carry the hashed value, e no go match the identity key wey your bridge present, so the client go reject the connection wey e just open.
Bridge dey reach users how?
You no dey hand your bridge line give anybody. Once descriptor reach bridge authority, distribution system (rdsys, wey replace BridgeDB) go assign your bridge to one distributor, and users go ask that distributor for bridges. As of August 2026, routes na these:
- The web form for bridges.torproject.org/options, wey dey serve bridge lines after captcha.
- Email to bridges@torproject.org from Gmail or Riseup address, wey go reply with bridge lines. This provider restriction dey because unlimited free accounts fit allow one censor enumerate every bridge.
- The Telegram bot @GetBridgesBot. Send
/start, then/obfs4or/webtunnel. - Tor Browser itself, under Settings then Connection, where "Request bridges" dey fetch dem through moat channel.
New bridge go show for Relay Search about three hours after setup. Users fit take much longer: Tor Project own wording be say, "It can take several days or weeks until you see a consistent set of users." If the first two weeks quiet, na normal; e no mean say fault dey.
If you set BridgeDistribution none, you opt out of everything. The bridge line go remain for you to send give the people wey need am, through channel wey censor no dey read.
When something no work
No self-testing line for the log. The ORPort no dey reachable. Test am from another machine with nc -vz your.ip 8443. If e hang, packets dey drop, so check ufw and provider panel. If e refuse, tor no dey listen, so check ss -lntp and read the log for config error.
The registered transport show port wey you no choose. tor ignore ServerTransportListenAddr. The transport name must match the one for ServerTransportPlugin exactly, and both must be obfs4.
obfs4proxy no go bind port 443. Confirm the capability with getcap /usr/bin/obfs4proxy, then confirm say the override reach the unit with systemctl show tor@default -p NoNewPrivileges. If e print NoNewPrivileges=yes, your drop-in go a unit wey no dey run.
Nothing dey inside /var/lib/tor/pt_state/. tor never start the transport, meaning say the path for ServerTransportPlugin wrong. Compare am with the output of command -v obfs4proxy.
Clients stop connecting after a change. Any change to the address or the obfs4 port invalidate every bridge line wey dem don distribute already. Check whether the server public IP move too. Some providers dey do this when dem rebuild the server.
tor no go start at all. Run sudo -u debian-tor tor --verify-config -f /etc/tor/torrc. E parse the file, print the line wey e object to, and leave the running service as e dey.
FAQ
My VPS provider go complain about Tor bridge?
Bridge na entry point, so traffic wey dey comot from your server go other Tor relays and e no go ever go site wey user choose. Your IP address no go show for anybody web log as source of request, and na this one dey cause the complaints wey exit relay operators dey handle. Hosting rules still dey vary, and some providers dey treat any Tor service as special case, so read the acceptable use policy before you start and put address wey you read into ContactInfo.
How much bandwidth Tor bridge dey use?
The published minimum na 1 Mbit/s up and down, compared with 10 Mbit/s for guard or middle relay. Real use dey start near zero, because your bridge only carry traffic for users wey distributor send come meet am. If you want hard ceiling, set RelayBandwidthRate and RelayBandwidthBurst for torrc.
Why nobody don connect to my new bridge?
Bridge dey take about three hours before e appear for Relay Search, and Tor Project guidance be say consistent set of users fit take several days or weeks. Check say descriptor publish, wey be the self-testing line for journalctl -u tor@default, look up your hashed fingerprint for Relay Search, and confirm say BridgeDistribution no set to none.
Make I run obfs4 or WebTunnel?
Run obfs4 if na your first bridge: one VPS, two ports, no domain, no certificate. Run WebTunnel where dem dey block traffic wey look random by itself, because e need domain wey you control, real web server, valid TLS certificate, and at least 1 GB of RAM. Put dem for separate addresses if you run both, because one blocked IP go otherwise remove two bridges at once.
Wetin go happen if I change obfs4 port later?
Every bridge line wey dem don distribute go stop to work. Bridge line dey tie address, port, fingerprint, and certificate together, so client wey hold old line go open connection to port wey nothing dey listen on, then e go give up. The same thing apply when server public IP change. Choose port during setup and leave am like that.