Skip to content

OpenVPN — sing-box ​

sing-box speaks OpenVPN natively through two endpoints — openvpn-client and openvpn-server under endpoints[] — plus an openvpn DNS server that resolves through the resolvers a server pushes to the client. Both endpoints interoperate with standard OpenVPN peers, including static-key mode, legacy ciphers and digests, and OpenVPN-style certificate checks.

Build tags

OpenVPN is only compiled in with the with_openvpn build tag; the default internal network stack (system: false) also needs with_gvisor. Without them the endpoints and the DNS server fail at startup with a rebuild hint.

Shared interface fields ​

Both endpoints embed these fields:

FieldTypeDefaultAllowed valuesDescription
systemboolfalsetrue | falseUse a system interface (needs privileges and must not clash with an existing interface). Addresses and MTU are configured on it, but no operating-system routes or DNS. false uses the internal network stack.
namestring(auto, ovpn…)<interface name>Interface name when system is true.
mtuuint321500<bytes>Tunnel interface MTU. On the client, 1500 is used until the server pushes a value.
udp_mappingUDPNATBehaviorendpoint_independentendpoint_independent | address_dependent | address_and_port_dependentUDP NAT mapping: reuse one mapping per source address and port for all destinations (default), or a separate mapping per destination address / address and port.
udp_filteringUDPNATBehaviorendpoint_independentendpoint_independent | address_dependent | address_and_port_dependentUDP NAT filtering: accept packets from any remote endpoint (default), or only from addresses / address-and-port pairs already sent to.
udp_nat_maxuint320 (auto)<uint32>Maximum number of UDP NAT sessions; the least recently used one is closed when full. 0 means 4096 on iOS, otherwise 4096–16384 based on total memory.

Source: option/openvpn.go:10-17 · pinned at v1.14.2 (af6e64c)

Client endpoint (openvpn-client) ​

type: "openvpn-client" under endpoints[]. Besides the fields below it takes server / server_port (conflicting with servers) and the dial fields, which apply to the connection to the OpenVPN server.

Connection and addressing ​

FieldTypeDefaultAllowed valuesDescription
modestringtlstls | static_keySession mode. static_key is a deprecated compatibility mode without a TLS control channel or forward secrecy; it ignores tls, username/password, pulled options and renegotiation.
networkstringudpudp | tcp | udp4 | udp6 | tcp4 | tcp6Default transport to the server. Applies to server and to servers entries without their own network.
servers[]OpenVPNRemoteOptions[][{server, server_port, network}]Servers tried in order, moving on when a connection fails. Each entry needs server and server_port and may override network. Conflicts with the top-level server; one of the two is required.
remote_randomboolfalsetrue | falseShuffle servers before connecting.
addressbadoption.Listable[netip.Prefix][][<CIDR>]Local IPv4 / IPv6 tunnel prefixes. Required in static_key mode; optional in TLS mode, where the server can push them.
peer_address*badoption.Addr(unset)<IPv4>IPv4 tunnel peer and VPN gateway. Required with an IPv4 address in static_key mode.
peer_address_ipv6*badoption.Addr(unset)<IPv6>IPv6 tunnel peer and VPN gateway. Required with an IPv6 address in static_key mode.
topologystring(pushed)net30 | p2p | subnetTunnel topology. Empty uses the topology pushed by the server in TLS mode.
udp_timeoutUDPTimeoutCompat5m<duration>UDP NAT session timeout for traffic through the tunnel.
explicit_exit_notifyuint320<count>Number of exit notifications sent one second apart when closing a UDP connection. 0 disables them.

Source: option/openvpn.go:19-73 · pinned at v1.14.2 (af6e64c)

Authentication and keys ​

