You add a branch route, it works, and then a firmware update or a save from the web UI removes it. Two fixes look equally reasonable at that moment: put the route in the appliance's supported configuration source, or append it to the generated file from a startup script. They behave the same for a week and diverge on the second upgrade. This article compares what each one actually owns.

The two candidates own different things

The supported configuration source is whatever the appliance treats as input: a GUI field, an imported profile, a documented per-client directory, a settings database the management package reads. The generated server.conf is output. Editing output works until the generator runs again, which happens on save, on reboot and on upgrade.

The script approach patches that output after the generator finishes. It is a legitimate technique for a lab, and it is the wrong default for a branch office, because it makes the route depend on text matching rather than on a documented field.

QuestionSupported config sourcePost-generation script
Survives a GUI saveYesOnly if the save does not regenerate the file
Survives a package upgradeUsually, when the field is documentedNo guarantee; the wrapper can be replaced
Supportable by the vendorYesNo
Obvious to the next adminYes, it is in the UINo, it lives in a wrapper

What the appliance regenerates, and when

Management packages usually keep settings in a database or a template set and render the daemon configuration at start. A save from the web UI often rewrites the whole file rather than patching a line. If your change lived in that file, it is now gone, and nothing logs a warning because from the appliance's point of view nothing was lost.

Startup wrappers have a second failure mode. A grep for a directive with particular spacing stops matching after a template change, and the script silently does nothing. Worse, a firmware update can replace the wrapper with a new version, taking the patch with it. You then have a route that existed for a year and disappeared during maintenance nobody connected to routing.

What the supported owner has to express

A branch prefix needs three statements, not one. The client must learn the route, the server must know which authenticated client owns the prefix, and the branch side must return traffic to the tunnel address it was given. In OpenVPN terms that means a pushed route, a matching iroute tied to the client, and a return path on the far side.

This is where appliance UIs mislead. A checkbox labelled "allow clients to access the server LAN" describes traffic toward the server's own network. Your branch is the opposite direction: a network behind one client, reachable from the server side. The same label does not imply support for that, and a valid directive in a file is not a promise that the package will preserve it.

When no supported control exists

Sometimes the installed release genuinely cannot express a peer-specific route. Then the honest options are a different gateway you control, or a supported site-to-site mode on both ends. Both endpoints have to speak it. A product page that says site-to-site does not make an arbitrary OpenVPN profile interchangeable with another protocol's tunnel, and forcing that pairing usually produces a half-connected tunnel that looks fine in a status page.

Pick the option you can describe in one sentence to whoever inherits the network. If the answer requires mentioning a script path and a text pattern, the design is already fragile.

Make the intent auditable

Record the contract outside the appliance: effective client identity, prefix, return gateway, and the supported field that supplies each one. Export the configuration through the supported mechanism so a rebuild has a reference, and verify service after a reconnect, a restart and an upgrade rather than only after the change.

Compare the generated result against that record when something breaks, instead of restoring an unexplained line and hoping. The OpenVPN 2.6 reference is the place to confirm how route and iroute interact before you argue with a UI.

Checklist for the next change: name the owner, state the three-part contract, export the intent, and re-test after the appliance's own lifecycle events rather than after your edit.

Ingingo zihuye