Browse by type
Obscura VPN library, CLI client, and App
No support is provided for this code directly. However, if you are experiencing issues with your Obscura VPN service please contact support@obscura.net.
At this time we are unable to accept external contributions. This is something that we plan to resolve soon. However until we finish the paperwork we are unable to look at any patches and will close all PRs without looking at them.
Conventions, terminology, and intended behavior are documented in the docs directory. Contributions must align with these documents or change them accordingly.
On macOS the app installs and manages a network extension (system extension). The network extension manages the virtual device and maintains the tunnel using the Rust code as library.
nix-env -iA nixpkgs.{cmake,rustup}bash
nix develop --print-build-logs --command just xcode-openProd Client build schemebash
nix develop --print-build-logs --command just xcode-openPick a build scheme using Xcode's GUI, one of:
ℹ️ INFO: Xcode differentiates between "build schemes" and "build configurations", see Apple's docs on this for more details.
Dev Client: Development Client
General purpose for development. Uses the main UI with additional developer and pre-release features exposed.
Uses the Debug* build configurations. Codesigned with the Apple Development xcode-managed identity.
⚠️ WARNING: When using this build scheme, make sure you are quitting the app via the top-right status menu bar and NOT using Xcode's "Stop" as doing so does not actually stop the dev server. This is because stopping via Xcode doesn't run the build scheme's "Run → Post-actions"
Prod Client: The App with a static web bundle
Useful for reproducing what the final shippable app will look like and be built as.
Uses the Release* build configurations. Codesigned with the Developer ID Application: Sovereign Engineering Inc. (5G943LR562) manually-managed identity.
The static web bundle built with the build scheme's "Build → Pre-actions".
If you encounter trouble with this build scheme, especially with codesigning or provisioning profiles:
Bare Client: The App with a minimal HTML UI
Useful for fine-grain control and debugging.
Uses the Debug* build configurations. Codesigned with the Apple Development xcode-managed identity.
Build or Run the App
⌘ + B (Build), or⌘ + R (Run)💡 TIP: It may initially seem like Xcode is doing nothing when you run or build, but it may just be running the build scheme's "Pre-actions", see the "Report navigator" in Xcode's top-left app menu: "View → Navigators → Reports" to track the actual status.
💡 TIP: If a build fails with could not find included file 'buildversion.xcconfig' in search paths, see the relevant troubleshooting entry.
Xcode places built products in a deeply nested directory structure that it controls, with seperate folders for each build configuration. The easiest way to locate where the app is:
⌘-Click the app icon to reveal it in the finder.💡 TIP: It is highly recommended to read through various sections in Development Tips to better understand the various ways we've configured the Xcode build system to work with our development process.
Nix builds provide an easy way to get a fully built APK. They are hermetic and reliable. However, they provide only coarse grained caching so if you are iterating during development you may prefer to use Incremental Builds.
nix build '.#apks-foss'
apksigner sign --ks your-keystore.jks --ks-pass pass:hunter2 --out=obscura-signed.apk result/app-foss-release-unsigned.apk # Sign.
adb install obscura-signed.apk # Push to your device.
Instead of app-foss-release-unsigned you can also use app-foss-debug for the debug build. Note that just the Android portion is a debug build, the Rust core and UI are still release builds.
The Android app requires a special build of the Rust library and Obscura UI. These are built using Nix, while the Android app itself can be built using Android Studio for local development, or the Gradle build system to create an official build.
bash
OBS_WEB_PLATFORM="android" nix develop '.#web' --print-build-logs -c just web-bundle-buildbash
nix develop '.#android' --command bash -c 'cd rustlib && cargo ndk -t arm64-v8a build --release'android directory, orbash
nix develop '.#android' --command bash -c 'cd android && gradle --no-daemon $GRADLE_OPTS build'In order to iterate you can just repeat the steps. 1 and 2 are only required if you changed the UI or Rust core respectively but the final APK build must always be re-run.
To ensure hermetic builds we pin our Gradle dependencies. If you change the dependencies you will need to regenerate the pin file.
bin/gradle-deps-update.sh
Install Visual Studio with the following Workloads:
wix-msi project)Install Rust.
Install just (winget install Casey.Just)
Install DotNET 10.
Install nvm-windows (winget install nvm-windows) and then run nvm install lts && nvm use lts && corepack enable.
You may also need to install Windows App SDK manually to get the client app running.
Install Powershell 7
Optionally install winapp cli: winget install Microsoft.WinAppCli
On Windows, definitely ARM64 machines, you need to add C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\ARM64\bin to path.
Download the signed wintun 0.14.1 DLLs.
You can use Get-FileHash -Path .\wintun-0.14.1.zip -Algorithm SHA256 to verify the hash against SHA2-256: 07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51.
Extract to windows/wintun-0.14.1 such that windows/wintun-0.14.1/bin/arm64/wintun.dll is a file.
To test the service, if you have sudo enabled (System > Advanced settings), you can run just service. Alternatively, open an admin-enabled terminal and run cargo run --bin obscura service in the rustlib dir.
The default config directory is %APPDATA%\Obscura. When testing the service, you may find it beneficial to manually add in an account number to config.json.
To clean DNS query manually from powershell, run Remove-DnsClientNrptRule -Name "{fb157da8-6578-4f53-81ea-0a9168e96c1f}"
You might need to add a source to dotnet nuget:
windows/obscura-client.dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org.dotnet restore.To run the UI, you have two options
just ui [arch]rustup target add aarch64-pc-windows-msvcrustup target add x86_64-pc-windows-msvcThe Rust service links aws-lc-sys/ring, which compiles C and assembly.
Cross-compiling x64 from a ARM64 host:
NASM + Ninja installed,
pwsh
winget install NASM.NASM Ninja-build.Ninja
Add NASM installation (%LOCALAPPDATA%\bin\NASM) to PATH environment variable.
When building obscura-client.csproj for x64 on ARM64, AWS_LC_SYS_CMAKE_BUILDER=1;CMAKE_GENERATOR=Ninja is automatically set.
Cross-compiling ARM64 on a x64 host has the following requirements:
obscura-client.csproj on x64, AWS_LC_SYS_CMAKE_BUILDER=0 is automatically set, forcing aws-lc-sys's CMake-free cc builder (the CMake builder nests object paths past Windows' MAX_PATH).To override the version (or any other properties) of a build, you can set the OBSCURA_VERSION environment variable in obscura-client/local.props and wix-msi/local.props.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OBSCURA_VERSION>v0.165.2</OBSCURA_VERSION>
</PropertyGroup>
</Project>
GUI logs are written to %LOCALAPPDATA%\Obscura\logs
When service is running as as system service, the config file is written to %SystemRoot%\System32\config\systemprofile\AppData\Local\Obscura
The WinUI 3 Gallery app is very useful at showcasing features currently available with code snippets.
When updating the .NET version, ensure windows-build.yml is updated as well.
Inside Visual Studio,
obscura-client unpackaged should be selected at the top.wix-msi project.Note this requires a self signed certificates to test.
"Swift Testing" tests are placed in *Test.swift files, which need to be a member of the Tests target. Testing (not running) with the Tests scheme builds and executes all tests.
Both app and network extension logs are available via Apple's unified logging system.
There are tools for analyzing logs available as bin/log-*. They accept log files in JSON lines format. This can be found in the app's Debug Bundle or from the Apple log command by specifying --style=ndjson.
The main tool is bin/log-text.py which just turns the logs into a readable text format as well as applying some basic filtering with a few CLI options to apply more filters. Other tools are available, run with --help to get information about what they do.
For more in-depth analysis you are likely best using the tools as a starting point and modifying them as needed or using other tools like jq, sqlite or duckdb. If your analysis is generally useful consider committing it.
This will output logs starting at the point in time when you run this command:
log stream --info --debug --predicate 'process CONTAINS[c] "obscura" || subsystem CONTAINS[c] "obscura"'
[!WARNING] Since Apple may or may not persist logs at the
INFOorDEBUGlevel, logs at these level might be lost. See Apple's developer docs on this for more information.You may be able to set a log configuration to ensure that these logs are persisted, though this has not been tested, please update this
READMEwith instructions if you successfully test this. See Apple's docs on "Customizing Logging Behavior While Debugging" for more information.
log show --last 200 --info --debug --color always --predicate 'process CONTAINS[c] "obscura" || subsystem CONTAINS[c] "obscura"' | less +G -R
defaults read "net.obscura.vpn-client-app"
# delete all defaults including Sparkle related keys (SU*)
defaults delete-all "net.obscura.vpn-client-app"
# delete keys individually
defaults delete "net.obscura.vpn-client-app" <key>
```bas
browse all types & interfaces →
$ claude mcp add obscuravpn-client \
-- python -m otcore.mcp_server <graph>