The server reboots, OpenVPN starts, and RRAS comes up while the adapter or route it depends on is still missing. Restarting RRAS by hand a minute later fixes it, which makes the problem look solved and hides the real one. Two different conditions are being confused here: the prerequisite service is running, and the network resource RRAS actually needs has become usable. A Windows service dependency can express the first condition and never the second, so adding one without defining the resource buys you a tidier-looking boot and the same failure.

What the symptom looks like on a cold boot

The tell is the difference between a cold start and a restart. On a cold start RRAS reports itself running while the tunnel adapter is absent, the route is missing, or the peer address does not resolve yet. A manual restart then succeeds because by that time the resource exists, and the service simply re-reads a world it could not see a minute earlier. The service log will show a clean start in both cases, which is why the event viewer alone rarely explains this.

Capture both states before you change anything: what RRAS reports at boot, and what exists at the moment the manual restart succeeds. If those two observations are identical, startup order is not your explanation and a dependency will not help. The comparison costs ten minutes and saves a week of guessing.

A dependency added on the strength of "it works after a restart" only delays the same failure by however long the prerequisite service takes to report RUNNING. It also makes the boot harder to reason about, because the ordering constraint now looks like an explanation. Ask what object the dependency guarantees and whether that object is the one RRAS could not see.

Name the resource, not just the service

Write down the specific thing that is missing. It might be a tunnel adapter with an address, a route to a peer subnet, a DNS answer, or a certificate that is still being provisioned. "The VPN service is running" is not a resource description, and neither is a green icon in a client. Until you can name the object and a command that shows it, you have not defined the condition you are trying to wait for.

Establish how this OpenVPN instance is launched, too. A GUI-managed tunnel and a service-managed tunnel have different boot lifecycles, and the service name has to come from the machine in front of you rather than from an example written for a different installer. Enumerate the candidates instead of trusting a remembered name.

Get-Service | Where-Object Name -match 'vpn|openvpn' | Select-Object Name, Status, StartType

Read the dependency chain before you add to it

The Service Control Manager reports states such as START_PENDING and RUNNING, and the SERVICE_STATUS reference defines exactly what each field means. None of those states promises that a peer, a DNS name or a downstream application is reachable. That gap is the entire reason this failure survives a correctly configured dependency.

Get-Service -Name RemoteAccess | Select-Object Status, StartType
sc.exe qc RemoteAccess
Get-Service -Name RemoteAccess | Select-Object -ExpandProperty DependentServices

The DEPENDENCIES line from sc.exe qc is the list you must preserve, because sc.exe config RemoteAccess depend= replaces the whole list rather than appending to it. Dropping an unrelated prerequisite while adding a VPN service creates a second fault that appears on a different boot, and it is far harder to diagnose than the original. Copy the existing list into your change record before you touch it.

Dependencies also change shutdown behaviour, because stopping a prerequisite stops the services that depend on it. Check what happens during maintenance before you wire RRAS to something that restarts often.

Gate the restart on a condition, not a timer

A fixed sleep assumes the tunnel will always be ready inside that window, which is exactly the assumption that fails on the boot where a certificate is slow or a link is down. Check the resource itself, with a deadline, and let the check decide whether a restart is needed at all.

Get-NetAdapter | Where-Object Status -eq 'Up'
Get-NetRoute -DestinationPrefix 0.0.0.0/0
Get-WinEvent -LogName System -MaxEvents 40 |
  Where-Object ProviderName -eq 'Service Control Manager'

A scheduled task at startup that runs those checks and restarts RRAS only when the adapter or route is still absent is bounded, auditable and easy to remove. The alternative, restarting RRAS on every reconnect, interrupts healthy sessions and turns an unstable link into a restart loop. That loop is worse than the original fault, because it now affects users who were fine.

Give the check a maximum wait that matches how long the tunnel plausibly takes on your hardware, and make the task exit with a non-zero status when it gives up. A silent task that simply stops trying is indistinguishable from one that succeeded.

Log the transition so the next boot explains itself

Record three timestamps on the same line: when the dependency service reached RUNNING, when the required resource appeared, and when RRAS finally accepted it. That single line answers the question the next engineer will ask, and it costs almost nothing to produce. Without it, the next investigation starts from the same guesswork this one did.

Stop the automation after a defined number of attempts and report failure rather than retrying forever. A boot that ends with a clear "resource never appeared" message is worth more than one that keeps restarting a service in the dark. When that message does appear, the resource name you wrote down in the second section is what the next person will search for.

Pennadoù liammet