OCSERV(8)

πŸ’– ocserv β€” the OpenConnect VPN server, bestie edition πŸ’–

okay so. this is OCSERV(8), from the System Manager's Manual, and it's genuinely one of the most iconic server pages out there. sit down, grab a strawberry πŸ“, and let's get into it.


✨ NAME ✨

ocserv β€” OpenConnect VPN server. that's it, that's the name. πŸ’…


✨ SYNOPSIS ✨

ocserv [ -flag [value] | --option-name[[=| ]value] ]...

OpenConnect VPN server (ocserv) is a VPN server that's compatible with the OpenConnect VPN client. it follows the AnyConnect VPN protocol, which, no cap, is used by several CISCO routers. so like, it's not niche, it's literally industry girlie. πŸ‘‘


✨ DESCRIPTION ✨

okay so this is a standalone server. it reads a configuration file (more on that below, bestie, keep reading 🫢) and then it just… waits. patiently. for client connections. main character energy but make it ✨humble✨. log messages get sent to the syslog daemon facility.

so here's the tea on the connections, because there are TWO of them, it's giving situationship:

  • the main VPN channel is established over TCP, using HTTP and TLS. this is the control channel AND the backup data channel. dual purpose icon.
  • after that gets established, a UDP channel using DTLS is initiated, and that serves as the main data channel. the upgrade era. πŸ¦‹
  • and if the UDP channel fails to establish, or is temporarily unavailable? the backup channel over TCP/TLS is being used. she's always got a backup plan, we love a resilient queen. πŸ’…

this server supports multiple authentication methods, including PAM and certificate authentication. authenticated users get assigned an unprivileged worker process and they obtain a networking (tun) device and an IP from a configurable pool of addresses. like, you get your own lil corner of the internet. obsessed. 🌸

once authenticated, the server gives the client an IP address and a list of routes that it may access. and the way that it allows high-speed transfers? it does not process or filter packets. periodt. it's expected that the server has or will set up any required routes or firewall rules. so like, do your homework, bestie, that part is on you. 🫢

groups are also a thing! it's possible to separate users into groups, which are either present on their certificate, or presented on login for the user to choose. that way a user may take advantage of the different settings that may apply per group. see the comments on the configuration file for more info, iykyk. πŸ’…

and hostname-based virtual servers?? yes. it's also possible to run those, and they could support different authentication methods. when multiple virtual servers are present, clients are distinguished by the advertised server name over TLS (SNI). clients which do not support or sent SNI, are directed to the default server. no SNI, no drama, you go to the default. πŸ’€


✨ OPTIONS ✨

  • -f, --foreground β€” do not fork server into background. she stays right here, in the foreground, watching. πŸ‘€
  • -d, --debug=num β€” enable verbose network debugging information. num must be between zero and 9999. so many numbers, so much lore.
  • -c, --config=FILE β€” specify the configuration file for the server. the default is /etc/ocserv/ocserv.conf. that's home base, bestie. 🏠
  • -t, --test-config β€” test the provided configuration file and exit. a successful exit error code indicates a valid configuration. vibe check for your config ✨
  • -p, --pid-file=FILE β€” specify a PID file for the server. this option is also available as the configuration file key pid-file. two ways to do the same thing, we love options. πŸŽ€
  • -e, --log-stderr β€” log to stderr. straight to the terminal, no filter. πŸ—£οΈ
  • -s, --syslog β€” log to syslog (default). the classic route. πŸ‘‘
  • --syslog-facility=NAME β€” set the syslog facility used when logging to syslog. NAME must be one of: daemon (default), user, auth, authpriv, local0 … local7. this option is also available as the configuration file key syslog-facility. pick your lane πŸ’…
  • --no-chdir β€” do not perform a chdir on daemonize. she stays in her directory, she's comfortable. πŸ›‹οΈ
  • -x, --traceable β€” allows the process to be traced and dumped. use for debugging purposes only. fr fr, this one's for debugging, not for your everyday lewk. πŸ™ˆ
  • -h, --help β€” display usage information and exit. the classic. 🫢
  • -v, --version β€” output version of program and exit. know your girlies. ⭐

✨ CONFIGURATION ✨

okay so every configuration option has a scope, and that scope determines where it may appear. it's giving ✨hierarchy✨.

Scope takes one of three values:

  • global β€” the option applies to the entire server and may only appear at the top level of the configuration file. placing it inside a [vhost:] section is a configuration error that prevents the server from starting (e.g. max-clients, device, route-add-cmd). not me putting a global in a vhost… πŸ’€ don't do it.
  • vhost β€” the option may appear at the top level applying as a default for all virtual hosts, or inside a specific [vhost:] (e.g. tls-priorities, banner, cookie-timeout). she's flexible like that. πŸ¦‹
  • vhost user β€” the option may appear at the top level, in a [vhost:] section, and also in per-user or per-group supplemental configuration files (e.g. routes, iroutes, no-udp). the triple threat. πŸ‘‘

