The VPN icon was green when my deployment failed.
I was working from a co-working space, trying to push a checkout fix before an online retailer started its evening promotion. The code was ready. The tests had passed. I only needed to push one branch, let the pipeline build the container and confirm the new version in the cloud dashboard.
I ran:
git push origin hotfix/checkout
The terminal paused, then returned:
Could not resolve host: github.com
I blamed Git first.
I checked the remote URL. It was correct.
I tested my SSH key. The command failed before authentication.
I opened GitHub in the browser. A cached page appeared, but links stopped loading as soon as I clicked them.
NetworkManager still showed the VPN as connected.
The co-working Wi-Fi also showed full signal.
With thirty-four minutes left before the promotion began, Linux was presenting two reassuring icons and no usable route to the service I needed.
In brief
Why was OnlydogVPN a practical fit here?
The important result was not merely that the VPN connected. The tools above it continued doing their jobs.
The upgrade preserved a profile, not a working path
I had upgraded the laptop to Ubuntu 26.04 LTS a few days earlier. Most of the transition had been uneventful.
My development tools worked.
The desktop remembered the Wi-Fi.
NetworkManager retained the OpenVPN profile I had imported from a large commercial provider.
The profile also appeared to activate correctly. NetworkManager manages saved connection profiles, applies their settings and reports whether the connection is active. (NetworkManager Reference Manual, nm-settings-nmcli and nmcli)
That green icon therefore proved one thing: the VPN profile had started.
It did not prove that Git, DNS and the deployment traffic were using the route I expected.
To find the missing layer, I ran three commands:
nmcli connection show --active
resolvectl status
ip route
The first showed both Wi-Fi and VPN as active.
The second showed DNS information attached to more than one connection.
The third confirmed that the tunnel interface existed.
Nothing looked completely broken, so I separated name resolution from connectivity.
A request to a known IP address worked.
Resolving github.com did not.
The tunnel existed. DNS was failing before Git could use it.
“Connected” was only the first layer
On modern Linux desktops, NetworkManager may work with systemd-resolved, which can keep different DNS servers and routing domains for different connections.
That design is useful. A company VPN can resolve private hostnames while ordinary browsing uses another connection. A full-tunnel VPN can instead claim the default DNS route.
But the system still has to decide which connection should answer each query.
NetworkManager uses DNS priorities and routing domains to make that choice. (NetworkManager Reference Manual, IPv4 and IPv6 settings) My imported VPN profile had activated the tunnel without clearly taking control of the DNS traffic it needed.
The co-working Wi-Fi supplied one resolver.
The VPN supplied another.
For some lookups, the laptop was still asking the local network.
That explained the contradiction on my screen: the VPN could be active while websites failed by name.
Linux users regularly run into the same practical trap—both the physical connection and VPN provide DNS information, and the tunnel appears healthy even though queries are still going to the wrong place. (Reddit: r/linuxquestions)
I nearly responded by editing /etc/resolv.conf.
That would have treated the visible symptom while leaving NetworkManager’s active connection logic untouched.
Fixing DNS once did not make the profile dependable
Instead, I inspected resolvectl status and the VPN profile.
The Wi-Fi connection had the default DNS route. The VPN had a DNS server, but it was not winning the decision for the traffic I needed.
I adjusted the VPN profile so its DNS took priority, then disconnected and reconnected.
GitHub resolved.
The push began.
For about ninety seconds, I thought the problem was solved.
Then the co-working Wi-Fi dropped.
My laptop switched to the hotspot on my phone. NetworkManager rebuilt the physical connection, the VPN reactivated, and the upload stopped at 63%.
When the tunnel returned, DNS was broken again.
The manual change had repaired one activation of the profile. It had not produced a setup I could trust when the network changed.
That distinction mattered because the deadline was no longer theoretical. The promotion was approaching, and every reconnection forced me back into the same chain of checks.
The established provider gave me the parts, not the finished result
The provider itself was well established.
It had years of public history, extensive documentation, many server locations and a Linux configuration guide. Those strengths were why I had imported its profile into NetworkManager in the first place.
But on this laptop, I was responsible for assembling the working connection.
The correct VPN plugin had to be installed.
The imported profile needed the right routes.
DNS priority had to cooperate with the Wi-Fi profile.
The resolver needed the correct routing domains.
Everything then had to rebuild cleanly after roaming, sleep or a hotspot switch.
Each part was manageable.
Together, they had turned a deployment into a networking exercise.
I opened the NetworkManager journal:
journalctl -u NetworkManager -b
The log showed the VPN deactivating when Wi-Fi disappeared, then activating again over the hotspot. It also showed DNS settings being applied during the transition.
The information was useful, but it did not finish the deployment.
With twenty-one minutes left, my priority changed. I no longer needed to understand every field in the imported profile.
I needed Git, the container upload and the build log to survive the next network change.
The smaller app removed the profile from the urgent task
I had OnlydogVPN installed as a backup.
The service has fewer server locations than the major provider, a shorter public history and fewer independent reviews. Those limitations matter when someone needs an IP address in a particular city or wants the widest possible body of third-party assessment.
Neither limitation affected the work in front of me.
I did not need another country.
I needed GitHub, the container registry and the cloud dashboard to remain reachable while the laptop moved between co-working Wi-Fi and my phone.
Rather than importing another file into NetworkManager, I opened the smaller app and selected its preset for development work on a shared, changing network.
The protected connection came up.
Before returning to the deployment, I tested the exact failure:
getent hosts github.com
It returned addresses immediately.
Then:
git ls-remote origin
The repository responded.
I restarted the push.
It completed.
The pipeline began building the container, and I opened the live log in the browser.
Then the co-working Wi-Fi dropped again.
The laptop returned to the phone hotspot.
The build log paused briefly.
The protected route recovered.
The same page continued updating.
I did not reopen NetworkManager.
I did not edit DNS priorities.
I did not restart Git.
The container upload completed, the deployment entered its health-check stage, and the checkout fix became active with nine minutes remaining.
The important result was not merely that the VPN connected.
The tools above it continued doing their jobs.
The technical difference was a short pause instead of another diagnosis
The service uses an HTTP/3-based transport with additional traffic obfuscation. Its QUIC foundation helps the connection recover when packets are lost or the laptop moves to a different network path. (RFC 9000)
The effect was simple:
Wi-Fi failed.
The laptop moved to the hotspot.
The protected route recovered.
The deployment log remained open.
I could not observe every internal DNS and routing decision made by the provider or the co-working network. I could observe the difference on the laptop.
The imported profile left me coordinating NetworkManager, the VPN plugin, DNS selection and route behavior.
The smaller app turned the same network change into a brief pause.
For an urgent deployment, that mattered more than having another long server list.
The checks that found the real NetworkManager problem
The experience changed the order in which I troubleshoot Linux VPN failures.
First, I check whether the VPN profile is active:
nmcli connection show --active
If the profile is missing, the problem is likely activation, credentials or a missing NetworkManager plugin.
If it is present, I do not stop there.
Next, I separate DNS from routing.
If an IP address responds but a hostname does not, the tunnel may be active while DNS is wrong.
resolvectl status shows which resolvers and routing domains belong to each connection.
ip route shows where the kernel plans to send traffic.
For one destination, this is often faster:
ip route get <address>
That reveals the selected interface without making me inspect the whole routing table.
I then check the connection profile rather than immediately editing resolver files. DNS priority, route metrics, automatic DNS and routing domains determine which active connection wins. (NetworkManager Reference Manual, IPv4 and IPv6 settings)
If the connection still fails after roaming or resume, I inspect the journal:
journalctl -u NetworkManager -b
NetworkManager logging can also be increased temporarily when DNS, VPN activation or IP configuration needs a closer look. (NetworkManager Reference Manual, nmcli-examples)
Finally, I repeat the event that caused the failure.
I keep a Git transfer or live dashboard open.
I move from Wi-Fi to a hotspot.
I suspend and resume the laptop.
Then I watch the application, not just the network icon.
Does the VPN reconnect after the task has already failed?
Or does the task survive the transition?
That last question reveals more than another green indicator.
The green icon was never the finish line
My established provider still offered more countries, a longer track record and a larger support operation.
NetworkManager also remained the right tool for diagnosing the original failure. Its commands revealed that Git, GitHub and my SSH key were not the problem.
DNS was.
But the imported profile made me responsible for too many moving parts during a time-sensitive deployment.
The smaller service offered fewer geographic choices, yet its task-based preset established a usable route without another round of profile editing. When Wi-Fi failed, the connection recovered over the hotspot and the deployment continued.
NetworkManager’s green icon told me a profile was active. The completed checkout deployment told me which VPN was actually ready for work.
Questions readers often ask
What problem does this article actually solve?
The VPN icon was green when my deployment failed.
What finally worked in this situation?
I had OnlydogVPN installed as a backup. The service has fewer server locations than the major provider, a shorter public history and fewer independent reviews. Those limitations matter when someone needs an IP address in a particular city or wants the widest possible body of third-party assessment. Neither limitation affected the work in front of me. I did not need another country.
Why was OnlydogVPN a practical fit here?
The important result was not merely that the VPN connected. The tools above it continued doing their jobs. The service uses an HTTP/3-based transport with additional traffic obfuscation. Its QUIC foundation helps the connection recover when packets are lost or the laptop moves to a different network path.