I've got two potential ideas:
#1
This probably is not going to be applicable to your average client setup (wherein they're running Windows or you have a limited ability to load/execute scripts on their machines), but I tackled this problem in a site-to-site configuration.
Basically the client machine runs a pair of OpenVPN daemons, one connecting to each of the primary/backup servers.
It uses scripts on connect/disconnect to change the routing such that traffic will preferentially transit the primary connection. It's a bit of a faff to setup, but it works like a charm. Probably not a practical option if you have hundreds of clients, either. But I figure it might give some inspiration at the very least:
http://s.co.tt/2019/04/23/redundant-vpn-tunnels/
Note that in my case the client was connecting to the same physical server, but via two different internet connections. It would work just as well connecting to two different servers, though the server-side would actually be simplified.
#2
But I also came upon this post looking for an easier solution to use with employee remote users, wherein a single client daemon could be used (and without scripting).
This isn't a direct solution, but may fit your use case.
Perhaps add the
inactive option to the
backup server's config. (Not the client, and
not as a
push from the server.)
On the client, the
inactive option causes the OpenVPN process to
exit and therefore not reconnect.
--inactive n [bytes]
Causes OpenVPN to exit after n seconds of inactivity on the TUN/TAP device. The time length of inactivity is measured since the last incoming or outgoing tunnel packet. The default value is 0 seconds, which disables this feature.
On the server side, it causes the server to terminate the connection of the inactive client only. It also does not terminate the server process. As such, the client is free to reconnect to the next
remote server.
So, if the backup server contained something like
inactive 600 in its config, it will terminate any clients that have been inactive for 10 minutes. The client should then try the next server in the sequence, which would be the primary. If the primary is still down, it will reconnect to the backup.
This actually works better, in a way, than forcing the client to reconnect to the primary as soon as it's reachable. In that case the client might be copying a file or doing something time critical and their connection would be interrupted during the failback. If they're inactive anyway, it's unlikely they'll notice.
The downsides are twofold:
If the client never goes inactive, they'll never reconnect to the primary. On the other hand, if clients are frequently inactive, they'll frequently reconnect to the backup server. I suppose that fiddling with the number of seconds until inactivity is determined could mitigate those issues, based upon your average user's workload.
In fairness, I haven't run #2 myself in production,
but I did just now test it in my lab using a single server with 2 IPs and two clients to insure that
inactive would work as expected. But my apologies in advance if that ends up being a red herring.
This "problem" does not - and will never - have a solution from within the scope of OpenVPN.
That is an incredibly "defeatest" attitude, considering near-solutions to this problem are available. I'm sure there are better ones than mine. Sadly I'm not as experienced with OpenVPN as you seem to be, given your precognition of
the entire lifetime of future development of OpenVPN. So I'm sure you can come up with something better, no?