FieldTypeDefaultAllowed valuesDescription
usernamestring(unset)<string>Username for OpenVPN username/password authentication. TLS mode only.
passwordstring(unset)<string>Password for username/password authentication.
auth_retrystringnonenone | nointeract | interactBehaviour after an authentication failure: none treats it as final; nointeract and interact allow retries.
static_challengestring(unset)<text>Static challenge text shown when an authentication response (for example a one-time code) is requested.
static_challenge_echoboolfalsetrue | falseShow the static-challenge response as plain text while it is entered.
static_keybadoption.Listable[string](unset)<key content>OpenVPN static key content. Required in static_key mode unless static_key_path is set; conflicts with it.
static_key_pathstring(unset)<path>Path to the OpenVPN static key file. Conflicts with static_key.
key_directionstring(bidirectional)server | clientStatic key direction, static_key mode only. Empty uses the key in both directions.
tls*OpenVPNOutboundTLSOptions(required in tls mode)OpenVPNOutboundTLSOptionsControl-channel TLS configuration; see the tls table below.

Source: option/openvpn.go:19-73 · pinned at v1.14.2 (af6e64c)

Data channel ​

FieldTypeDefaultAllowed valuesDescription
cipherstringBF-CBC<cipher name>Data-channel cipher for static_key mode only. The upstream default BF-CBC is a legacy 64-bit-block cipher — set the server's cipher explicitly. NONE gives no confidentiality.
data_ciphersbadoption.Listable[string]AES-256-GCM, AES-128-GCM, CHACHA20-POLY1305[<cipher name>]Data-channel ciphers allowed during negotiation. TLS mode only. Legacy CBC / CFB / OFB ciphers and NONE exist but are not enabled by default.
data_ciphers_fallbackstring(disabled)<cipher name>Cipher used with servers that cannot negotiate one. TLS mode only.
authstringSHA1<digest name>Data-channel HMAC digest. Only applies to non-AEAD ciphers and tls_auth; legacy digests such as MD5 and RIPEMD160 are accepted when set explicitly.
mss_fixuint32(OpenVPN default)<bytes>Maximum OpenVPN packet size used to clamp the MSS of TCP connections in the tunnel. Empty uses the upstream default: fragment if set, otherwise 1492 or the configured tunnel MTU.
mss_fix_disabledboolfalsetrue | falseDisable MSS clamping, including the default clamp. Conflicts with mss_fix and mss_fix_mode.
mss_fix_modestring(encapsulation-aware)mtu | fixedHow an explicit mss_fix is interpreted: mtu also counts the outer IP and UDP/TCP headers; fixed treats it as an inner IPv4 packet size. Requires mss_fix.
fragmentuint3200 | >= 68Maximum UDP packet size for OpenVPN's own data-channel fragmentation. 0 disables it; not allowed with a TCP transport.
replay_windowuint3264<= 65536UDP data-channel replay window size. TCP always requires consecutive packet IDs.
replay_window_timebadoption.Duration15s<= 10m, whole secondsUDP data-channel replay window duration.
compressionstring(disabled)none | no | lz4 | lz4-v2 | stub | stub-v2 | disabled | offOpenVPN compress framing. Compression can weaken confidentiality; prefer stub / stub-v2 when only framing compatibility is needed.
compression_lzostring(disabled)none | no | yes | adaptive | asym | disabled | offOpenVPN comp-lzo mode. Enable it only when the server requires it.
allow_compressionstringnono | asym | yesPolicy for compression pushed by the server: no allows only stub framing; asym accepts compressed packets but never compresses outgoing ones; yes is a legacy alias for asym.

Source: option/openvpn.go:19-73 · pinned at v1.14.2 (af6e64c)

Pushed options and routing ​

FieldTypeDefaultAllowed valuesDescription
route_no_pullboolfalsetrue | falseIgnore routes, DNS / DHCP options, route metrics, redirect-gateway, redirect-private, block-ipv6 and block-outside-dns pushed by the server. Addressing, topology and MTU are still applied.
pull_filters[]OpenVPNPullFilterOptions[][{action, text}]Ordered filters for pushed options; see the pull_filters[] table below.
routesbadoption.Listable[netip.Prefix][][<CIDR>]Extra prefixes preferred for this endpoint in sing-box routing, on top of routes accepted from the server. No operating-system routes are installed.
route_gateway*badoption.Addr(pushed gateway)<IPv4>IPv4 gateway for routes through the endpoint. Kept for OpenVPN compatibility; route preference is prefix-based.
route_metricint0<int>Default route metric. Kept for OpenVPN compatibility; no system route is installed.
redirect_gatewayboolfalsetrue | falsePrefer this endpoint for all IPv4 destinations in sing-box routing. No operating-system default route is installed.
redirect_gateway_flagsbadoption.Listable[string][]!ipv4 | def1 | ipv6 | local | autolocalOpenVPN redirect-gateway flags: !ipv4 drops the IPv4 preference, def1 expresses it as two /1 prefixes, ipv6 also prefers IPv6. block-local is unsupported; bypass-dhcp / bypass-dns do not apply.
redirect_privateboolfalsetrue | falseAccept redirect_gateway_flags without adding a default-route preference.
block_ipv6boolfalsetrue | falseReject IPv6 traffic locally instead of sending it through the VPN.