the description of each option in the configuration file carries a [scope:] annotation that identifies its scope. so like, read the labels, bestie, they're there for you. 🏷️

furthermore, certain configuration options specified are not-reloadable and a change only takes effect when restarting the server. these options are marked as (non-reloadable) in their scope annotation. no soft launches, you gotta do a full restart. 😀


🌸 PER-USER AND PER-GROUP CONFIGURATION 🌸

options with vhost user scope may be further overridden for individual users or groups through supplemental INI-format configuration files. the relevant directories are set with config-per-user and config-per-group in the main configuration file. ✨

when a user connects, ocserv looks for a file named after their username in the per-user directory and a file named after their group in the per-group directory. values found there override the corresponding values from the active virtual host configuration for that session only; they do not affect other connected users. very personal, very bespoke, very much for you. πŸ’…

Ocserv rereads these files when the user is connected, so there is no need to reload ocserv after you modify per-user or per-group configuration. the way that it just picks up your changes automatically?? iconic. no reload needed, we love a low-maintenance situation. πŸŽ€

options not specified within a virtual host, or within a per-user/group file, fall back to the global configuration value, or to the built-in default if not set globally. fallback chain, bestie. she always has somewhere to land. 🫢


πŸ¦‹ VIRTUAL HOSTS πŸ¦‹

Ocserv supports virtual hosts, allowing a single instance to serve multiple domains with different configurations. this feature operates similarly to virtual hosts in Apache or Nginx β€” when clients connect requesting a specific domain name (via TLS SNI), the server selects the corresponding virtual host configuration. if no matching virtual host is found, the connection falls back to the global configuration. 😌

virtual host sections are introduced in the configuration file with a header of the form:

[vhost:www.example.com]

all options that follow (until the next section header or end of file) apply only to that virtual host. scoped. contained. focused. ✨

πŸ” AUTHENTICATION πŸ”

okay bestie, there's not just ONE way to log in, there are multiple, and we're gonna go through every single one. if you need to manage peeps who are already connected, that's what the occtl tool is for. πŸ’…

πŸ”‘ Password authentication

if your system has Pluggable Authentication Modules (PAM) on it, then ocserv is gonna use that to password-authenticate everyone. no PAM? no problem, there's also a plain password file, basically a UNIX password file situation, and you manage it with the ocpasswd tool. πŸ’–

heads up bestie: password authentication can be used together with certificate authentication. they're not mutually exclusive, they're a collab. ✨

🎫 GSSAPI authentication

ocserv will happily use the MIT Kerberos project GSSAPI libraries and let you authenticate with literally any method GSSAPI supports β€” which, mainly, is Kerberos authentication. and the way that it's often more useful is combined with PAM or other password auth methods, so you get a fallback mechanism for when GSSAPI fails (like, say, when the user doesn't already have a Kerberos ticket, embarrassing for them). the GSSAPI authentication is implemented using SPNEGO over HTTP (RFC4559). πŸŽ€

πŸͺͺ Public key (certificate) authentication

public key auth means the user gets authenticated by possessing the private key that matches a public key the server already knows about. which means: yes, you can use common smart cards for user authentication. iconic honestly. πŸ‘‘

in ocserv, a certificate authority (CA) is used to sign the client certificates. that CA can be local β€” used only by the server to sign its users' known public keys, which then get handed to users in the form of certificates. that authority also needs to provide a CRL so the server can reject revoked clients (see ca-cert, crl). 🚫

in certificate authentication, each client presents a certificate and signs data provided by the server, as part of TLS authentication, to prove they possess the corresponding private key. the certificate also needs to contain user-identifying information β€” for example, the user ID of the client must be embedded in the certificate's Distinguished Name (DN), i.e., in the Common Name, or UID fields. for the server to actually read that name, the cert-user-oid configuration option must be set. no cap.

the following examples demonstrate how to use certtool from GnuTLS to generate such a CA. 🧚

πŸ—οΈ Generating the CA

$ certtool --generate-privkey --outfile ca-key.pem
$ cat << _EOF_ >ca.tmpl
cn = "VPN CA"
organization = "Big Corp"
serial = 1
expiration_days = -1
ca
signing_key
cert_signing_key
crl_signing_key
_EOF_

$ certtool --generate-self-signed --load-privkey ca-key.pem \
           --template ca.tmpl --outfile ca-cert.pem

πŸ–₯️ Generating a local server certificate

this next example generates the server key and certificate pair. the key generated here is an RSA one, but you can use different types by specifying the 'ecdsa' or 'dsa' options to certtool. 🌈

$ certtool --generate-privkey --outfile server-key.pem
$ cat << _EOF_ >server.tmpl
cn = "VPN server"
dns_name = "www.example.com"
dns_name = "vpn1.example.com"
#ip_address = "1.2.3.4"
organization = "MyCompany"
expiration_days = -1
signing_key
encryption_key #only if the generated key is an RSA one
tls_www_server
_EOF_

