OpenSSL is already installed, the host has entropy, and generating a key with it feels like the obvious shortcut. The output will be random and secret and completely unusable, and the failure arrives as a control-channel error rather than as anything mentioning a key format. That misdirection is the expensive part, because it sends people to inspect their ciphers. What the VPN reads is a specific file structure, not an arbitrary block of bytes, and one variant of the feature cannot be produced outside the server at all.

What the file on disk actually has to be

An OpenVPN static key file is text. It opens with a comment line that declares what it is, carries hex data in fixed-width rows, and totals 256 bytes of key material. OpenVPN reads it as the control channel's shared secret, not as a certificate, not as a passphrase and not as anything a TLS library would recognise.

The same object type serves both control-channel features. With tls-auth, each peer also needs a direction so that one side's packets cannot be reflected back at it. With tls-crypt, a single shared secret encrypts and authenticates the control channel in both directions, which hides the handshake as well as protecting it.

None of that is secret knowledge, and the format is not the point. The point is that the file has to match what the reader expects exactly: header, row width, trailing newline and total length. A file that is off by one row loads as garbage or fails outright. Comparing two peers byte for byte is therefore a legitimate first test, and it is faster than reading either configuration file.

The supported way to make one

Generate the plain static key with the tool that will consume it, then reference it from both ends:

openvpn --genkey secret /etc/openvpn/tc-shared.key
tls-crypt /etc/openvpn/tc-shared.key

The option spelling changed over time: older 2.4-era installations used a form with a separate flag before the filename, while current builds accept the shorter one. Either way the resulting file is the same kind of object, so the check is whether both peers hold identical bytes.

The second generation adds structure that no external generator can invent. A server key is created once, and each client receives a wrapped key derived from it:

openvpn --genkey tls-crypt-v2-server /etc/openvpn/tc-v2-server.key
openvpn --genkey tls-crypt-v2-client /etc/openvpn/laptop1.key --tls-crypt-v2 /etc/openvpn/tc-v2-server.key

What the client receives is not the server's own key duplicated. It is a wrapped object carrying metadata that only the server can unwrap, and that wrapping is why a per-device file can be revoked without touching any other device. Keep the server key on the server and treat it as the root of that per-device trust.

Where hand-made bytes break down

Printing 256 random bytes as hex beneath a correct header would, in theory, yield a static key file that loads. It remains a bad idea. Every formatting detail becomes a chance to produce material that fails at load time or, worse, leaves two peers holding different values that only reveal themselves as an authentication failure.

Nothing equivalent is possible with the v2 variant. A wrapped client key exists only as output from the server key process, and the server retains the material needed to unwrap it. A random blob will be rejected, or will simply fail to decrypt, and neither message will mention randomness.

Version compatibility sits on top of all this. The first generation needs a release that supports it on both ends, and the second needs a newer release again. A client built before the feature existed cannot complete a handshake with a server that only accepts wrapped material, and the failure it reports points at the control channel rather than at the version.

Rotating without locking everyone out

Rotating a single shared secret is a coordination exercise rather than a technical one. Every client needs the replacement file in hand before the server withdraws the previous one, and any machine still holding the old value fails the moment that happens. Do not start that rotation in the middle of a working day.

With the v2 arrangement, rotation is per device: issue a new wrapped key for one machine and retire the old one for that machine alone. That is the main argument for moving once every client is on a release that supports it.

File permissions belong in the same conversation. The key should be readable only by the account that runs the service, and it should not live in the same repository as the profiles it protects. The OpenVPN 2.6 reference documents the generation forms and the key-material sections, which is a better source than a copied command from a forum post.

Nuŋlɔɖi siwo ku ɖe eŋu