Self-hosted Element Call with LiveKit

Element Call gives Matrix users group voice and video calls, but on a self-hosted Synapse it needs experimental Synapse features, a LiveKit SFU and an authorization service you run yourself. This page explains what to plan, configure and verify.

On this page

How self-hosted Element Call fits into a Matrix deployment

Element Call on a self-hosted Synapse requires specific experimental Synapse features to be enabled, plus a LiveKit SFU and a MatrixRTC Authorization Service that your organization runs itself. If you operate a Synapse homeserver and need group voice and video calls to stay inside your own infrastructure, without depending on a hosted calling service, this section explains how the pieces connect. Element Call is the web client that places and joins the calls. It is licensed AGPL-3.0 and maintained by Element in the element-hq/element-call repository, and its self-hosting guide treats the calling stack as a separate deployment from the homeserver.

Each component has a distinct job. The LiveKit SFU (selective forwarding unit) carries the audio and video. It receives each participant's media and forwards it to the others, so every client does not need a direct connection to every other client. The MatrixRTC Authorization Service, lk-jwt-service in the self-hosting guide, checks that a Matrix user may join a call and issues the credentials the SFU requires. Synapse holds the call state that clients use to find each other. For that role, it needs the MSC3266, MSC4140, MSC4519 and MSC4222 features enabled through experimental_features, with max_event_delay_duration set as the guide describes. Synapse does not carry the media itself.

Consider this feature if your team already runs Synapse and can operate a media service with public network exposure, UDP reachability and TLS certificates. The SFU is a separate capacity question from the homeserver, because media load grows with the number of participants and streams, so plan it with its own sizing. Confirm which Synapse release you run before you wire anything together. Synapse v1.161.0 deprecated matrix_rtc.livekit_service_url in favour of a url property set to the SFU WebSocket URL, with the authorization service configured as an application service. Your configuration depends on which of these forms your release expects.

This section sets up the rest of the page: the configuration keys, the setup order, the reverse proxy routes at paths such as /livekit/sfu and /livekit/jwt, the security controls around the SFU and the authorization service, and the limits you should confirm before you commit. Plan the reverse proxy as part of the design, since both services sit behind it and its path layout determines what clients can reach. Before you start, decide which team owns the SFU's public exposure and certificates, and confirm the exact feature requirements against the current Element Call self-hosting guide, because they change between releases.

Configuration options and when each fits

This table compares the main configuration choices for Element Call on a self-hosted Synapse, with the trade-off for each and what to confirm before you commit. Read each row as a decision point, starting with the Synapse settings that calls depend on. The main takeaway is that the SFU endpoint setting and the reverse proxy layout must match your Synapse version and proxy, so confirm both before you build.

DecisionOptionTrade-offConfirm before choosing
Synapse experimental featuresEnable the features Element Call requires and set max_event_delay_durationCalls depend on these settings, and enabling them adds homeserver configuration your team must review and maintainExact flag names and values for your Synapse release in the Element Call self-hosting guide
SFU endpoint in SynapseSet the url property to the LiveKit SFU WebSocket URLThis is the current property, while livekit_service_url is deprecated and older examples still show itYour Synapse version, since v1.161.0 deprecated livekit_service_url in favour of url
SFU and lk-jwt-service placementRun both on the same hostFewer machines and simpler routing, but media load and the authorization service share CPU, memory and networkExpected concurrent call volume and whether the vendor guidance allows co-location
SFU and lk-jwt-service placementRun them on separate hostsIsolates media load from the authorization service, but adds hosts to patch, monitor and secureNetwork paths, firewall rules and UDP reachability for media traffic in your environment
Reverse proxy path layoutServe the SFU and JWT service under paths on the homeserver domainOne hostname simplifies certificates and client settings, but the proxy must pass WebSocket upgrades correctlyPath names in the self-hosting guide and WebSocket support in your reverse proxy
Synapse process modelRun Synapse as a single processSimplest to operate and sufficient for smaller deployments, with limited headroom for traffic growthExpected user count and load, and whether your team can size one process for it
Synapse process modelRun Synapse with worker processes and RedisSpreads client, federation and event traffic across processes, but adds Redis and more configuration to maintainWorker layout and Redis requirements in the Synapse workers documentation for your release

What Synapse must enable before Element Call works

