Microsoft Tunnel is Intune's own VPN gateway: containers on a Linux server registered with Intune, with Microsoft Defender for Endpoint as the client app on Android and iOS/iPadOS. When it breaks, the clues are spread across the setup script, the Health status tab, the Linux journal and the device. In this post I'll follow that chain, decode the log errors Microsoft documents and show what a healthy server looks like.
Errors this guide fixes
main: tun.c:655: Can't open /dev/net/tun: Operation not permittedjournalctl -t ocserv (Tunnel server)Error executing Checkupjournalctl -t mstunnel_monitorFailure starting service mstunnel-agentjournalctl -t mstunnel_monitorFailure starting service mstunnel-serverjournalctl -t mstunnel_monitorFailed to parse version-info.json for version information.journalctl -t mstunnel-agentSystem.Text.Json.JsonException: The JSON value could not be converted to System.DateTimejournalctl -t mstunnel-agentLast check-in: UnhealthyIntune admin center (Tunnel health check)TLS certificate revocation: WarningIntune admin center (Tunnel health check)
Symptoms#
- The
mstunnel-setupscript stops at the certificate, sign-in or Site step, or the server never appears online under Tenant administration › Microsoft Tunnel Gateway › Health status. - The server's Health check tab shows
Last check-in: Unhealthy,TLS certificate revocation: Warningor another check that isn't Healthy. - The journal on the Linux server contains lines like these:
# journalctl -t ocserv
main: tun.c:655: Can't open /dev/net/tun: Operation not permitted
# journalctl -t mstunnel_monitor (Podman hosts)
Error executing Checkup
Message: Failure starting service mstunnel-agent
Message: Failure starting service mstunnel-server
# journalctl -t mstunnel-agent (Podman hosts)
Failed to parse version-info.json for version information.
System.Text.Json.JsonException: The JSON value could not be converted to System.DateTime- Devices get the VPN profile, but the Defender app never connects, sessions end after an hour, or internal names don't resolve.
Why it happens#
- Intune objects. A Server configuration holds the client IP range, port, DNS servers and split-tunnel rules. A Site holds the public FQDN or IP devices connect to, an optional internal URL that servers probe every five minutes, and upgrade settings. Setup joins the server to one Site.
- The Linux host. Docker or Podman runs two containers: an agent that talks to Intune, and the VPN server (journal tag
ocserv). Themstunnel_monitorservice watches both;/usr/sbin/mst-climanages everything. - Certificates. The TLS certificate secures client connections; the management agent certificate authenticates the agent to Intune and should renew itself.
- The client. Defender for Endpoint plus a VPN profile with connection type Microsoft Tunnel.
Most failures come from blocked outbound access (proxy or TLS inspection), certificate mistakes, overlapping client IP ranges, Podman losing track of its containers, or client configuration conflicts.
How to fix it#
1. Check the Intune side first#
- The Site's FQDN or IP must resolve in public DNS and be publicly routable. Allow the server port inbound over TCP, and over UDP unless you selected Disable UDP Connections.
- The client IP range must not overlap corporate ranges, or traffic falls back to loopback. Microsoft suggests
169.254.0.0/16. - Never use
0.0.0.0in split-tunnel rules, and include your corporate DNS servers in the include rules. - Run Microsoft's Tunnel readiness tool (linked from the prerequisites page) before installing.
2. Run (or re-run) the setup script#
# as root, for example after sudo -i
wget --output-document=mstunnel-setup https://aka.ms/microsofttunneldownload
chmod +x ./mstunnel-setup
export mst_log_verbose=1 # optional: detailed console output
./mstunnel-setup # rootless Podman: mst_rootless_mode=1 ./mstunnel-setup- Re-running an interrupted script resumes where it stopped.
- Certificate: PEM needs the full chain in
/etc/mstunnel/certs/site.crtand an unencrypted key in/etc/mstunnel/private/site.key; a PFX goes to/etc/mstunnel/private/site.pfx. The SAN must contain the server's FQDN or IP. - Sign-in: enter the device code at
https://microsoft.com/deviceloginwith an account that has Intune Administrator-equivalent permissions and an Intune licence. - Site: choose the Site GUID. On Red Hat Enterprise Linux 8.4 or later, run
mst-cli server restartbefore connecting clients.
Compare the certificate on disk with what clients receive:
openssl x509 -in /etc/mstunnel/certs/site.crt -noout -subject -enddate -ext subjectAltName
openssl s_client -connect tunnel.contoso.com:443 -servername tunnel.contoso.com -showcerts </dev/null3. Work through the Health check tab#
| Check | Not healthy means | Fix |
|---|---|---|
| Last check-in | No check-in for over five minutes | mst-cli agent status, mst-cli agent logs --tail 200; fix proxy or CA trust |
| Server container | Server container not healthy | mst-cli server restart; read journalctl -t ocserv |
| Server configuration | Configuration from Intune couldn't be applied | Recheck step 1 values and the agent log |
| TLS certificate | Warning at 30 days or less; Unhealthy when expired | Renew and import (below) |
| TLS certificate revocation | Warning: OCSP/CRL address unreachable; Unhealthy: revoked | Allow those URLs outbound; replace a revoked certificate |
| Internal network accessibility | Can't reach the Site's internal URL (Unknown = no URL set) | Routing, firewall and DNS towards the internal network |
| Upgradeability / Server version | No contact with the Microsoft Container Repository / two or more versions behind (unsupported) | Proxy for image pulls; approve or schedule upgrades |
Proxy and TLS inspection. Change the host's proxy in /etc/mstunnel/env.sh, then run mst-cli install to rebuild the containers. If traffic is inspected, copy your root CA files (.crt) to /etc/mstunnel/ca-trust and run mst-cli server restart and mst-cli agent restart. On Podman hosts, also add the proxy to the monitor service (systemctl edit --force mstunnel_monitor) so upgrades can pull images.
Certificate renewal. Copy the new site.crt and site.key (or site.pfx) into place, then run mst-cli import_cert and mst-cli server restart.
Server offline, but clients connect. Microsoft's fix is reinstalling, which re-enrolls the agent: run mst-cli uninstall as root (it also removes the server from the admin center), then the setup script.
4. Match the log errors#
| Log line | Meaning | Fix |
|---|---|---|
Can't open /dev/net/tun: Operation not permitted | Devices can't connect | mst-cli server restart after the host reboots; schedule it with cron if it recurs |
Error executing Checkup + Failure starting service ... | Podman can't see the running containers | Restart the Podman containers; cron job if it returns |
Failed to parse version-info.json ... | Podman/agent date-format mismatch; not fatal | Update the containers |
journalctl -t mstunnel-agent -t mstunnel_monitor -t ocserv --since "1 hour ago"
journalctl -t mstunnel_monitor -f5. Fix the client side#
- Assign Defender for Endpoint and have users open it. In Devices › Manage devices › Configuration, the VPN profile needs connection type Microsoft Tunnel and the right Site. Android Enterprise dedicated devices, guest accounts and personal Microsoft accounts aren't supported.
- Android per-app VPN doesn't start when an app opens: enable Always-on VPN or users must connect manually. iOS/iPadOS ignores split-tunnel rules when per-app VPN is on.
- Defender as MTD app and Tunnel client on Android: use custom settings in the VPN profile; on personally owned work profiles a separate Defender app configuration profile conflicts with Tunnel and can block connections. For Tunnel without Defender features, use
defendertoggle= 0 (Android) orTunnelOnly= True (iOS). - Android Strict Tunnel Mode blocks all traffic while the VPN is down, except excluded apps, by design.
- Sessions last 3,600 seconds by default; Always-on clients reconnect at once. The timeout is changed through Microsoft Graph.
Verify the fix#
- Health status shows the server online with every check Healthy.
- After a test device connects,
journalctl -t ocserv | grep TELEMETRYshows anOCSERV_TELEMETRY,connect,...line with the user ID. Its device ID identifies the Defender installation, not the Intune or Entra device. - An internal site opens from an app in the per-app VPN list.
- Still failing? Send logs on the server's Logs tab collects verbose logs for eight hours; reproduce the issue in that window before opening a case.
Prevent it next time#
- Stage renewed certificates early:
mst-cli import_cert delay 10080starts using the new certificate after that many minutes. - Stay at most one version behind with automatic upgrades and a maintenance window per Site.
- Set an internal URL check on every Site, and document proxy and CA trust settings that upgrades rely on.
Related: third-party VPN profiles, VPN certificate chain issues and Android COPE enrollment errors.
References#
- Configure Microsoft Tunnel for Intune (Microsoft Learn)
- Monitor Microsoft Tunnel (Microsoft Learn)
- Reference for Microsoft Tunnel Gateway (mst-cli) (Microsoft Learn)