Source: option/openvpn.go:19-73 · pinned at v1.14.2 (af6e64c)

Timers and renegotiation ​

FieldTypeDefaultAllowed valuesDescription
ping_intervalbadoption.Duration(disabled)<duration>Send a data-channel ping after this long without sending to the server. A server-pushed ping overrides it. Whole seconds.
ping_restartbadoption.Duration120s (UDP, pull)<duration>Reconnect after this long without receiving a packet. A server-pushed ping-restart overrides it; TCP has no default. Whole seconds.
ping_restart_disabledboolfalsetrue | falseDisable the initial 120s UDP pull timeout and any local ping_restart. Conflicts with ping_restart.
renegotiate_intervalbadoption.Duration1h<duration>TLS renegotiation interval.
renegotiate_disabledboolfalsetrue | falseDisable time-based TLS renegotiation, including the default interval. Conflicts with renegotiate_interval.
renegotiate_bytesuint640<bytes>Renegotiate data-channel keys after this many bytes. 0 uses the cipher-dependent OpenVPN default.
renegotiate_packetsuint640<packets>Renegotiate data-channel keys after this many packets. 0 uses the cipher-dependent OpenVPN default.
tls_timeoutbadoption.Duration2s<duration>Initial retransmission timeout for TLS control packets.
handshake_windowbadoption.Duration1m<duration>Maximum time for the initial TLS handshake and each renegotiation.

Source: option/openvpn.go:19-73 · pinned at v1.14.2 (af6e64c)

pull_filters[] ​

FieldTypeDefaultAllowed valuesDescription
actionstring(required)accept | ignore | rejectaccept applies the matched option, ignore discards it, reject terminates the connection.
textstring(required)<prefix>Case-sensitive prefix of the complete pushed option. The first matching filter wins; unmatched options are accepted. "route " matches pushed IPv4 routes but not route-gateway.

Source: option/openvpn.go:117-120 · pinned at v1.14.2 (af6e64c)

tls ​

FieldTypeDefaultAllowed valuesDescription
server_namestring(unset)<name>Expected server certificate name. Empty disables the name check; the chain or fingerprint and the certificate purpose are still verified.
server_name_typestringnamesubject | name | name-prefixCertificate field matched by server_name: the full subject, the exact common name, or a common-name prefix.
certificatebadoption.Listable[string](unset)<PEM>Trusted CA certificate content. One of certificate, certificate_path or peer_fingerprint is required; conflicts with certificate_path.
certificate_pathstring(unset)<path>Trusted CA certificate path. Conflicts with certificate.
client_certificatebadoption.Listable[string](unset)<PEM>Client certificate content; set it together with a client key. Conflicts with client_certificate_path.
client_certificate_pathstring(unset)<path>Client certificate path. Conflicts with client_certificate.
client_keybadoption.Listable[string](unset)<PEM>Client private key content. Conflicts with client_key_path.
client_key_pathstring(unset)<path>Client private key path. Conflicts with client_key.
peer_fingerprintbadoption.Listable[string][][<64 lowercase hex chars>]Allowed SHA-256 fingerprints of the server leaf certificate. With a trusted CA both are checked; without one the chain itself is not verified.
crl_pathstring(unset)<path>PEM or DER certificate revocation list used to reject revoked server certificates.
remote_certificate_kubadoption.Listable[string][][<hex mask>]Required key-usage masks in OpenVPN remote-cert-ku format; the certificate must contain all bits of at least one mask.
remote_certificate_ekustring(unset)<OID or name> | server | clientRequired extended key usage. Replaces the default remote_certificate_tls check and conflicts with an explicit one.
remote_certificate_tlsstringserverserver | client | noneCertificate purpose check on the server certificate; none disables it.
certificate_profilestringlegacyinsecure | legacy | preferred | suitebCertificate strength profile: insecure also accepts MD5 / SHA-1 chains and small keys, legacy accepts SHA-1 but not MD5, preferred requires stronger signatures and keys, suiteb defaults the TLS 1.2 ciphers to Suite B.
ns_certificate_typestring(disabled)server | clientDeprecated Netscape certificate type check. Prefer remote_certificate_tls.
version_minstring1.21.0 | 1.1 | 1.2 | 1.3Minimum TLS version.
version_maxstring(highest supported)1.0 | 1.1 | 1.2 | 1.3Maximum TLS version; cannot be lower than version_min.
cipherstring(default suites)<OpenSSL names, colon-separated>Cipher suites for TLS 1.2 and earlier. TLS 1.3 suites are not affected.
groupsstring(default groups)X25519 | SECP256R1 | SECP384R1 | SECP521R1Key-exchange groups in preference order, colon-separated.
control_wrap*OpenVPNControlWrapOptions(disabled)OpenVPNControlWrapOptionsControl-channel wrapping (tls-auth / tls-crypt / tls-crypt-v2); see the next table.