$ certtool --generate-certificate --load-privkey server-key.pem \
           --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem \
           --template server.tmpl --outfile server-cert.pem

from this point on, the clients need ca-cert.pem to be able to securely connect to the server. periodt. πŸ”’

real talk: it's a better practice to use two separate RSA keys β€” one with the signing_key option and another with the encryption_key. don't be lazy with your keys bestie. πŸ™ˆ

🌍 Generating an external CA-signed server certificate

$ certtool --generate-privkey --outfile server-key.pem
$ cat << _EOF_ >server.tmpl
cn = "My server"
dns_name = "www.example.com"
organization = "MyCompany"
expiration_days = -1
signing_key
encryption_key #only if the generated key is an RSA one
tls_www_server
_EOF_
$ certtool --generate-request --load-privkey server-key.pem \
           --template server.tmpl --outfile server-cert.csr

at this point you need to hand server-cert.csr over to your CA, and they'll send you back the server certificate. πŸ“¬

πŸ§‘πŸ’» Generating the client certificates

ngl, it's recommended to leave detailed personal information out of the certificate, because it gets sent in clear during TLS authentication. the following process generates a certificate and converts it to PKCS #12 that's protected by a PIN and that most clients can import. (the 3DES cipher is used in the example because it's supported by far more devices than AES β€” slay for compatibility. πŸ’…)

$ certtool --generate-privkey --outfile user-key.pem
$ cat << _EOF_ >user.tmpl
dn = "cn=Full Name,O=Example Org,UID=username"
#if usernames are SAN(rfc822name) email addresses
#email = "username@example.com"
expiration_days = 365
signing_key
tls_www_client
_EOF_
$ certtool --generate-certificate --load-privkey user-key.pem \
           --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem \
           --template user.tmpl --outfile user-cert.pem

$ certtool --to-p12 --load-privkey user-key.pem \
           --pkcs-cipher 3des-pkcs12 \
           --load-certificate user-cert.pem \
           --outfile user.p12 --outder

β›” Revoking a client certificate

to revoke that previous client certificate β€” i.e., stopping the user from accessing the VPN resources before their certificate expires β€” you use:

$ cat << _EOF_ >crl.tmpl
crl_next_update = 365
crl_number = 1
_EOF_
$ cat user-cert.pem >>revoked.pem
$ certtool --generate-crl --load-ca-privkey ca-key.pem \
           --load-ca-certificate ca-cert.pem --load-certificate revoked.pem \
           --template crl.tmpl --outfile crl.pem

after that, you may want to notify ocserv about the new CRL by using the HUP signal, or you can just wait for it to reload it. your call bestie. πŸ“£

and when there are no revoked certificates, an empty revocation list should be generated like this:

$ certtool --generate-crl --load-ca-privkey ca-key.pem \
           --load-ca-certificate ca-cert.pem \
           --template crl.tmpl --outfile crl.pem

πŸ“ FILES πŸ“

πŸ—‚οΈ ocserv's configuration file format

by default, if you don't specify another file, ocserv goes looking for its configuration file at /etc/ocserv/ocserv.conf. here's an example configuration file for you:

@CONFIGFILE@

🧠 IMPLEMENTATION NOTES 🧠

okay so, real talk: while this server utilizes privilege separation and all authentication occurs on the security module β€” due to a TLS protocol limitation, this does not apply for TLS client certificate authentication. 😭

so if you want to actually take advantage of privilege separation: combine certificate and password authentication. do both. be extra. πŸ’–


🌐 NETWORKING CONSIDERATIONS 🌐

in certain setups, where a firewall may be blocking ICMP responses, setting the MSS of TCP connections to MTU will eliminate the "black hole" connection issues. (yes, that's literally what it's called, and yes it's as dramatic as it sounds. πŸ’€)

see http://lartc.org/howto/lartc.cookbook.mtu-mss.html for instructions to enable it on a Linux system. πŸ”§


πŸ‘‘ AUTHORS πŸ‘‘

Written by Nikos Mavrogiannopoulos. Many people have contributed to it. (a whole village fr fr 🫢)


πŸ› REPORTING BUGS πŸ›

Issue tracker: https://gitlab.com/openconnect/ocserv/-/issues

go tell them, bestie, they wanna know. πŸ“


Copyright (C) 2013-2024 Nikos Mavrogiannopoulos and others, all rights reserved. This program is released under the terms of the GNU General Public License, version 2.


πŸ¦‹ SEE ALSO πŸ¦‹

occtl(8), ocpasswd(8), openconnect(8)

go read those too, iykyk. πŸ’œ


and that's the whole page bestie!! this was OCSERV(8), dated June 2026 β€” ty for reading all the way to the bottom, you're literally the main character of this manpage. go configure something iconic. βœ¨πŸ’…πŸŽ€

πŸ“¦ where this page comes from