Firezone
firezone.devOpen-source self-hosted VPN and firewall built on WireGuard®.
- Homepage:firezone.dev
- GitHub:github.com/firezone/firezone
- Web info:web-check.xyz/check/firezone.dev
Firezone Source Code
Author
Description
Enterprise-ready zero-trust access platform built on WireGuard®.
Homepage
https://www.firezone.devRepository
- LicenseApache-2.0
- Created22 Apr 20
- Primary languageElixir
- Size344,099 KB
- Stars9,048
- Forks450
- Watchers9,048
Top Contributors
@jamilbk (4550)
@thomaseizinger (2413)
@dependabot[bot] (2311)
@AndrewDryga (632)
@ReactorScram (479)
@bmanifold (216)
@conectado (206)
@klochowicz (129)
@firezone-bot (102)
@princemaple (49)
@roop (33)
@Copilot (24)
@Patticatti (21)
@jasonboukheir (20)
@pratikvelani (16)
@gongjason (14)
@francesca64 (11)
@Intuinewin (9)
@mdp (6)
@DoctorFTB (6)
@gbe0 (5)
@chetanverma16 (2)
@thermionic (2)
@toreanderson (2)
@tyrann0us (1)
@numberjs (1)
@sebastianbuechler (1)
@shantanugadgil (1)
@hieultan (1)
@leriel (1)
@lilibobear (1)
@oddlama (1)
@pemontto (1)
@seer-by-sentry[bot] (1)
@wwuck (1)
@yenba (1)
@RamboRogers (1)
@salemgolemugoo (1)
@kianmeng (1)
@jefferenced (1)
@jameswinegar (1)
@muroed (1)
@ssaunderss (1)
@akrousset (1)
@marbindrakon (1)
@aljaxus (1)
@adrianbaena (1)
@mostafahussein (1)
Recent Commits
Thomas Eizinger(03 Sept 26)
fix(apple): space the iOS permission screens by a fixed gap (#15037) The iOS grant screens put a spacer between every element, which splits the free height into equal gaps. On an iPad that leaves the logo, the text, the icon and the button hundreds of points apart, with the small icon floating alone in the middle. The elements now sit as one centred group with the same gap on every screen, as the macOS screen already does. Related: #15036 --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Firezone Bot <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(ci): upload only each runner's own screenshots (#15038) A screenshot runner uploaded its whole gallery directory, which also holds the other runner's images as committed. The commit job downloads both artifacts into the same directory, so the second one overwrote the first one's fresh captures with the stale committed ones: the iPad artifact put back the iPhone renders, and the macOS 15 artifact put back the macOS 26 ones. Each runner now uploads only the images it drew. Related: #15037 --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Firezone Bot <[email protected]>
Thomas Eizinger(03 Sept 26)
ci(apple): photograph the iOS screens on an iPad too (#15036) The iOS screenshot job built the app, its extension and connlib, then photographed one simulator. The build now runs once and hands its products to a job per simulator, so an iPad joins the gallery without lengthening the run. The captures carry the device family in their name (`-iphone`, `-ipad`) to tell the two apart, the same way the macOS images carry their release. --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Firezone Bot <[email protected]>
Firezone Bot(03 Sept 26)
chore(fuzz): grow the x509-claims corpus (#15035) The nightly fuzz job discovered new coverage for `x509-claims` and refreshed its uncovered-region ceiling.
Firezone Bot(03 Sept 26)
chore(fuzz): grow the relay-proto corpus (#15034) The nightly fuzz job discovered new coverage for `relay-proto` and refreshed its uncovered-region ceiling.
Thomas Eizinger(03 Sept 26)
fix: log disk-full flow-log spool failures on debug (#15033) A full disk is an operator problem the flow-log spool cannot fix, yet every flow start and end tried to spool a report while the disk stayed full and logged the failure on `WARN`. Because the message embeds a unique file path, Sentry turned each one into a new issue across the GUI, Apple and Gateway projects. Those failures are now logged on `DEBUG` and the writer carries on as before. Detecting the error kind was not possible with `atomicwrites`: its error type only implements the deprecated `cause`, so `anyhow` chains never reach the underlying `io::Error`. What we need from that crate is small (a temp file in the target directory, fsync, rename into place), and `tempfile` already provides the temp file and the cross-platform rename. The new in-tree `atomicfs` crate builds on that and exposes a single `write` function mirroring `std::fs::write` that returns a plain `io::Result`. All three former `atomicwrites` call sites use it and the dependency is removed from the workspace. Files are created owner-only, which the flow-log spool wanted anyway, so its own permission fixup goes away. The device ID file is now overwritten if it exists but failed to parse, instead of erroring out. --------- Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(connlib): enable recv options before binding UDP sockets (#15028) Darwin decides at enqueue time whether a datagram gets its `IP_RECVDSTADDR` / `IPV6_PKTINFO` control message. We only enabled those options via `quinn_udp::UdpSocketState::new` after `bind` (catch-all socket) or after `bind` + `connect` (Apple flow sockets). A flow socket is connected precisely because its 4-tuple is busy, and a rebind reuses the listen port, so datagrams routinely land in that window. They come back without a local IP and are dropped with "Skipping packet without local IP". Construct the `UdpSocketState` before binding so the options are already on when the first datagram can arrive. On Windows, `quinn-udp` used `getsockname` to learn the address family, which fails on an unbound socket; the bumped `quinn-udp` reads it from `SO_PROTOCOL_INFOW` instead so the same order works there too. --------- Co-authored-by: Claude <[email protected]>
Firezone Bot(03 Sept 26)
fix(nix): bump gui-client pnpm-deps hash (#15018) rust/gui-client/pnpm-lock.yaml changed; refreshing the fetchPnpmDeps pin so local Nix builds match CI.
Thomas Eizinger(03 Sept 26)
fix(gui-client): accept `auth_base_url` in legacy settings (#15031) Installs from before the "General" settings split store the auth URL as `auth_base_url` in `advanced_settings.json`. The old in-GUI migration only rewrote that file when no general settings existed yet, so many installs still carry the old key. The service migration parses the file strictly as `AdvancedSettings`, which requires `auth_url`, so it fails on every start and the user's settings never reach the Tunnel service. Accept both spellings when reading the legacy file. Related: #13332 --------- Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
chore(x509): drop the tunnel hint from the Windows tasks (#15032) The Windows install and uninstall tasks still closed by naming the Tunnel service's `x509` subcommand. They provision the store for every client, so the pointer goes, as it already did from the Linux tasks. Related: #14972 Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(x509): uninstall only certificates from the test CA (#15022) The uninstall tasks matched on the common name `dev.firezone.device-trust`, which a real deployment's certificates carry too, so on a machine that also holds an MDM-issued certificate they would have deleted it, private key included. They now decide by the test CA instead: a certificate is removed only when it chains cryptographically to the CA in `~/.cache/firezone/x509/ca.crt`, checked against the CA's key rather than its name, and anything else under that common name is left alone and listed. On Linux that means removing the matching objects from the token rather than the whole token, which goes, with its PIN file, only once nothing remains on it. Without a `ca.crt` the tasks cannot tell the test certificates apart, since the certificate may have been issued on another machine, so on a terminal they print each candidate with its issuer, fingerprint and expiry and ask per certificate, and without a terminal they refuse rather than guess. The Linux task also treated a machine that never ran the install task as a failure: `softhsm2-util` reports a missing token as "Could not find a token", which the message match did not cover. Related: #14991 Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
feat(snownet): buffer candidates for unknown connections (#15030) A connection and its remote candidates are signalled independently through the portal, so a peer's candidates can arrive before the message that creates the connection locally. Today we drop them with a warning and rely on later candidates (or optimistic ones) to still establish the connection. This holds candidates for unknown connections for a short while and replays them once the connection is created, so the early ones are not lost. The simulator now delivers the gateway's candidates to the client before the client learns about the connection, mirroring that ordering. Co-authored-by: Claude <[email protected]>
Jamil(03 Sept 26)
feat(portal): realtime Entra directory sync via Graph webhooks (#15024) Entra directory sync used to learn about changes only when the full sync ran every 2 hours. It now subscribes to Microsoft Graph change notifications for users and groups, so membership changes, disabled or deleted users, renamed users and groups, and deleted groups are applied within moments of happening in Entra. The full sync now runs once a day as a safety net, and the first sync runs right after a directory is created. How it works: - Each directory gets two Graph subscriptions, one for `/users` and one for `/groups`. They are created after the first successful sync, renewed daily by the same job, and deleted when the directory is disabled or removed. - Graph posts notifications to `/integrations/entra/webhooks`. The endpoint checks the per-directory `clientState` secret, drops anything about users or groups this directory does not track, and queues one job per changed object. - The job re-reads the object from Graph and writes it with a fresh `synced_at`. Because the full sync stamps everything with its start time, a webhook write always wins over an older full-sync read of the same row, so an in-flight full sync cannot undo or delete it. - Users are only updated when they already have an identity in the directory, and groups only when the directory already tracks them (or syncs all groups). New app role assignments have no Graph subscription, so in assigned-groups mode they still wait for the daily sync or Sync Now. Related: firezone/website#543
Thomas Eizinger(03 Sept 26)
fix(x509): sign TLS handshakes with SHA-256 only (#15029) Firezone clients advertise the TLS signature schemes their device certificate's key can sign with, and the RSA lists led with SHA-512. A TPM-held RSA key is not obliged to do that: the TCG PC Client Platform TPM Profile mandates SHA-256 for RSASSA and RSAPSS in every revision, leaves SHA-512 optional, and only made SHA-384 mandatory in its 2020 revisions. A firmware TPM refused the very first request with `NTE_NOT_SUPPORTED` and the handshake died there, even though the same key signs PSS and PKCS#1 with SHA-256 without complaint. Every platform now offers `rsa_pss_rsae_sha256` followed by `rsa_pkcs1_sha256` and nothing else. That loses nothing against a conforming server: RFC 8446 makes `rsa_pss_rsae_sha256` mandatory to implement, TLS 1.2 servers accept `rsa_pkcs1_sha256`, and the portal offers both. ECDSA keys are unaffected, since TLS pairs each curve with its own digest. Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(snownet): drop ufrag mapping of failed connections (#15027) `Connections::handle_timeout` removes failed connections from `established` and records them in the `disconnected_*` maps, but leaves their entry in `established_by_local_ufrag`. That entry is only cleaned up in `remove_established`, so every ICE-failed connection leaks its ufrag mapping for the lifetime of the node. Late STUN binding requests for such a ufrag also resolve to an id that no longer exists, so they are reported as "No connection for id" instead of "No connection for ufrag" and lose the recent-disconnect hint. Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(clients): keep error details out of the disconnect alert (#15025) When connlib disconnects, the error reached the user with its whole cause chain attached, keystore internals and OS error codes included: a Windows signing failure read "This device could not sign in with its certificate: the keystore failed to sign: The requested operation is not supported. (0x80090029)" in the alert. The error now answers two questions separately. `user_message()` is the sentence a person can act on: `phoenix_channel::Error` is the one type worded for a user, so it is that type's `Display` when the chain carries one and a generic sentence otherwise. `log_message()` is the full chain. Diagnostics move out of the variant text into `#[source]` fields, so `Display` stays user copy while `{:#}` still renders everything for the log; the portal's own wording in `AuthenticationFailed` and `CertificateRejected` stays where it is, since the portal writes those for the user. The FFI error exposes only the two accessors, so every Swift and Kotlin call site had to choose, and the GUI's IPC disconnect message carries both strings: the dialog and the notifications show the user message, the logs on every platform keep the chain. --------- Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
ci(apple): restore the newest Xcode build for Swift changes (#15019) The screenshot jobs run because `swift/apple` changed, and the cache key hashes every file under it, so a Swift pull request never hits: the case the cache exists for always builds cold. A fallback on the platform prefix restores the newest `main` build instead. A pull request that edits one view then compiles 31 of 205 Swift tasks on macOS and 24 of 137 on iOS, against 27 and 20 for an exact hit. The fallback is only safe if Xcode can tell an edited file from an untouched one, and under a constant date it cannot: with the constant date and a fallback, an edited view kept the date its predecessor had been built under, was not recompiled, and the run photographed the predecessor. Dating each file by a hash of its content gives an unchanged file the date the cached build recorded and a changed file a different one, which is all Xcode compares; edited files that hashed to earlier dates were recompiled just the same. The package checkouts travel with the products again. Without them Xcode clones the packages afresh, every package target rebuilds and `FirezoneKit` with them, so an exact hit still ran 196 of 205 tasks. The measurement that found them independent had read a job log truncated at the front, which is where those compiles are. Related: #14984 --------- Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(apple): isolate tunnel IPC on main actor (#15020) Provider-message handling enters through `@MainActor` APIs, but the private async helpers were nonisolated and could run on the generic executor. This allowed concurrent mutation of the mock message array, causing the intermittent `SIGSEGV` in the [Swift coverage job](https://github.com/firezone/firezone/actions/runs/33599103333/job/100148640023). Keep the helper functions and `MockTunnelSession` isolated to the main actor, removing the mock’s unchecked `Sendable` conformance and making its existing isolation assumption explicit.
Thomas Eizinger(03 Sept 26)
fix(android): await the screens in the auth flow e2e test (#15017) `AuthFlowE2eTest` launches `AuthActivity` through the application context and asserts the handoff to `MainActivity` right away. Espresso's `intended` only drains the main looper before it checks, so when the launch is still queued in `system_server`, nothing has been recorded yet and the assertion fails. The activity then goes on to open the auth tab while the next test is already recording, which makes that test see two auth-tab intents. Both tests also end with the handoff to `MainActivity` still in flight, so the splash screen starts `SessionActivity` after the Hilt component has been torn down and the process crashes, hiding the results of every test class after it. Wait for the screen a step lands on before asserting how it got there, and end each test on the session screen so nothing is left in flight. Related: #14888 Co-authored-by: Claude <[email protected]>
Jamil(03 Sept 26)
fix(apple): repair managed VPN profiles missing the extension id (#15010) Some MDMs, for example Intune's built-in VPN payload, cannot set `ProviderBundleIdentifier` on the VPN profile they push. The macOS client found such a profile, logged a warning, and then tried to start the tunnel from it anyway. macOS could not find the provider for the profile and showed "The VPN app used by the VPN configuration is not installed" at every launch. The client now writes its own extension identifier into the managed profile and saves it, then starts the tunnel as usual. Everything else in the profile, including the client certificate reference, stays as the administrator wrote it. Fixes: #15009 Related: #14742 --------- Co-authored-by: Claude <[email protected]>
Thomas Eizinger(03 Sept 26)
fix(apple): lay the grant screen's steps out as a grid (#15015) On macOS 15 the welcome window that asks for the system extension and the VPN configuration opens taller than the screen, with nothing in view. The step columns kept a spacer between their text and their button, and once the row holding them was fixed to its ideal height so that the buttons would line up, macOS 15 sized that spacer as unbounded and grew the window to fit it. macOS 26 sizes the same spacer as zero, which is why the committed pictures never showed it. A grid gives the buttons a row of their own, so they sit under the steps whichever column runs longer, and nothing in the screen asks for more height than its content. SwiftUI lays a window out with the macOS release it runs on rather than the SDK it was built with, so the macOS screenshot job now runs on both releases, and every macOS capture carries the release that drew it in its name. Fixes: #15008 --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Firezone Bot <[email protected]>
Jamil(03 Sept 26)
refactor(portal): track one presence for every device (#14909) Clients and gateways were tracked apart, on `presences:account_clients:` and `presences:account_gateways:`. Their metadata had drifted into two shapes: a gateway carried what a connection needs to pick it, a client carried the tunnel addresses and keys a device pool needs to reach it, and neither carried the other's. They are one tracker now, on `presences:account_devices:`, with one meta built in one place from the device row. Both kinds carry the same keys, `nil` where a kind has no answer, so a reader that does not care which kind it is holding does not have to know. The two channels no longer assemble their own meta. The per-actor and per-site trackers are gone too. The account meta now carries the actor id and the token id, so every page and worker that asked `presences:actor_clients:` or `presences:sites:` now filters the account list instead. The Actors and Service Accounts pages subscribe to the account topic once at mount and refresh their token list only when a diff carries a device of the selected actor. The relay topic is renamed from `presences:global_relays` to `presences:relays`. Draft, because two things want a second opinion before this is merged. Every subscriber to the account topic now wakes on every connect in the account, so the Actors, Service Accounts, Sites, and Resources pages see joins they do not care about. And the topic names change, so during a deploy the two versions track to different topics and each sees only its own half until the older one is gone. Related: #14899 Related: #14907
Jamil(02 Sept 26)
fix(gui-client): bump @humanfs/node (#15005) ## Summary - pin the gui client's transitive `@humanfs/node` dependency to 0.16.8 - refresh the pnpm lockfile and its required HumanFS dependencies Fixes https://github.com/firezone/firezone/security/dependabot/334 --------- Co-authored-by: Firezone Bot <[email protected]> Co-authored-by: Thomas Eizinger <[email protected]>
Jamil(02 Sept 26)
fix(flow-log-upload): list only one batch of reports per pass (#15006) Every upload pass read the name of every report file in an authorization directory into memory and sorted the whole list, then uploaded only the first batch. To reduce memory usage, the uploader now keeps only the oldest report names needed for one batch while it walks the directory, so a pass uses memory in proportion to the batch size no matter how large the spool is. Related: #15003
Jamil(02 Sept 26)
fix(apple): offer the extension install from the menu bar (#15011) Fixes a regression where if the macOS system extension needs install, the menu item was not displaying this status, instead showing `Sign in` which would lead to the same alert screen that #15010 hits. Fixes that by changing the menu item in this state so that it's not possible to initiate a sign in unless the system extension is installed. Related: #14742 Related: #15010
Jamil(02 Sept 26)
fix(portal): unmap IPv4-mapped IPv6 remote addresses (#15013) The portal listens on a dual-stack socket. IPv4 clients arrived as IPv4-mapped IPv6 addresses, for example `::ffff:107.197.104.68`. That value was stored and shown as the remote IP on devices, sessions and sites. It also did not match IPv4 trusted-proxy blocks. The portal now converts a mapped address to plain IPv4 at the endpoint and when it builds the auth context. Rows that already hold the mapped form are updated on the next connection.
Jamil(02 Sept 26)
feat(portal): show the trust shield on an online attested device (#15012) The Online badge for a client device shows a green dot. When the device attested through an X.509 certificate, the dot is now the device trust shield instead. An admin can see at a glance which online devices proved their identity. This applies to the Devices table, the device panel, and the device pool member list on a resource. Offline devices and devices that did not attest look the same as before.
Jamil(02 Sept 26)
fix(relay): revoke TURN access for disabled accounts (#14986) Relays use the account list from #14993 to accept account-bound TURN credentials only for enabled accounts. Removing an account immediately clears its existing allocations. Related: #14993
Firezone Bot(02 Sept 26)
chore(fuzz): grow the x509-claims corpus (#15002) The nightly fuzz job discovered new coverage for `x509-claims` and refreshed its uncovered-region ceiling.
Firezone Bot(02 Sept 26)
chore(fuzz): grow the relay-proto corpus (#15000) The nightly fuzz job discovered new coverage for `relay-proto` and refreshed its uncovered-region ceiling.
Firezone Website
Website
Zero Trust Access That Scales | Firezone
Replace your VPN with Firezone, an open-source zero trust access platform built on WireGuard®. Connect users to anything, anywhere. Try free today.
Redirects
Does not redirect
Security Checks
2 security checks failed (63 passed)
- Domain Recently Created
- Domain Very Recently Created
Server Details
- IP Address76.76.21.61
- LocationWalnut,California,United States of America,NA
- ISPVercel Inc
- ASNAS16509
Associated Countries
US
CA
JP
Safety Score
Website marked as safe
100%
Blacklist Check
www.firezone.dev was found on 0 blacklists
- AntiSocial Blacklist
- Artists Against 419
- Badbitcoin
- Bambenek Consulting
- CERT Polska
- CoinBlockerLists
- CRDF
- CryptoScamDB
- EtherAddressLookup
- EtherScamDB
- Fake Website Buster
- MetaMask EthPhishing
- NABP Not Recommended Sites
- OpenPhish
- PetScams
- PhishFeed
- PhishFort
- Phishing.Database
- PhishStats
- PhishTank
- Phishunt
- RPiList Not Serious
- Scam.Directory
- SecureReload Phishing List
- Spam404
- StopGunScams
- Suspicious Hosting IP
- ThreatFox
- ThreatLog
- TweetFeed
- URLhaus
- ViriBack C2 Tracker
Website Preview
Firezone Reviews
More Self-Hosted Network Security
Powerful open source web content filter.
A hardened, versatile, state-of-the-art open source firewall based on Linux. Its ease of use, high performance and extensibility make it usable for everyone.
Widely used, open source firewall/router.
Network-level advertisement and Internet tracker blocking application which acts as a DNS sinkhole. Pi-Hole can significantly speed up your internet, remove ads and block malware. It comes with a nice web interface and a mobile app with monitoring features, it's open source, easy to install and very widely used.
A simple way to set up a home VPN on any Debian server. Supports OpenVPN and WireGuard with elliptic curve encryption keys up to 512 bit. Supports multiple DNS providers and custom DNS providers - works nicely along-side PiHole.
Another DNS server for blocking privacy-invasive content at its source. Technitium doesn't require much of a setup, and basically works straight out of the box, it supports a wide range of systems (and can even run as a portable app on Windows). It allows you to do some additional tasks, such as add local DNS addresses and zones with specific DNS records. Compared to Pi-Hole, Technitium is very lightweight, but lacks the deep insights that Pi-Hole provides, and has a significantly smaller community behind it.
Detect if you have a malware-infected computer on your network, and powerful network analysis framework and monitor.
About the Data: Firezone
Edit Firezone Data
You can edit Firezone's entry in this section of awesome-privacy.yml by submitting a PR to our GitHub repo.
Note that some of the information shown above has been aggregated from external
sources, a list of these can be found data documentation.
Origin Data
Modify Data
API
You can access Firezone's data programmatically via our API. Simply make a GET request to:
https://api.awesome-privacy.xyz/v1/services/firezoneThe REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.
Share Firezone
Help your friends compare Self-Hosted Network Security, and pick privacy-respecting software and services.
Share Firezone and Awesome Privacy with your network!