Source: option/openvpn.go:122-143 · pinned at v1.14.2 (af6e64c)

tls.control_wrap ​

FieldTypeDefaultAllowed valuesDescription
typestring(required when set)tls_auth | tls_crypt | tls_crypt_v2Wrapping type, matching OpenVPN tls-auth, tls-crypt and tls-crypt-v2.
keybadoption.Listable[string](unset)<key content>Wrapping key content. Conflicts with key_path.
key_pathstring(unset)<path>Wrapping key path. Conflicts with key.
directionstring(bidirectional)server | clienttls_auth key direction; only with type tls_auth. Empty uses the key in both directions.

Source: option/openvpn.go:169-174 · pinned at v1.14.2 (af6e64c)

Server endpoint (openvpn-server) ​

type: "openvpn-server" under endpoints[], plus the listen fields (listen, listen_port, and udp_timeout for UDP NAT sessions).

Session and addressing ​

FieldTypeDefaultAllowed valuesDescription
modestringtlstls | static_keySession mode. static_key serves a single peer without TLS or forward secrecy and ignores tls, users, push and renegotiation options.
networkstringudpudp | tcpTransport served by this endpoint. One network per endpoint — use two endpoints with separate address subnets to serve both.
remotestring(unset)<address>Fixed peer address for a UDP static_key server, required together with remote_port. TCP servers take the peer from the accepted socket.
remote_portuint16(unset)<port>Fixed peer port for a UDP static_key server.
max_clientsint1024< 16777216Maximum established plus pending TLS sessions. static_key mode supports one peer, so it must be 0 or 1 there.
addressbadoption.Listable[netip.Prefix](required)[<CIDR>]Server prefixes, at most one IPv4 and one IPv6. The prefix address goes on the server interface and the masked prefix becomes the client pool and route. In static_key mode these are the local tunnel prefixes.
peer_address*badoption.Addr(unset)<IPv4>IPv4 tunnel peer address. Required with an IPv4 address in static_key mode.
peer_address_ipv6*badoption.Addr(unset)<IPv6>IPv6 tunnel peer address. Required with an IPv6 address in static_key mode.
topologystringsubnet (tls) / p2p (static_key)subnet | p2p | net30Topology pushed to clients.
duplicate_cnboolfalsetrue | falseAllow several active clients with the same certificate common name or username. When off, a new session replaces the old one and reuses its address. TLS mode only.
users[]auth.User[][{username, password}]Username/password users. When set, clients must pass this check in addition to the certificate policy. TLS mode only.

Source: option/openvpn.go:75-110 · pinned at v1.14.2 (af6e64c)

Keys and data channel ​

