Everything not listed in this document should behave the same as upstream Tor. If a feature, setting, or behavior is not mentioned here, the upstream documentation is accurate and fully applicable — see the Documentation section of
instructions.mdfor links.
Runs Tor as a non-exit relay or an obfs4 bridge. It never runs onion services and never lets traffic exit, and Tor starts only on a public IPv4 the user has confirmed.
- Image and Container Runtime
- Volume and Data Layout
- File Models
- Dependencies
- Network Access and Interfaces
- Installation and First-Run Flow
- Actions
- Tasks
- Health Checks
- Backups and Restore
- Limitations and Differences
- Built from
Dockerfile:alpine:3.23with pinnedtorandlyrebirdpackages plusbusybox-extrasfor the dashboard. - Architectures:
x86_64,aarch64. - One subcontainer (
tor-sub) runs three processes: aprepareoneshot (creates and chowns the mode's DataDirectory),tor -f /data/torrcas usertor, andbusybox-extras httpdserving/wwwon port 80.
Volume main, mounted at /data:
| Path | Contents |
|---|---|
store.json |
Package settings (see File Models) |
torrc |
Rendered on every start |
status.json |
Written every health-check cycle; read by the dashboard |
relay/ |
Tor DataDirectory and identity for relay mode |
bridge/ |
Tor DataDirectory and identity for bridge mode, including pt_state/ for obfs4 |
store.json(startos/fileModels/store.json.ts):configured,mode,nickname,contactInfo,bandwidthRate/bandwidthBurst(KB/s),accountingMax(GB per month or null),confirmedIp. Written by the Configure Node and Confirm Public IP actions;mainre-runs whenever it changes.torrc(startos/fileModels/torrc.ts): rendered bystartos/utils/torrc.tsfrom the store and the ORPort binding. Hand edits are overwritten on the next start.
None.
| Interface | Port | Type | Purpose |
|---|---|---|---|
| Dashboard | 80 (HTTP) | ui | Status page |
| Tor ORPort | 9001 (TCP, passthrough) | p2p | Tor network traffic; needs exactly one public IPv4 |
| obfs4 Bridge Port | 8443 (TCP, passthrough) | p2p | obfs4 clients in bridge mode; needs the same public IPv4 |
When StartOS assigns an external ORPort other than 9001, the torrc advertises the external port with NoListen and listens on 9001 with NoAdvertise. IPv6 is advertised only when a public IPv6 is enabled on the ORPort.
- Configure Node (critical task).
- Enable one public IPv4 on the Tor ORPort interface (and on obfs4 Bridge Port in bridge mode).
- Confirm Public IP (critical task).
- Start. Tor's self-test and descriptor upload take about 20 minutes.
| Action | When | Effect |
|---|---|---|
| Configure Node | Any time | Mode, nickname, contact info, bandwidth, monthly limit. Restarts the service. Changing mode switches to that mode's identity. |
| Confirm Public IP | First setup, after an IP change | Checks the input equals the ORPort's single public IPv4, that it is public, and that the user confirmed it is static; stores it. |
| Node Info | Any time | Fingerprint, Tor Metrics link (hashed fingerprint for bridges), bridge line in bridge mode. |
| Import Identity | Service stopped | Installs secret_id_key and ed25519_master_id_secret_key from a base64 .tar.gz into the chosen mode, removing derived keys. Into bridge mode it also restores pt_state/obfs4_state.json when the archive has it, so the bridge line keeps its cert. |
| Export Identity | Any time | Returns the chosen mode's two identity keys as a base64 .tar.gz, plus pt_state/obfs4_state.json in bridge mode. |
- Configure Node — critical, raised until the store is configured; cleared once it is.
- Confirm Public IP — critical,
input-not-matchesagainst the ORPort's current single public IPv4. It re-arms whenever that address changes, is removed, or gains a second address, and StartOS keeps the service stopped while it is open. When the address matches the confirmed one again (for example once the user re-enables it after a restore), init clears the task by its replay ID.
- Node Setup — present only while Tor is held back; its message names what is missing.
- Dashboard — the HTTP port listens.
- Tor — reads the control socket; loading while bootstrapping, success at 100%.
- Reachability — success once Tor's ORPort self-test passed and a directory authority accepted the descriptor; loading for the first 20 minutes, failure after.
The whole main volume is backed up, including both identities and the confirmed IP. StartOS does not restore which addresses were public; once the user re-enables the same public IPv4 on the interfaces, the node starts without re-confirming. Restoring onto a second server while the first still runs puts the same identity online twice; stop one first.
- No exit relay mode, no SOCKS port, no onion services.
- obfs4 is the only pluggable transport.
- The package cannot tell whether an address is static; it relies on the user's confirmation and stops Tor when the address changes.
package_id: 'tor-node'
image: 'Dockerfile (alpine:3.23, tor 0.4.9.14-r0, lyrebird 0.7.0-r6)'
architectures: [x86_64, aarch64]
subcontainers: [tor-sub]
volumes: { main: /data }
file_models: [store.json, torrc]
startos_managed_env_vars: []
dependencies: []
interfaces: { ui: 80, or: 9001, obfs4: 8443 }
actions:
[
configure-node,
confirm-public-ip,
node-info,
import-identity,
export-identity,
]
tasks:
[configure-node (critical), confirm-public-ip (critical, input-not-matches)]
health_checks: [setup, dashboard, tor, reachability]