Element Call does not run on a bare Synapse install. Before any group call can start, the homeserver must support four Matrix proposals: MSC3266 (room summaries), MSC4140 (delayed events), MSC4519 (the MatrixRTC transports registry) and MSC4222 (sync state_after). Synapse switches these on through the experimental_features block in homeserver.yaml, and it needs max_event_delay_duration set so that delayed events are accepted. Treat these as prerequisites for the whole call path, not as optional tuning. Each dependency has a plain role in call setup. Room summaries let the client show a room's details and membership before the user joins, which the call screen relies on. Delayed events let the client schedule a server-side event that is sent if the client disconnects, so other participants see that a call has ended even when a browser crashes. The MatrixRTC transports registry lets the homeserver publish which LiveKit SFU a room should use, so clients discover the media service without hardcoded addresses. Sync state_after gives the client an accurate view of room state at the point a sync batch ends, which keeps call membership consistent across devices.

The required set is not fixed. Element's self-hosting guide for Element Call lists the proposals and settings that a given release expects, and that list can change as the protocol moves forward. Before you edit homeserver.yaml, open the current self-hosting guide in the element-call repository, compare its list with the Synapse configuration manual for your version, and record the exact keys and values you will set. Make the change in a staging homeserver first, restart it, and confirm that a test room can start a call end to end. The LiveKit wiring also depends on the Synapse version. Synapse v1.161.0 deprecated matrix_rtc.livekit_service_url in favour of a url property that points at the SFU WebSocket endpoint, and the LiveKit authorization service is registered as an application service. If your installed Synapse predates this change, plan a Synapse upgrade before you finish the call configuration, because the deprecation path described in the upgrade notes assumes the newer layout. Read every release note between your current version and the target, check the database and Python or PostgreSQL floors, and take a database backup first, since the upgrade notes warn that rolling back can be difficult. Ask your implementation partner or internal team to confirm three things before scheduling the change: the Synapse release you will run in production, the exact experimental_features keys that release requires, and whether any other feature in your deployment, such as single sign-on through Matrix Authentication Service, changes how the authorization service authenticates users. Writing these answers into the change record turns a configuration edit into a repeatable step that can be reviewed and rolled back.

Setting up Element Call with LiveKit in order

This sequence takes an existing Synapse homeserver to a working group call. Each step depends on the one before it, so the check at the end of every step matters more than how quickly the change is made. The result is a Synapse configuration that enables the MatrixRTC settings, a LiveKit SFU and authorization service you host, and reverse proxy routes that a two-user test call can use.

  1. Confirm Synapse, PostgreSQL and Python versions

    The Synapse administrator confirms the release to be run before changing any configuration. The MatrixRTC url property described below requires Synapse v1.161.0 or later. Synapse 1.143.0 and later require PostgreSQL 14 or newer, and Synapse 1.142.0 and later require Python 3.10 or newer. Check the installed versions on the host, then compare them with the upgrade notes for the exact release. The step is done when the running Synapse, database server and Python versions all meet the floor for that release and are recorded in your change log.

  2. Enable experimental features and delayed events

    The Synapse administrator adds the experimental features that Element Call depends on to homeserver.yaml. The Element Call self-hosting guide lists them by MSC number: room summaries, delayed events, the MatrixRTC transports registry and sync state_after support. Set max_event_delay_duration as well, because delayed events depend on it. Restart Synapse and read the startup log. The step is done when the configuration loads without errors and the server starts cleanly on its configured listeners.

  3. Deploy the LiveKit SFU

    The infrastructure team deploys the LiveKit SFU as a dedicated service beside Synapse, on hosts or nodes they control. Element Call's self-hosting guide expects the SFU to run separately from the homeserver. Generate and store its keys according to the LiveKit documentation, and set its network options so the reverse proxy can reach it. Check that the process starts and that a local client can open its WebSocket endpoint. The step is done when the SFU runs and answers from the proxy network.

  4. Deploy the lk-jwt-service authorization service

    The same team deploys lk-jwt-service, the MatrixRTC Authorization Service, and configures it with your homeserver details and the LiveKit key material it needs to issue tokens for the SFU. Store its credentials in your secrets store and limit who can read them. Check that the service starts, that its log shows the configuration loaded, and that the reverse proxy can reach it on the internal address. The step is done when the service runs and reports no configuration errors.

  5. Register the authorization service with Synapse

    The Synapse administrator creates an application service registration file for lk-jwt-service, using the sender and namespace settings from the Element Call guide. Add the file to the homeserver's application service configuration, then restart Synapse. Check the startup log for the registration loading without errors, and confirm that the authorization service's own log shows it starting its connection to the homeserver. The step is done when both sides load the registration without errors.

  6. Set the MatrixRTC URL to the SFU

    In homeserver.yaml, the administrator sets the url property under matrix_rtc to the WebSocket URL of the LiveKit SFU. Synapse v1.161.0 deprecated the older livekit_service_url setting in favour of this property, so remove the old key if it was carried over from an earlier configuration. Restart Synapse and check that the configuration loads without deprecation or validation errors. Confirm that the value matches the address the SFU answers on through the proxy. The step is done when Synapse loads the setting and the URL is reachable from a client's network.

  7. Configure reverse proxy routes

    The web or network team adds routes to the reverse proxy in front of the SFU and lk-jwt-service. The Element Call guide serves them at paths such as /livekit/sfu and /livekit/jwt, and the SFU route needs WebSocket upgrades enabled. Validate the proxy configuration before reloading it. Check that each path returns a response from its intended backend, and that Synapse client endpoints still respond after the reload. The step is done when every route answers on its expected path from outside the cluster.

  8. Test a two-user call from separate clients

    Two users sign in to Element Call from separate clients, ideally on different devices or networks, and join the same room. Confirm that each user sees the other in the call, that audio and video pass in both directions, and that leaving and rejoining the call works. If a call fails, check the SFU and lk-jwt-service logs for that session. The step is done when both users complete a call with working media and the logs show the session established without errors. Record the client versions and any failing step so they can feed back into the configuration.

