https://github.com/21-dot-dev/swift-tor
Swift wrapper around the Tor daemon with a concurrency-first client API. Provides SOCKS5 proxy, onion-routing, and Tor control protocol. iOS, macOS, and Linux.
https://github.com/21-dot-dev/swift-tor
anonymity async c-language censorship-resistance daemon hidden-services networking onion-routing privacy proxy socks5 spm swift swift-concurrency swift-library swift-package-manager swift6 tor tor-control tor-network
Last synced: 13 days ago
JSON representation
Swift wrapper around the Tor daemon with a concurrency-first client API. Provides SOCKS5 proxy, onion-routing, and Tor control protocol. iOS, macOS, and Linux.
- Host: GitHub
- URL: https://github.com/21-dot-dev/swift-tor
- Owner: 21-DOT-DEV
- License: mit
- Created: 2026-01-20T23:02:08.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-05-14T18:11:43.000Z (about 1 month ago)
- Last Synced: 2026-05-29T00:27:19.723Z (20 days ago)
- Topics: anonymity, async, c-language, censorship-resistance, daemon, hidden-services, networking, onion-routing, privacy, proxy, socks5, spm, swift, swift-concurrency, swift-library, swift-package-manager, swift6, tor, tor-control, tor-network
- Language: Swift
- Homepage: https://docs.21.dev/documentation/tor/
- Size: 10.9 MB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Security: SECURITY.md
- Agents: .github/AGENTS.md
Awesome Lists containing this project
README
[](https://github.com/21-DOT-DEV/swift-tor/actions/workflows/apple-builds.yml) [](https://github.com/21-DOT-DEV/swift-tor/actions/workflows/docker-builds.yml) [](LICENSE) [](https://swiftpackageindex.com/21-DOT-DEV/swift-tor) [](https://swiftpackageindex.com/21-DOT-DEV/swift-tor)
# swift-tor
Swift package that embeds Tor (`libtor`) and provides a Swift-concurrency-first API (`TorClient`), plus Tor control protocol utilities (including ephemeral onion service management).
## Contents
- [Features](#features)
- [Platforms](#platforms)
- [Installation](#installation)
- [Quick Start (Basic)](#quick-start-basic)
- [Creating a Hidden Service](#creating-a-hidden-service)
- [Demo](#demo)
- [Testing](#testing)
- [Roadmap](#roadmap)
- [Security](#security)
- [Contributing](#contributing)
- [License](#license)
## Features
- **Embedded Tor**: run Tor in-process (via the `libtor` product)
- **High-level API**: `TorClient` actor to start/stop Tor and observe events
- **Control protocol**: `TorControlClient` for `GETINFO`, `SIGNAL`, `ADD_ONION`, `DEL_ONION`, etc.
- **Onion services**: create/delete ephemeral v3 onion services
- **Caching**: optional `cacheDirectory` to reuse consensus/descriptor cache across runs
- **Apple-only networking helper**: `URLSessionConfiguration` + `TorClient.makeURLSession()` (guarded by `canImport(CFNetwork)`)
## Platforms
- **macOS**: 15+
- **iOS**: 18+
- **Linux**: Ubuntu 22.04+ (via Docker)
> [!IMPORTANT]
> **tvOS/watchOS/visionOS are not supported.** Tor's codebase relies on UNIX process primitives (`fork`, `execve`, `daemon`, `setuid`) that Apple prohibits on these platforms. These restrictions are enforced at the App Store review level and would cause runtime crashes.
## Installation
This package uses Swift Package Manager.
### Xcode
1. Go to `File > Add Packages...`
2. Enter the package URL: `https://github.com/21-DOT-DEV/swift-tor`
3. Select the desired version
### Package.swift
Add the dependency:
```swift
.package(url: "https://github.com/21-DOT-DEV/swift-tor", from: "0.1.0"),
```
> [!WARNING]
> This package is pre-1.0 ([SemVer major version zero](https://semver.org/#spec-item-4)). The public API is not stable and may change with any release. Pin a version using `exact:` to avoid unexpected breaking changes.
Then add `Tor` as a dependency:
```swift
.target(
name: "MyApp",
dependencies: [
.product(name: "Tor", package: "swift-tor")
]
)
```
## Quick Start (Basic)
Start Tor, wait for bootstrap, and get a SOCKS endpoint:
```swift
import Tor
let config = TorConfiguration.makeDefault()
let client = TorClient(configuration: config)
try await client.start()
try await client.waitUntilBootstrapped()
let socks = await client.socksEndpoint
```
### Faster bootstraps with `cacheDirectory`
> [!TIP]
> Reusing a `cacheDirectory` across runs can significantly reduce bootstrap time.
```swift
import Tor
import Foundation
let tempDataDir = FileManager.default.temporaryDirectory
.appendingPathComponent("tor-data-\(UUID().uuidString)")
.path
let cacheDir = FileManager.default.temporaryDirectory
.appendingPathComponent("tor-cache")
.path
try? FileManager.default.createDirectory(atPath: cacheDir, withIntermediateDirectories: true)
let config = TorConfiguration(
dataDirectory: tempDataDir,
cacheDirectory: cacheDir,
socksPort: .ephemeral
)
let client = TorClient(configuration: config)
try await client.start()
try await client.waitUntilBootstrapped()
```
### Apple-only: URLSession via Tor
> [!NOTE]
> This helper requires `CFNetwork` and is only available on Apple platforms.
```swift
#if canImport(CFNetwork)
let session = try await client.makeURLSession()
let (data, _) = try await session.data(from: URL(string: "https://check.torproject.org/api/ip")!)
#endif
```
## Creating a Hidden Service
Create an ephemeral v3 onion service that forwards traffic to a local server:
```swift
import Tor
// Start Tor first
let client = TorClient(configuration: .makeDefault())
try await client.start()
try await client.waitUntilBootstrapped()
// Get the control client
let control = try await client.control()
// Create an ephemeral onion service
// - Maps port 80 on the .onion to localhost:8080
// - Private key is discarded (service won't survive restart)
let service = try await control.addOnion(
key: .newV3(discardPrivateKey: true),
ports: [.toLocalPort(80, localPort: 8080)]
)
print("🧅 Hidden service running at: \(service.onionAddress)")
// e.g., "duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion"
// Your local HTTP server on port 8080 is now accessible via Tor!
// Users can reach it at: http://.onion/
// When done, clean up
try await control.delOnion(service)
await client.stop()
```
### Persistent Hidden Services
To create a hidden service that survives restarts, keep the private key:
```swift
// Create service and get the private key
let service = try await control.addOnion(
key: .newV3(discardPrivateKey: false), // Keep the key
ports: [.toLocalPort(443, localPort: 8443)]
)
// Save service.privateKey securely for later use
let privateKey = service.privateKey! // e.g., "ED25519-V3:base64..."
// Later, recreate the same .onion address:
let restoredService = try await control.addOnion(
key: .providedV3(privateKey),
ports: [.toLocalPort(443, localPort: 8443)]
)
// restoredService.onionAddress == service.onionAddress
```
> [!WARNING]
> Store private keys securely (e.g., Keychain on Apple platforms). Anyone with the private key controls the .onion address.
## Demo
Run the bundled demo:
```bash
swift run TorDemo
```
The demo starts Tor, fetches a clearnet URL via Tor, fetches an `.onion`, and creates/deletes an ephemeral onion service.
## Testing
Run unit tests:
```bash
swift test
```
Integration tests are **env-gated** and skipped by default:
```bash
TOR_INTEGRATION_TESTS=1 swift test --filter IntegrationTests
```
## Roadmap
- **Linux support**: ✅ complete (Phase 1)
- **Remove libbsd dependency**: ✅ complete (Phase 2)
- **iOS Target Refactor**: 🔜 planned (Phase 3)
- **Binary Size Optimization**: 🔜 planned (Phase 3.5)
See [roadmap.md](.specify/memory/roadmap.md) for full details.
## Security
For information on reporting security vulnerabilities in swift-tor, see [SECURITY.md](SECURITY.md). For other 21-DOT-DEV projects, see the [organization Security Policy](https://github.com/21-DOT-DEV/.github/blob/main/SECURITY.md).
> [!CAUTION]
> Tor can't "fix" unsafe application behavior. Review the [Tor Project guidance](https://support.torproject.org/) on staying anonymous. Avoid logging sensitive information (credentials, onion private keys). Consider your threat model — Tor integration is only one part of privacy/security.
## Contributing
Contributions welcome! Please read the [21-DOT-DEV contributing guidelines](https://github.com/21-DOT-DEV/.github/blob/main/CONTRIBUTING.md) for general workflow. For swift-tor specific guidance and AI-assisted development, see [AGENTS.md](AGENTS.md).
## License
This project is licensed under the MIT License. See `LICENSE`.
Tor source code is vendored in `Vendor/tor` and is subject to its own license(s). See `Vendor/tor/LICENSE`.