FieldTypeDefaultAllowed valuesDescription
static_keybadoption.Listable[string](unset)<key content>OpenVPN static key content. Required in static_key mode unless static_key_path is set; conflicts with it.
static_key_pathstring(unset)<path>Path to the OpenVPN static key file. Conflicts with static_key.
key_directionstring(bidirectional)server | clientStatic key direction, static_key mode only. Conventionally the server uses server and the peer uses client.
tls*OpenVPNInboundTLSOptions(required in tls mode)OpenVPNInboundTLSOptionsControl-channel TLS configuration; see the server tls table below.
cipherstringBF-CBC<cipher name>Data-channel cipher for static_key mode only. BF-CBC is the legacy upstream default; NONE gives no confidentiality.
data_ciphersbadoption.Listable[string]AES-256-GCM, AES-128-GCM, CHACHA20-POLY1305[<cipher name>]Data-channel ciphers offered during negotiation. TLS mode only. Legacy ciphers exist but are not enabled by default.
data_ciphers_fallbackstring(disabled)<cipher name>Cipher for legacy clients that cannot negotiate one (OpenVPN data-ciphers-fallback). TLS mode only.
authstringSHA1<digest name>Data-channel HMAC digest, matching the upstream default. Only applies to non-AEAD ciphers and tls_auth.
mss_fixuint32(OpenVPN default)<bytes>Maximum encapsulated packet size used to clamp TCP MSS; the default calculation uses 1492 with the default MTU.
mss_fix_disabledboolfalsetrue | falseDisable MSS clamping, including the default clamp.
mss_fix_modestring(encapsulation-aware)mtu | fixedHow an explicit mss_fix is interpreted. Requires mss_fix.
replay_windowuint3264<= 65536UDP data-channel replay window size; TCP packet IDs stay strictly consecutive.
replay_window_timebadoption.Duration15s<duration>UDP replay window duration. Whole seconds.

Source: option/openvpn.go:75-110 · pinned at v1.14.2 (af6e64c)

Push and timers ​

FieldTypeDefaultAllowed valuesDescription
push*OpenVPNPushOptions(unset)OpenVPNPushOptionsOptions pushed to clients; see the push table below.
ping_intervalbadoption.Duration(disabled)<duration>Server side: send a ping after this long without sending to a client. Use push.ping_interval for clients. Whole seconds.
ping_restartbadoption.Duration(disabled)<duration>Server side: close a client session after this long without receiving from it. Keep it longer than the client's timeout. Whole seconds.
renegotiate_intervalbadoption.Duration1h<duration>TLS renegotiation interval. TLS mode only.
renegotiate_disabledboolfalsetrue | falseDisable time-based TLS renegotiation, including the default interval. TLS mode only.
renegotiate_bytesuint640<bytes>Renegotiate data-channel keys after this many bytes; 0 uses the cipher-dependent default. TLS mode only.
renegotiate_packetsuint640<packets>Renegotiate data-channel keys after this many packets; 0 uses the cipher-dependent default. TLS mode only.
handshake_windowbadoption.Duration1m<duration>Maximum time for the initial TLS handshake and each renegotiation. TLS mode only.

Source: option/openvpn.go:75-110 · pinned at v1.14.2 (af6e64c)

tls ​