Reverse proxy routes between clients, Synapse and LiveKit

The Element Call self-hosting guide places the LiveKit SFU and the MatrixRTC Authorization Service (lk-jwt-service) behind one reverse proxy, at paths such as /livekit/sfu and /livekit/jwt, alongside the Synapse client routes. A client signs in and browses rooms through Synapse, requests credentials from the authorization service, and then opens its media connection to the SFU. Each of those three destinations must resolve through the same public hostname and prefix scheme. Synapse v1.161.0 deprecated matrix_rtc.livekit_service_url in favor of a url property set to the SFU WebSocket URL, so the path you publish in Synapse configuration has to match the route your proxy actually serves.

Wrong path prefixes usually fail quietly. Clients can reach Synapse, log in and see rooms, which makes the deployment look healthy, and then the call step fails because the authorization request or the SFU connection goes to a path the proxy does not forward. Problems also appear when the proxy strips or rewrites a prefix that the component expects to see, or when the Synapse setting and the proxy rule name the SFU differently. Before go-live, write down the exact public URL of each of the three destinations, then check that the Synapse setting, the proxy rule and the component's own configuration all agree on it.

Confirm WebSocket and TLS handling on each route with the documentation for that component, not with a single generic proxy block. The SFU depends on WebSocket connections that the proxy must upgrade and hold open, and the authorization service and Synapse routes may need different timeout, header and body size settings. Check where TLS terminates, whether the proxy re-encrypts traffic to the backend, and which certificate each hostname presents. Note any requirement the LiveKit or lk-jwt-service documentation places on the network path that the proxy cannot satisfy, and raise it before the build starts.

Test each path separately before testing a call. Start with a Synapse client endpoint through the public hostname, then request the authorization service path directly and confirm it responds as its documentation describes. Next, open a WebSocket connection to the SFU path with a standalone client, and only then run a two-account call from Element Call. If the call fails, the earlier checks show which hop broke. Keep the list of paths and the test results in your runbook, and repeat the same checks after any proxy change, Synapse upgrade or certificate renewal.

Security and operational risks of hosting calls yourself

Self-hosting Element Call adds a media path, an authorization service and a set of Synapse features that you must run and keep current. The cards below cover where that adds exposure, how to contain it, and what to verify before calls go live for users.

Internet exposure and TLS for the SFU

