Skip to content

OpenVPN — mihomo ​

mihomo can dial an OpenVPN server as an outbound, running a userspace client that stands up a tun-style stack device and routes matched traffic through the encrypted tunnel. The control channel is authenticated with certificates (ca / cert / key), optional tls-crypt, and/or auth-user-pass credentials; the data channel is encrypted with the negotiated cipher.

Outbound ​

Entry under proxies: with type: openvpn. Embeds BasicOption (common outbound fields).

FieldTypeDefaultAllowed valuesDescription
namestring(required)<string>Unique proxy name.
serverstring(required)<host>OpenVPN server host/IP.
portint(required)<port>Server port.
protostringudpudp | tcpTransport protocol of the OpenVPN tunnel.
devstringtuntunVirtual device type (e.g. tun).
cipherstringAES-128-GCMAES-128-GCM | AES-192-GCM | AES-256-GCM | AES-128-CBC | AES-192-CBC | AES-256-CBC | CHACHA20-POLY1305Data-channel cipher used when data-ciphers is unset.
data-ciphers[]string(unset)[<cipher>]Data-channel cipher list offered for negotiation (OpenVPN --data-ciphers). The negotiated cipher is the first server-pushed entry that also appears here; when unset, the single cipher value is used.
data-ciphers-fallbackstring(unset)<cipher>Cipher used when the server does not support cipher negotiation (OpenVPN --data-ciphers-fallback).
authstringSHA256MD5 | SHA1 | SHA256 | SHA384 | SHA512HMAC digest (OpenVPN --auth), e.g. SHA256. Also sets the tls-auth HMAC digest.
comp-lzostring(unset)yes | no | adaptiveLZO compression setting.
castring(required)<inline PEM>CA certificate (inline PEM block).
certstring(unset)<inline PEM>Client certificate (inline PEM block).
keystring(unset)<inline PEM>Client private key (inline PEM block).
tls-authstring(unset)<inline static key>Inline OpenVPN Static key V1 block for tls-auth HMAC protection of the control channel. Mutually exclusive with tls-crypt and tls-crypt-v2. The HMAC digest follows auth.
key-directionstring(bidirectional)0 | 1Key direction for tls-auth. 0 / 1 select the directional key slots; unset uses the same key in both directions.
tls-cryptstring(unset)<inline static key>tls-crypt static key for control-channel encryption/authentication.
tls-crypt-v2string(unset)<inline PEM client key>Inline PEM-encoded tls-crypt-v2 client key. Mutually exclusive with tls-auth and tls-crypt.
usernamestring(unset)<string>auth-user-pass username.
passwordstring(unset)<string>auth-user-pass password.
peer-infomap[string]string{}{<key>: <value>}Extra peer-info key/value pairs (e.g. IV_HWADDR, UV_*) appended to the built-in IV_* entries sent during key exchange. An IV_VER entry replaces the built-in version string.
pingint(unset)<seconds>Keepalive ping interval (seconds).
ping-restartint(unset)<seconds>Restart the tunnel after this many seconds without a ping (seconds).
tran-window*int3600<seconds>Seconds an old data key stays usable after a rekey (OpenVPN --tran-window). Unset means 3600; an explicit 0 expires the old key immediately. Match the server's --tran-window. Negative values are rejected.
handshake-timeoutint0 (no limit)<seconds>Abort tunnel establishment when the OpenVPN handshake takes longer than this many seconds. 0 disables the timeout.
mtuint1500<integer>Tunnel MTU.
udpboolfalsetrue | falseAllow UDP traffic through the proxy.
ip-stackIPStackOption(auto)IPStackOptionUserspace IP stack for the tunnel: { mode: auto|gvisor|mips, congestion-controller: cubic|reno|bbr|bbr3 } — the same block as WireGuard's ip-stack.
remote-dns-resolveboolfalsetrue | falseResolve destination names using the tunnel's DNS.
dns[]string[][<server>]DNS servers used for the tunnel.

Source: adapter/outbound/openvpn.go:40-73 · pinned at v1.19.31 (ab405ba)

Examples ​

Outbound — certificate authentication:

yaml
proxies:
  - name: ovpn-cert
    type: openvpn
    server: vpn.example.com
    port: 1194
    proto: udp
    cipher: AES-256-GCM
    auth: SHA256
    ca: |
      -----BEGIN CERTIFICATE-----
      <ca-certificate>
      -----END CERTIFICATE-----
    cert: |
      -----BEGIN CERTIFICATE-----
      <client-certificate>
      -----END CERTIFICATE-----
    key: |
      -----BEGIN PRIVATE KEY-----
      <client-private-key>
      -----END PRIVATE KEY-----
    udp: true

Outbound — username/password authentication with keepalive:

yaml
proxies:
  - name: ovpn-userpass
    type: openvpn
    server: vpn.example.com
    port: 1194
    proto: tcp
    ca: |
      -----BEGIN CERTIFICATE-----
      <ca-certificate>
      -----END CERTIFICATE-----
    username: <username>
    password: <password>
    ping: 10
    ping-restart: 60
    udp: true

Notes ​

  • proto selects the link transport: udp (default) or tcp.
  • Data-channel cipher selection follows OpenVPN 2.5+ semantics: data-ciphers is the negotiation offer (sent as IV_CIPHERS), and the negotiated cipher is the first server-pushed entry that also appears in it. data-ciphers-fallback covers servers that cannot negotiate. When data-ciphers is unset, the single cipher value (default AES-128-GCM) is used.
  • ca is required. cert + key provide certificate authentication; username + password provide auth-user-pass authentication. They can be combined when the server requires both. All key material is given inline (YAML block scalar) — file paths are not read.
  • The three control-channel wrappers are mutually exclusive: tls-auth (HMAC-authenticates the control channel; pair with key-direction: 0|1 for directional keys), tls-crypt (encrypts and authenticates it with a shared static key), and tls-crypt-v2 (per-client wrapped key, supplied as the inline PEM client key).
  • The tls-auth HMAC uses the auth digest (default SHA256), as OpenVPN itself does. If the server runs OpenVPN's default auth SHA1, set auth: SHA1 explicitly.
  • peer-info adds custom key/value pairs (e.g. IV_HWADDR, UV_*) after the built-in IV_VER / IV_PROTO / IV_CIPHERS entries the client sends during key exchange. A user-supplied IV_VER replaces the built-in value; IV_PROTO / IV_CIPHERS are always generated and cannot be overridden.
  • handshake-timeout bounds how long tunnel establishment may take; 0 (the default) waits indefinitely.
  • ping sends a keepalive at the given interval; ping-restart tears the tunnel down after that many seconds with no received packet so it can be re-established. Both are expressed in seconds.
  • tran-window keeps the previous data key alive for that many seconds after a rekey so in-flight packets still decrypt; leave it unset (3600 s) unless the server uses a non-default --tran-window.
  • mtu sets the tunnel MTU and defaults to 1500.
  • remote-dns-resolve routes destination-name lookups through the tunnel using the servers listed in dns; it has no effect unless dns is non-empty.

Cross-core notes ​

  • Xray-core has no OpenVPN support — to bridge an OpenVPN endpoint with Xray you would run a separate OpenVPN client and point a socks/http or TUN inbound at it. sing-box implements OpenVPN as endpoints rather than an outbound (openvpn-client and openvpn-server, compatible with standard OpenVPN peers), plus an openvpn DNS server that uses the DNS options the server pushes. See OpenVPN — sing-box.

Source: adapter/outbound/openvpn.go:40-73 · v1.19.31 (ab405ba)

Core Tutorial by Argsment