FieldTypeDefaultAllowed valuesDescription
certificatebadoption.Listable[string](required)<PEM>Server certificate content. certificate or certificate_path is required; they conflict.
certificate_pathstring(required)<path>Server certificate path. Conflicts with certificate.
keybadoption.Listable[string](required)<PEM>Server private key content. key or key_path is required; they conflict.
key_pathstring(required)<path>Server private key path. Conflicts with key.
client_certificatebadoption.Listable[string](unset)<PEM>CA certificate content used to verify client certificates. With verify_client_certificate require or optional, one of client_certificate, client_certificate_path or peer_fingerprint is required.
client_certificate_pathstring(unset)<path>CA certificate path used to verify client certificates. Conflicts with client_certificate.
verify_client_certificatestringrequirerequire | optional | noneClient certificate policy: optional verifies a certificate when one is presented, none does not request one. users are still checked when set.
client_namestring(unset)<name>Expected client certificate name. Empty disables the check.
client_name_typestringnamesubject | name | name-prefixCertificate field matched by client_name.
peer_fingerprintbadoption.Listable[string][][<64 lowercase hex chars>]Allowed SHA-256 fingerprints of client leaf certificates; works without a client CA.
crl_pathstring(unset)<path>Certificate revocation list used to reject revoked client certificates.
remote_certificate_kubadoption.Listable[string][][<hex mask>]Required client key-usage masks in OpenVPN remote-cert-ku format.
remote_certificate_ekustring(unset)<OID or name> | server | clientRequired client extended key usage. Conflicts with an explicit remote_certificate_tls.
remote_certificate_tlsstringclientserver | client | noneCertificate purpose check on client certificates; none disables it.
certificate_profilestringlegacyinsecure | legacy | preferred | suitebCertificate strength profile, same meaning as on the client.
ns_certificate_typestring(disabled)server | clientDeprecated Netscape certificate type check.
version_minstring1.21.0 | 1.1 | 1.2 | 1.3Minimum TLS version.
version_maxstring(highest supported)1.0 | 1.1 | 1.2 | 1.3Maximum TLS version.
cipherstring(default suites)<OpenSSL names, colon-separated>Cipher suites for TLS 1.2 and earlier. TLS 1.3 suites are not affected.
groupsstring(default groups)X25519 | SECP256R1 | SECP384R1 | SECP521R1Key-exchange groups in preference order, colon-separated.
control_wrap*OpenVPNInboundControlWrapOptions(disabled)OpenVPNInboundControlWrapOptionsControl-channel wrapping; see the next table.

Source: option/openvpn.go:145-167 · pinned at v1.14.2 (af6e64c)

tls.control_wrap ​

FieldTypeDefaultAllowed valuesDescription
typestring(required)tls_auth | tls_crypt | tls_crypt_v2Wrapping type. For tls_crypt_v2 the key is the server key.
keybadoption.Listable[string](unset)<key content>Wrapping key content. key or key_path is required; they conflict.
key_pathstring(unset)<path>Wrapping key path. Conflicts with key.
directionstring(bidirectional)server | clienttls_auth key direction: server maps to OpenVPN key-direction 0, client to 1. Empty uses the key in both directions.
force_cookieboolfalsetrue | falsetls_crypt_v2 only: require UDP clients to support stateless session cookies. When off, clients without cookie support are still accepted.

Source: option/openvpn.go:176-182 · pinned at v1.14.2 (af6e64c)

push ​

FieldTypeDefaultAllowed valuesDescription
routesbadoption.Listable[netip.Prefix][][<CIDR>]Routes pushed to clients; IPv4 and IPv6 may be mixed.
dnsbadoption.Listable[netip.Addr][][<IP>]DNS servers pushed as legacy dhcp-option DNS / DNS6. A pushed modern server group overrides them on compatible clients.
dns_servers[]OpenVPNPushDNSServerOptions[][{priority, addresses, resolve_domains, dnssec, transport, sni}]Modern DNS server groups. addresses take IP or IP:port ([IPv6]:port); transport is plain, dot or doh; dnssec is yes, optional or no. Clients use only the group with the lowest priority number.
search_domainsbadoption.Listable[string][][<domain>]Modern search domains to push.
dhcp_optionsbadoption.Listable[string][][<option>]Extra legacy dhcp-option values, without the dhcp-option prefix.
redirect_gatewayboolfalsetrue | falsePush redirect-gateway so clients route their traffic through the VPN.
redirect_gateway_flagsbadoption.Listable[string]def1[<flag>]redirect-gateway flags to push; only used with redirect_gateway.
block_outside_dnsboolfalsetrue | falsePush block-outside-dns, which blocks DNS outside the VPN on Windows clients.
ping_intervalbadoption.Duration(disabled)<duration>OpenVPN ping interval pushed to clients. Whole seconds.
ping_restartbadoption.Duration(disabled)<duration>OpenVPN ping-restart timeout pushed to clients. Whole seconds.

Source: option/openvpn.go:184-195 · pinned at v1.14.2 (af6e64c)

DNS server (openvpn) ​

type: "openvpn" under dns.servers[]:

FieldTypeDefaultAllowed valuesDescription
endpointstring(required)<openvpn-client tag>Tag of the openvpn-client endpoint whose pushed resolvers are used. Queries are sent through that endpoint.
accept_default_resolversboolfalsetrue | falseUse the pushed resolvers for queries that match no pushed resolve-domains, DOMAIN-ROUTE or search-domain suffix. When off, such queries get NXDOMAIN.
accept_search_domainboolfalsetrue | falseRetry single-label queries (such as intranet) with each pushed search domain until one resolves.

Source: option/openvpn.go:206-210 · pinned at v1.14.2 (af6e64c)

Examples ​

Client with certificate authentication and tls-crypt, routing one subnet through the tunnel and resolving the server's internal names through the pushed resolvers:

json
{
  "endpoints": [
    {
      "type": "openvpn-client",
      "tag": "ovpn-client",
      "server": "vpn.example.com",
      "server_port": 1194,
      "network": "udp",
      "tls": {
        "certificate_path": "/etc/openvpn/ca.crt",
        "client_certificate_path": "/etc/openvpn/client.crt",
        "client_key_path": "/etc/openvpn/client.key",
        "control_wrap": { "type": "tls_crypt", "key_path": "/etc/openvpn/tc.key" }
      }
    }
  ],
  "dns": {
    "servers": [
      { "type": "local", "tag": "local" },
      { "type": "openvpn", "tag": "ovpn-dns", "endpoint": "ovpn-client", "accept_default_resolvers": true }
    ],
    "rules": [
      { "preferred_by": "ovpn-dns", "action": "route", "server": "ovpn-dns" }
    ],
    "final": "local"
  },
  "route": {
    "rules": [
      { "ip_cidr": ["10.8.0.0/16"], "outbound": "ovpn-client" }
    ]
  }
}

Server on UDP 1194 that hands out 10.8.0.0/24 and pushes a default route:

json
{
  "endpoints": [
    {
      "type": "openvpn-server",
      "tag": "ovpn-server",
      "listen": "::",
      "listen_port": 1194,
      "network": "udp",
      "address": ["10.8.0.1/24"],
      "tls": {
        "certificate_path": "/etc/openvpn/server.crt",
        "key_path": "/etc/openvpn/server.key",
        "client_certificate_path": "/etc/openvpn/ca.crt",
        "control_wrap": { "type": "tls_crypt", "key_path": "/etc/openvpn/tc.key" }
      },
      "push": {
        "redirect_gateway": true,
        "dns": ["1.1.1.1"]
      }
    }
  ]
}

Notes ​

  • Endpoints sit under endpoints[] and are selected by tag in route rules, just like outbounds. Neither endpoint installs operating-system routes or DNS settings: routes, redirect_gateway and pushed routes only shape which destinations sing-box prefers to send through the endpoint.
  • The client's dial fields apply to its connection to the OpenVPN server; that control connection never follows the endpoint's own routes, so the redirect-gateway flags local / autolocal need no route exception.
  • static_key mode exists only for compatibility with peers that cannot be upgraded — it has no TLS control channel and no forward secrecy. Prefer tls.
  • Interactive authentication (challenge / response, auth_retry: "interact") is completed through the sing-box graphical clients or the Dashboard, under Tools › Endpoints.
  • DNS options pushed by the server are never written into the operating system. Use the openvpn DNS server to consume them: only the pushed server group with the lowest priority number is active, legacy dhcp-option DNS is used when no modern group exists, and a group that requires DNSSEC (dnssec yes) is rejected because this transport does not validate DNSSEC.
  • Durations such as ping_interval, ping_restart and replay_window_time must be whole seconds.

Cross-core notes ​

  • mihomo has an OpenVPN client only: a type: openvpn outbound whose keys mirror .ovpn directives (ca / cert / key, tls-auth / tls-crypt, username / password, …). It has no OpenVPN server. mihomo defaults auth to SHA256 while sing-box follows upstream OpenVPN's SHA1 — set auth explicitly on both sides when mixing implementations. See OpenVPN — mihomo.
  • Xray-core has no OpenVPN support.

Source: option/openvpn.go:10-210 · v1.14.2 (af6e64c)

Core Tutorial by Argsment