The LiveKit SFU and the MatrixRTC Authorization Service must be reachable by clients, so they sit on the public path. Serve both through your reverse proxy with valid TLS certificates, and confirm the certificate chain and renewal work for every hostname clients will use. Restrict which ports are open at the firewall and test that only the intended routes, such as those under /livekit/sfu and /livekit/jwt, respond from outside.

Separating call credentials from Synapse secrets

The authorization service and LiveKit hold keys that issue and verify call tokens, and these should not share files, environment variables or secret stores with Synapse's signing and database credentials. Generate the call keys separately, store them with restricted read access, and document who can rotate each one. Test a rotation in a staging environment before relying on it in production.

Access control and logging on the call path

Calls pass through the proxy, the authorization service, the SFU and Synapse, and each component logs differently. Decide which log sources you retain, where they go, and who can read them, including the reverse proxy access logs that show which routes were requested. Confirm that logs do not record token values or other secrets, and that you can trace one failed join across all four components.

Added moving parts in the patch and monitoring surface

A call deployment adds a dedicated SFU, an authorization service, a reverse proxy configuration and its TLS automation, on top of Synapse, its database and Redis if you use workers. Each component needs its own patch cycle, version record and health check. Before go-live, list every component with its version source and alert on process health, certificate expiry and failed token issuance.

Experimental Synapse features and upgrade risk

Element Call depends on Synapse experimental features and a delayed-event setting, so an upgrade can change behavior the call path relies on. Read the upgrade notes for every Synapse release between your current and target version, and check whether the call-related options changed. Rehearse the upgrade on a copy of your database, because rolling back Synapse can be difficult after schema changes.

Deprecated Synapse call settings

Synapse 1.161.0 deprecated matrix_rtc.livekit_service_url in favor of a url property, with the authorization service configured as an application service. Configurations copied from older guides can fail silently or keep pointing at a removed setting. Compare your homeserver configuration against the current Element Call self-hosting guide and the Synapse configuration manual before each upgrade.

Keeping Element Call working through Synapse upgrades

Plan the MatrixRTC configuration change before you upgrade Synapse, because a working Element Call setup can stop working when the homeserver moves to a release that no longer reads the old setting. Synapse v1.161.0 deprecated matrix_rtc.livekit_service_url in favour of a url property, which takes the LiveKit SFU WebSocket URL. The LiveKit authorization service also needs to be set up as an application service. Find every homeserver configuration that still uses the old key, schedule the change alongside the upgrade, and confirm in the upgrade notes how your target version handles the deprecated key.

Treat the upgrade as one-way unless you have proven a restore. The Synapse upgrade notes warn that rolling back can be difficult because database schema changes occur between releases. Element Call depends on three components, so a partial rollback can leave Synapse, the LiveKit SFU and the lk-jwt-service authorization service on mismatched versions or configurations. Before the change window, take a PostgreSQL backup, copy the Synapse configuration files, and save the LiveKit and authorization service configurations with it. Name the person who owns the restore procedure and write down the steps before the window opens.

Check the platform floors before you choose the target version. Synapse 1.142.0 and later require Python 3.10 or newer, and Synapse 1.143.0 and later require PostgreSQL 14 or newer. Synapse also drops support for Python and PostgreSQL versions once they reach upstream end of life. Confirm the Python runtime on the homeserver host and the PostgreSQL server version now. If either is below the floor, plan the operating system or database upgrade as a separate, earlier change, since it carries its own backup and rollback steps. Synapse supports SQLite, but its documentation recommends PostgreSQL for production.

Read every set of upgrade notes between your current version and your target, not only the notes for the final release. Synapse v1.163.0 is the latest release listed on the Synapse GitHub releases page at the time of research, so your target depends on your own review and approval cycle. Skipping intermediate notes can hide deprecations like the matrix_rtc change. Build a list of each version in between, record every configuration change, and check the Element Call self-hosting guide for any change to the required experimental features, including MSC3266, MSC4140, MSC4519 and MSC4222 enabled through experimental_features and max_event_delay_duration.

Rehearse every upgrade on a copy of production before you touch production. Restore a recent database backup and the configuration files to a staging environment that runs the same Synapse, LiveKit, lk-jwt-service and reverse proxy versions. Apply the planned changes in the same order you will use in production. Then test a call between at least two clients on different networks through the /livekit/sfu and /livekit/jwt routes. Record how long each step takes and every error you see, and set the production window from those measurements, not from estimates. Ask any implementation partner to confirm in writing whether rehearsal and rollback testing are part of the agreed scope.

