The Linux app, in depth
This is the deep dive: every major surface of the Linux app, what it controls, its defaults, and how to fix it when something breaks. It assumes you have already installed and connected. If not, start with getting started. For how the network behind the app works, read the overview.
The Linux client is a GTK4/libadwaita desktop app over a root systemd daemon, shipped as an AppImage plus a .deb. All of it is open source at github.com/urnetwork/linux.
Settings at a glance
The defaults protect you without configuration. The connection controls live in the connect drawer; provide mode sits in the home controls; the device-location override sits above the connected-providers globe.
| Setting | Default | Effect | Main cost |
|---|---|---|---|
| Connection mode | Auto | picks the provider windows; Auto runs quality and speed together | Web or Streaming narrow to one window |
| Strong Anonymization | On | hides your source IP from the provider | more latency |
| Post Quantum Encryption | On | encrypts from the app to the provider | skips a provider it cannot seal to |
| Kill switch | Off | stops local fallback when the tunnel is down | no traffic while providers fail |
| Fixed IP | Off | one provider, one exit address | no failover |
| Block ads and trackers | Off | filters ad and tracker traffic | filtering can break some sites |
| Custom DNS | encrypted DoH via the tunnel | DNS stays encrypted and inside the tunnel | loosening it is the trade |
| Provide mode | Never | shares spare bandwidth as an exit for others | strangers' traffic egresses from your IP |
| Device location override | Off | apps that ask GeoClue see your longest-held provider's city | needs GeoClue 2.7+; affects every app on the machine |
| Split rules (domain/IP) | empty | listed destinations use your local connection | that traffic is unprotected |
Caveats that go with the table:
- Turning Strong Anonymization off is direct mode: the client talks straight to the provider and gets faster, and that provider then sees your real address. The default protects your identity. Spend it deliberately.
- The kill switch also decides what happens to a packet the security filter drops (see provide mode): on, it is blocked outright; off, it leaves by your normal route.
- Per-app split tunneling is not available on Linux. The split rules are domain- and IP-level.
- Deleting your account is not on Linux either. Do that in the web app, which manages the same account.
The daemon split
Two programs, two privilege levels:
urnetworkdis a root daemon managed byurnetworkd.service, with no GUI dependencies at all. It embeds the SDK'sDeviceLocal, opens and owns/dev/net/tun, pumps packets through the SDK's IO loop, and applies routes and DNS. The.debor the install tarball installs it.urnetworkis the desktop app, gtkmm-4.0 and libadwaita, running as your normal user and shipped as an AppImage. It holds aDeviceRemote: a view of the daemon's device, not a device of its own.
They talk over two channels:
- Device RPC. The app's
DeviceRemotedrives the daemon'sDeviceLocalover the SDK's mutually authenticated TLS RPC on loopback,127.0.0.1:12025, the same transport the Windows app uses. - The control socket. A unix-domain socket at
/run/urnetwork/control.sockcarries tunnel lifecycle: bring the tunnel up, tear it down, set provide mode, report daemon state.
The unix socket is the real authorization boundary. Loopback TCP is reachable by any local process, which is why the device RPC is mutually authenticated with certificates. But nothing starts a tunnel without passing the unix socket, where the kernel itself tells the daemon which user is asking (SO_PEERCRED, checked before a single byte of the request is parsed, and authorizing on user id, never process id). The directory is 0750 root:urnetwork, the socket 0660, and the rule is: root, or a member of the urnetwork group.
Moving the device RPC onto a unix transport too is a recorded follow-up in the SDK; the design notes state the loopback limitation instead of treating loopback as private.
The two halves must match
Linux is the first URnetwork platform where the app and the tunnel update independently: the AppImage self-updates as you, the daemon updates through apt. So the app checks two things on connect: the control protocol version, and that both halves carry the exact same SDK build. A mismatch is refused up front with a distinct message (service not running, service out of date, app out of date, builds differ) because each has a different fix, and a silently half-working tunnel is worse than an error.
How the pieces install
Both halves come from the release page: .deb, .install.tar.gz and .AppImage, amd64 and arm64, with a glibc 2.35 floor that means Ubuntu 22.04 or Debian 12 and newer. There is no store listing.
The package owns everything privileged and stable: the daemon at /usr/lib/urnetwork/urnetworkd, its systemd unit, the desktop entry, icons, the world map data the globe draws from, translations, and a launcher at /usr/bin/urnetwork.
The GUI AppImage is never installed by the package. It lives in your home directory (~/.local/lib/urnetwork/URnetwork.AppImage), user-writable so it can replace itself without root. The launcher searches a fixed list of locations ($URNETWORK_APPIMAGE, then ~/.local/lib/urnetwork/, then ~/Applications/, then /usr/lib/urnetwork/, then any urnetwork-gui on $PATH) and runs the first hit; with none installed it prints a one-line hint telling you where to get one.
The daemon runs with the privilege it needs and gives up what it does not: NoNewPrivileges, ProtectHome (it is headless and must never read user home directories), PrivateTmp, root-only state and log directories. It is ordered against network-pre.target, the slot a VPN needs so it can act before the network comes up, and it is always-running rather than socket-activated, because a lazily started unit cannot participate in that ordering at all.
Routes
When the tunnel comes up, the daemon does not replace your default route. It outbids it, the way wg-quick does:
- It adds routes through the tunnel interface (
urnet0) covering the whole IPv4 space except the private LAN ranges: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. - Those are more specific than your existing
0.0.0.0/0default, so they win without touching it. Teardown is just removing them; your original routing is never modified. - Excluding the private ranges keeps your printer, NAS, and local services working while you are connected, the same behavior as the Android, Apple, and Windows clients.
NetworkManager is told to keep its hands off: urnet0 is marked unmanaged via a NetworkManager config drop-in and a udev rule, so the desktop's network manager never fights the daemon over the interface.
DNS
DNS on the tunnel link is set through systemd-resolved (resolvectl), the standard resolver on Ubuntu desktops: the link's resolvers are pointed at the network's, with ~. so queries route through it, and everything is reverted on teardown. Not every system runs resolved, so the behavior is best-effort by design:
- With systemd-resolved: DNS for the tunnel link is captured and restored.
- Without it: the tunnel still routes, but DNS on that link is not captured. Your queries keep using whatever resolver the system had.
One more subtlety: a DHCP-supplied search domain (lan, home) is a longer match than ~. and will beat it for names in that domain. If you run an unusual resolver setup, check where your DNS actually goes.
The app's own Custom DNS sheet is the more meaningful control. It edits the SDK's resolver settings, whose default is encrypted DNS over HTTPS resolved through the tunnel. It offers DoH and unencrypted resolution, remote or local, editable server lists per family, a local-DNS fallback switch that races a local resolver while the tunnel starts so lookups do not stall, regional recommendations for places where the strictest configuration is known to break, and one action to restore the secure defaults.
The tray
The status icon is a StatusNotifierItem with a com.canonical.dbusmenu menu, spoken directly over GDBus: the protocol KDE and most panels support natively, and GNOME supports through the AppIndicator extension. With no tray host present, the app shows no icon rather than failing.
Closing the window hides to the tray and keeps the tunnel running. The menu carries connect/disconnect, show, and quit. Quit is the real exit here: it ends the session and brings the tunnel down. Day to day you want the close button, not quit.
The window
Sign-in first, then the home view: the connect control, the provider globe, and the drawer. Sign-in takes an email or phone code, Create account, an auth code generated on a device you are already signed in on, or a wallet signature through Solana (Phantom, Solflare) or Bittensor. A legacy Try Guest Mode button also sits there. It mints an ordinary permanent account on the server, but this app throws away the recovery seedphrase that comes back with it, so use one of the other paths if you want to be able to recover the account later.
The provider globe is drawn from a world topology bundled with the app. No map tiles are fetched, so nothing about the map you are looking at leaves your machine.
The connect drawer carries the session:
- The connection controls card. The selected location, a connection mode of Auto, Web, or Streaming, and four switches: Fixed IP, Strong Anonymization, Post Quantum Encryption, and the kill switch. The mode picks which provider window runs: Web is the quality window (2–6 providers at once), Streaming the speed window (1–2), and Auto runs both side by side, which is why an ordinary session commonly has 3–8 providers open, not one. Strong Anonymization is what forbids a direct client-to-provider path, so no provider ever sees your real address; switching it off is the direct-mode trade from the table above. Post Quantum Encryption seals the session itself (see the identity panel below).
- Client and local statistics cards with live charts, each opening a detail sheet.
- Custom DNS status, opening the resolver editor above.
- Block ads and trackers.
- Plan and usage. Your tier, the used/pending/available bar, the daily allowance and referral rows, Get UR Pro, and redeeming a balance code.
- The post-quantum identity panel (below).
Sheets, each a real screen rather than a stub:
- Locations. The SDK's bucketed sections: your connected network peers first, then best-available, then countries with live provider counts. Typing in the search box adds top matches plus regions, cities and devices. A city is something you search for here, not something you scroll to.
- Connected providers. A globe over one row per provider currently in your window, oldest connection first, with client id, city/region/country, coordinates, duration, and an inline remove.
- Contracts. The live transfer contracts behind your session, one stack per peer, send and receive kept separate.
- Split rules. Domain- and IP-level rules that force specific traffic to your local connection, over a live feed of what is being acted on.
- Redeem code. Apply a balance code, with the history of ones you have redeemed.
- Upgrade. UR Pro monthly or yearly through Stripe checkout, embedded in the app where the system has WebKitGTK, and falling back to your browser otherwise, because a payment path must never hard-fail.
There is no separate Account, Wallet, or Leaderboard screen on Linux today. Plan and balance live in the drawer and the redeem sheet, and account settings live in the web app at ur.io. Sign out is in the home view.
The device-location override
Linux gets a real version of what Android calls "sync device location": apps that ask the system where you are can be told the coordinates of the provider you have been connected to the longest, instead of your actual location. The toggle sits above the connected-providers globe, with a setup guide, and it is off until you turn it on.
The mechanism is narrow. GeoClue, the service desktop apps ask for location, has a static source that reads a fixed position from /etc/geolocation and watches the file for changes. That file is the only injection point and it lives under /etc, so the write is done by the daemon over the same control channel; the GUI never touches it and never needs root.
The guide states its limits directly. It needs GeoClue 2.7.0 or newer, which is not on every system; Ubuntu 22.04 and Debian 12 ship an older version and can never satisfy it. And it moves only what GeoClue reports: GNOME Settings and Maps, Firefox, and sandboxed Flatpak and Snap apps follow it. Chrome and KDE Plasma never ask GeoClue at all, anything that works your location out from your IP address is untouched, and Firefox falls back to its own lookup if the system answers slowly. It also changes the location reported to every app on the machine, not just URnetwork. Everything else in the app works regardless.
Provide mode
Providing is off by default, and the home controls offer Auto, Always, Network (your own account's devices only), or Never. Providers participate in the UR protocol; ur.xyz documents how rewards work.
What protects you when you share is the connect engine's open-source ip_security layer. It runs deep packet inspection on your own egress and drops DMCA-class traffic (stateful BitTorrent and file-sharing signatures, opaque-protocol drops) and CFAA-class traffic (attack and intrusion patterns) before it leaves your machine. The same filter also runs on your own send path as an ordinary user, whether or not you ever turn providing on, so your traffic is judged on your machine before it reaches any provider.
On a match the packet is dropped, with no destination, domain or contents recorded. A BitTorrent signature on traffic you carry for someone else additionally raises an abuse flag to the operator holding only the sending device's id and a boolean, and the operator ships no handler for it today. An opaque-encrypted flow is a plain drop that reports nothing at all. Sealing does not bypass the filter, because it runs where traffic exits. And the kill switch decides the fate of a dropped-class packet from your own machine: off, it goes out your local connection; on, it stops.
The post-quantum identity panel
The drawer shows this device's session identity: an identicon, the canonical key hash and client id (click to copy), a deck of the provider identities you have established verified sessions with, the full provider-identities list, and a share dialog for comparing your fingerprint out of band.
What the setting does: Post Quantum Encryption ships on, and while it is on your client seals traffic end to end to the provider over a session negotiated with X25519MLKEM768 (hybrid classical plus ML-KEM). That sealed leg is what makes the middle hop blind: the operator carries bytes it cannot read. It is fail-closed. While the setting is on the client will not send or accept application data in the clear, so a provider it cannot establish that session with is skipped rather than used unsealed: the cost is a lost provider, not lost encryption, and you cannot be silently downgraded. Every current provider build enables the responder side, so the skip is rare. Switch the setting off and traffic can take the standard TLS-to-platform path again. Identity signatures remain Ed25519 and the cipher is AES-256-GCM. "Post-quantum" means this key exchange, nothing broader.
What the network is doing underneath
Your traffic takes four legs: you → extender → operator → provider → internet. The extender is a reachability hop that forwards your encrypted session without reading it; as your first hop, it does see your address. The overview explains the full path, why it stops at four legs, and the provider windows.
What matters for this app's controls is the split across the two relay parties. The provider never learns who you are, because the operator sits in between. The operator cannot read what you send, because Post Quantum Encryption seals the session end to end to the provider by default. Both hold on a stock install, so no single party holds both your identity and your activity. The three states the two switches produce:
| Mode | Operator sees | Provider sees | Default and availability |
|---|---|---|---|
| Relayed sealed | your account and source connection, which providers you are on, and ciphertext with its timing and volume | destinations it egresses and a device/contract id, not your real IP | the shipped default: Post Quantum Encryption, on in the connect drawer |
| Relayed standard | your account and source connection, which providers you are on, and the destinations and packet bytes inside | destinations it egresses and a device/contract id, not your real IP | only with Post Quantum Encryption switched off |
| Direct | less relay involvement | your real IP and the destinations it egresses | opt-in: switch off Strong Anonymization |
The threat model works these rows against named adversaries and is explicit about where each one fails.
On the operator's side there is little to keep: connection records hold a keyed one-way hash (scrambled with one secret key) of your IP block rather than the address, the contract ledger holds client ids and byte counts with no destination, host, URL or domain anywhere, and the data path logs nothing. A geographic lookup does record an approximate city per connection; what you reach through it is not recorded at all. No independent audit covers the protocol or the operator's server code (the two 2025 third-party assessments cover other surfaces: a penetration test of the web application and API, and a passed Leviathan MASA AL2 assessment of the Android app, not the Linux client). The checks that exist instead are the open source itself, continuously checkable by anyone, and the exit design: egress is a decentralized fleet of separately operated providers rather than one custodian holding everything. Limit: how independent that fleet really is has never been measured, and nothing stops the operator running providers of its own (threat model §6.1).
Limits
- The kill switch ships off. It is a real toggle in the connect drawer, but until you turn it on, traffic falls back to your normal connection whenever no provider is up instead of stopping. The drawer applies it live over the device RPC and the daemon restores your choice at the next start.
- IPv4 only through the tunnel. IPv6 is not routed through it, so on an IPv6-enabled network a v6-capable site can still see your real address. Disable IPv6 on the connection if you need everything to exit through a provider.
- No per-app split tunneling. Rules are domain- and IP-level.
- No Google or Apple sign-in.
- DNS capture depends on systemd-resolved, as described above.
Troubleshooting
"The URnetwork system service is not running"
Check the daemon and its socket:
systemctl status urnetworkd
journalctl -u urnetworkd -fThe daemon narrates what it configures and what it restores, so this is the first place to look for tunnel bring-up, route, and DNS problems. GUI logs stay in your user session, separate from the privileged half, which is the point of the split.
If the daemon is running and the app still cannot reach it, you are probably not in the urnetwork group: id -nG will tell you. Add yourself with sudo usermod -aG urnetwork "$USER" and log out and back in.
"The service is out of date" / "different builds"
Update both halves to the same release: the daemon by installing the newer .deb (or by re-running install.sh from the newer tarball), and the AppImage in ~/.local/lib/urnetwork/. The check exists so a half-upgraded install says so instead of misbehaving quietly.
The AppImage won't start
Ubuntu 22.04+ does not ship libfuse2 by default and AppImages need it. The .deb declares that dependency, so installing the daemon package usually resolves it; otherwise install libfuse2 (or libfuse2t64 on newer releases). Also check the file is executable.
No tray icon
Your desktop has no StatusNotifierItem host. On GNOME, install the AppIndicator extension; KDE and most panels support it natively. The app works fine without one: closing the window just hides it, and you reopen from the app menu.
urnetwork:// links do nothing
Wallet sign-in returns through a urnetwork:// link, which needs the desktop database refreshed after install. Run update-desktop-database ~/.local/share/applications (or the system path with sudo). The packaged install triggers this for you; a manual install may not have.
The interface exists but nothing routes
Check that NetworkManager is not managing urnet0. The package ships a config drop-in and a udev rule marking it unmanaged, and both need a reload (nmcli general reload conf, udevadm control --reload), which the installer does.
Elsewhere
The overview explains the network end to end: providers, contracts, what each party can and cannot see, and the encryption. The FAQ answers the common questions. Other platforms: Android, iOS, macOS, Windows, and the browser.