Limits to confirm in your environment before you commit

The points below are not settled by the public documentation alone, so each one needs an answer from Element, LiveKit or a test in your own environment. They share one dependency: the call feature only works when the Synapse release, the LiveKit SFU, the network path and the license terms fit together.

Call support in your Synapse version

Element Call depends on several Matrix MSCs that Synapse must enable through experimental_features and max_event_delay_duration. Ask Element which Synapse release supports every required MSC, then confirm that release still accepts the matrix_rtc settings in the self-hosting guide. Also read the upgrade notes for your target release, because Synapse v1.161.0 deprecated matrix_rtc.livekit_service_url in favor of a url property that points to the SFU WebSocket.

LiveKit SFU capacity and scaling

The LiveKit SFU forwards media for every participant, so sizing depends on expected concurrent participants, video layouts, bitrates and the number of rooms running at once. Ask LiveKit how a single node scales, whether you can add nodes in the deployment mode you plan, and what load testing they recommend. Run a test at your expected peak in a non-production environment and record CPU, bandwidth and packet loss before you size production.

UDP reachability and TURN requirements

Media travels most efficiently over direct UDP paths, but some client networks block UDP and may require a TURN service to relay traffic. Confirm which UDP port range the LiveKit SFU needs, whether it must accept connections from the internet or only from client networks, and whether you need a TURN server and which one. Test from several networks, including corporate Wi-Fi and mobile connections, because results vary by location.

Behavior behind NAT and firewalls

Calls behind NAT or restrictive firewalls can fail or degrade when ICE negotiation finds no working path or when fallback transports are blocked. Ask Element and LiveKit which connection paths the stack attempts, what fallback exists when UDP is blocked, and which ports the reverse proxy and host firewall must allow. Test call setup from behind your egress proxy and from a network that blocks UDP, so you see the actual failure mode before users do.

AGPL-3.0 obligations for changes

Synapse and Element Call are licensed under AGPL-3.0, whose conditions can apply when you modify the software, offer it to users over a network or distribute copies. Have counsel review planned changes, such as custom login flows or Element Call branding, and ask Element whether a commercial exception applies to your case. Confirm the license of each other component in the stack, including the LiveKit SFU and the authorization service, since each may carry different terms.

Questions buyers ask before hiring help with Element Call

How much does a self-hosted Element Call setup cost?

The cost depends on the scope agreed in writing, and DeployOpen does not publish a price list. Most of the fee pays for people's time across five components: planning (topology, domains, certificates, identity and capacity), Synapse configuration and upgrades, LiveKit SFU and authorization service deployment, reverse proxy work for the call routes, and testing and handover. Planning and first deployment are one-time costs. Synapse upgrades, certificate renewal, LiveKit version updates and monitoring recur, either as internal hours or under a support retainer. Ask every supplier for a quote that prices each component separately, names who performs each task, and marks which items recur and how often. That structure makes quotes comparable.

How long does it take to deploy Element Call with LiveKit?

Duration depends mainly on your starting point and on approvals outside the project team. The main drivers are the Synapse version you already run, whether experimental features are already enabled, whether a dedicated host exists, lead times for DNS and TLS certificates, firewall changes for media traffic, and the length of your test window. Identity integration and the number of client platforms to test also affect the schedule. Ask for a written timeline with milestones, the client dependencies behind each milestone, and the change windows the plan assumes. A timeline without named dependencies is hard to hold a supplier to.

What does our team need to provide before deployment starts?

Before work starts, the team should provide administrative access to the Synapse host and its PostgreSQL database, the current Synapse version and its upgrade history, and the planned server_name and DNS records. You will also need TLS certificates or a process to issue them, access to the reverse proxy, network paths from users to the LiveKit media ports, and your firewall change process. Name one owner for infrastructure decisions and one for user and room policy, and reserve a change window for the cutover. Test accounts on at least two client platforms help the test phase run without delay.

Can our internal team set up Element Call without outside help?

Yes, if the team already runs Synapse, a reverse proxy and a Linux server estate, and is willing to learn the media side. The skills needed are Synapse configuration and PostgreSQL administration, reverse proxy routing with TLS and WebSocket support, container or Kubernetes operation depending on the chosen deployment method, firewall and UDP networking for call media, and identity provider configuration. Most internal teams find the gap in WebRTC networking and in upgrade rollback planning. A pilot on a non-production homeserver lets the team test these areas before touching live users. Confirm the exact steps against the Element Call self-hosting guide for your versions.

Which Synapse experimental features does Element Call require?

Element Call needs homeserver support for MSC3266 (room summaries), MSC4140 (delayed events), MSC4519 (the MatrixRTC transports registry) and MSC4222 (sync state_after). In Synapse these are enabled through experimental_features, and the delayed event behavior is controlled through max_event_delay_duration. Confirm the exact keys and values against the Element Call self-hosting guide for the Synapse version you run, because the configuration changes between releases. Restart Synapse after the change and verify the features in a test room before enabling calls for users. Keep a copy of the previous configuration so the change can be reversed if a test fails.

How do the LiveKit SFU and authorization service fit behind the reverse proxy?

Element Call uses a dedicated LiveKit SFU for media alongside the MatrixRTC Authorization Service, which the guide calls lk-jwt-service. The reverse proxy serves them at paths such as /livekit/sfu and /livekit/jwt. Synapse v1.161.0 deprecated matrix_rtc.livekit_service_url in favour of a url property that points to the SFU WebSocket URL, and the authorization service is set up as an application service. Check that the proxy forwards WebSocket upgrades on the SFU route, that TLS is valid for each host, and that the routes respond before testing calls. Confirm the Synapse configuration keys against your version, since older configurations will need changes.

What should we check before upgrading Synapse with Element Call enabled?

Read the upgrade notes for every version between your current release and the target, not only the final one. Synapse 1.143.0 and later require PostgreSQL 14 or newer, and 1.142.0 and later require Python 3.10 or newer, so check both floors first. The upgrade notes warn that rolling back can be difficult because database schema changes between releases, so take a verified database backup and rehearse the upgrade on a copy. Confirm that the Element Call and LiveKit versions you run support the target Synapse release, and that the Synapse configuration changes for the MatrixRTC settings are in place. Schedule the upgrade with a documented fallback plan.

What does DeployOpen handle for Element Call, and what stays with our team?

DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms in your own infrastructure, including your cloud accounts, data centers or air-gapped networks. Most engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts, and ongoing support, upgrades and testing are available as retainers. Your team keeps ownership of the domains, keys, accounts and hosts, along with the decisions on change windows, user policy and room governance. DeployOpen prepares systems and evidence for compliance assessments, but independent auditors and certification bodies issue audit reports and certifications. A quote follows from the written scope.

How DeployOpen works on this

DeployOpen plans and implements Self-hosted Element Call with LiveKit inside your own infrastructure, starting from a written scope that names the Synapse experimental features, the LiveKit SFU, the authorization service and the reverse proxy routes. Work is fixed-scope, so deliverables and timelines are agreed in writing before the build starts. Ongoing support and upgrades are available as a retainer.

How we scope

  • The written scope names the Synapse experimental features Element Call requires, and how each is enabled.
  • It fixes the server_name, public hostnames and the LiveKit SFU and authorization service placement in your environment.
  • Scope also lists the reverse proxy routes for the SFU and JWT paths, and who operates each component.

How we build

  • Enable the MSC-dependent Synapse settings in a staging homeserver first, then confirm each one loads cleanly.
  • Deploy the LiveKit SFU and the lk-jwt-service authorization service, and set the Synapse url property to the SFU WebSocket URL.
  • Route the SFU and JWT paths through the reverse proxy, then test WebSocket upgrades and TLS on each path.

How we hand over

  • Deliver the configuration, proxy rules and service definitions as versioned files your team can review and redeploy.
  • Provide a runbook covering call join tests, log locations, certificate renewal and the LiveKit restart order.
  • Walk your operators through the upgrade notes for Synapse and Element Call so they know what changes each release.

How we support

  • Support can run as a retainer covering upgrades, monitoring review and fixes to the calling stack.
  • Element Call upgrades track the Synapse experimental features it depends on, so each upgrade is checked against them.
  • Security testing of the call path can be scoped separately, covering the proxy routes and the authorization service.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.