TURN(1)
TURN(1) โ the turnserver glow-up ๐
okay bestie, sit down, hydrate, because we're about to read the turnserver manual together and it's genuinely a lot. this is the man page for the TURN server, and yes we're doing the whole thing, no skimming. ๐ซถ
GENERAL INFORMATION
so the TURN Server project is literally the source code for a TURN server and a TURN client messaging library. plus there are some extra little programs bundled in, and those are for testing only, okay? no main character energy for the test tools. ๐
if you wanna know how to build it, go look at the docs/Build.md file. that's your girl for building instructions. โจ
after the build, you get these binary images, and I'm listing every single one because we don't skip:
turnserver: the TURN Server relay itself. the compiled binary image of the TURN Server program lives in thebin/sub-directory.turnadmin: the TURN administration tool. peepREADME.turnadminand theturnadminman page.turnutils_uclient. seeREADME.turnutilsand theturnutilsman page.turnutils_peer. seeREADME.turnutilsand theturnutilsman page.turnutils_stunclient. seeREADME.turnutilsand theturnutilsman page.turnutils_rfc5769check. seeREADME.turnutilsand theturnutilsman page.
and in the examples/scripts sub-directory you'll find examples of command lines for running these programs. those scripts are meant to be run from the examples/ sub-directory, like:
$ cd examples $ ./scripts/secure_relay.sh
periodt. ๐
SYSTEMD
if the systemd development library is available, then it'll notify systemd about the server status. so it's keeping systemd in the loop, very communicative of it. ๐
RUNNING THE TURN SERVER
wanna run the coturn server as a daemon? use:
$ turnserver -o
note that if you make any changes to the config file, the server has to be restarted. no sneaky hot-reloading, bestie. ๐ญ
options note: turnserver has long and short option names, for most options. some options have only a long form, some options have only a short form. their syntax is somewhat different if an argument is required:
the short form must be used as this (for example):
$ turnserver -L 12.34.56.78
the long form equivalent must use the "=" character:
$ turnserver --listening-ip=12.34.56.78
if it's a flag option (no argument required) then their usage is the same, for example:
$ turnserver -a
is equivalent to:
$ turnserver --lt-cred-mech
โจ NAME โจ
turnserver โ a TURN relay server implementation. that's it, that's the vibe. ๐
๐ธ SYNOPSIS ๐ธ
$ turnserver [-n | -c <config-file> ] [flags] [ --userdb=<userdb-file> | --psql-userdb=<db-conn-string> | --mysql-userdb=<db-conn-string> | --mongo-userdb=<db-conn-string> | --redis-userdb=<db-conn-string> ] [-z | --no-auth | -a | --lt-cred-mech ] [options]
$ turnserver -h
๐ฆ DESCRIPTION ๐ฆ
config file settings:
-nโ do not use a configuration file, use only command line parameters. it's giving "I don't trust files, I say what I mean." ๐-cโ configuration file name (default isturnserver.conf). the format of the config file can be seen in the suppliedexamples/etc/turnserver.confexample file. long names of the options are used as the configuration items names in the file. if it's not an absolute path you supplied, then the file gets searched in these directories, in order:- current directory
- current directory
etc/sub-directory - upper directory level
etc/ /etc//usr/local/etc/- installation directory
/etc
user database settings:
-b,--db,--userdbโ SQLite user database file name (default โ/var/db/turndbor/usr/local/var/db/turndbor/var/lib/turn/turndb).-e,--psql-userdb,--sql-userdbโ user database connection string for PostgreSQL. this database can be used for the long-term credentials mechanism, and it can store the secret value for secret-based timed authentication in TURN REST API. the connection string format is like that:
"host=<host> dbname=<dbname> user=<db-user> password=<db-user-password> connect_timeout=<seconds>" (for 8.x or newer Postgres).
or:
"postgresql://username:password@hostname:port/databasename" (for 9.x or newer Postgres).
see the docs/PostgreSQL.md file for more explanations and examples. and also, see http://www.PostgreSQL.org for the full PostgreSQL documentation. ๐
-M,--mysql-userdbโ user database connection string for MySQL or MariaDB. this database can be used for the long-term credentials mechanism, and it can store the secret value for secret-based timed authentication in TURN REST API. the connection string format is like that:
"host=<host> dbname=<dbname> user=<db-user> password=<db-user-password> connect_timeout=<seconds> read_timeout=<seconds>"
see the docs/MySQL.md file for more explanations and examples. also, see http://www.mysql.org or http://mariadb.org for the full MySQL documentation.
optional connection string parameters for secure communications (SSL): ca, capath, cert, key, cipher (see http://dev.mysql.com/doc/refman/5.1/en/ssl-options.html for the command options description).
--secret-key-fileโ this is the file path which contains the secret key of aes encryption while using MySQL password encryption. if you want to use the password in encrypted format in the MySQL connection string, then set in this option the file path of the secret key. the key which is used to encrypt the MySQL password. warning: if this option is set, then the MySQL password must be set in the"mysql-userdb"option in encrypted format! if you want to use a cleartext password, then do not set this option! ๐ณ-J,--mongo-userdbโ user database connection string for MongoDB. this database can be used for the long-term credentials mechanism, and it can store the secret value for secret-based timed authentication in TURN REST API. the connection string format is like that:
"mongodb://username:password@host:port/database?options"
see the docs/Mongo.md file for more explanations and examples. also, see http://docs.mongodb.org/manual/ for the full MongoDB documentation.
-N,--redis-userdbโ user database connection string for Redis. this database can be used for the long-term credentials mechanism, and it can store the secret value for secret-based timed authentication in TURN REST API. the connection string format is like that:
"ip=<ip-addr> dbname=<db-number> password=<db-password> connect_timeout=<seconds>"
if the TURN server was built with hiredis_ssl support, a TLS transport can be requested by adding "tls=true" plus, typically, a CA file: "... tls=true ca=<ca-cert-file>". server-certificate verification is on by default; see the docs/Redis.md file for the full list of TLS keys (ca, capath, cert, clientkey, sni, verify) and examples.
see the docs/Redis.md file for more explanations and examples. also, see http://redis.io for the full Redis documentation. ๐ฅ
flags:
-v,--verboseโ moderate verbose mode. chill, informative, cute.-V,--Verboseโ extra verbose mode, very annoying and not recommended. lowercasevand uppercaseVare literally different options, do not mix them up bestie ๐-o,--daemonโ run server as daemon.--no-software-attributeโ DEPRECATED. see"--software-attribute".--software-attributeโ sendSOFTWARE_ATTRIBUTEon messages that can have it. disabled by default. equals to deprecated option"--no-software-attribute false".-f,--fingerprintโ use fingerprints in the TURN messages. if an incoming request contains a fingerprint, then the TURN server will always add fingerprints to the messages in this session, regardless of the per-server setting. committed to the bit, honestly. ๐--include-reason-stringโ include descriptive reason strings in STUN/TURN error responses. by default, only the standard reason phrase for the error code is sent. enabling this option adds detailed error descriptions which may aid debugging but can also leak internal server information. so like, helpful but oversharing. ๐-a,--lt-cred-mechโ use long-term credentials mechanism (this one you need for WebRTC usage). yes, this is the one. ๐-z,--no-authโ do not use any credentials mechanism, allow anonymous access. opposite to-aand-Aoptions. this is the default option when no authentication-related options are set. by default, no credential mechanism is used โ any user is allowed. doors wide open, no cap.--use-auth-secretโ TURN REST API flag. flag that sets a special WebRTC authorization option that is based upon authentication secret. the feature's purpose is to support "TURN Server REST API" as described in the TURN REST API section below. this option uses timestamp as part of combined username:usercombo -> "timestamp:username",turn user -> usercombo,turn password -> base64(hmac(input_buffer = usercombo, key = shared-secret)). this allows TURN credentials to be accounted for a specific user id. if you don't have a suitable id, the timestamp alone can be used. this option just turns on secret-based authentication. the actual value of the secret is defined either by optionstatic-auth-secret, or can be found in theturn_secrettable in the database.--oauthโ support oAuth authentication, as in the third-party STUN/TURN RFC 7635.--dh566โ use 566 bits predefined DH TLS key. default size of the key is 2066.--dh1066โ use 1066 bits predefined DH TLS key. default size of the key is 2066.--tlsv1โ set TLSv1 as a minimum supported protocol version.--tlsv1_1โ set TLSv1.1 as a minimum supported protocol version.--no-tlsv1_2โ set TLSv1.3/DTLSv1.2 as a minimum supported protocol version.--no-udpโ do not start UDP client listeners.--no-tcpโ do not start TCP client listeners.--no-tlsโ do not start TLS client listeners.--no-dtlsโ do not start DTLS client listeners.--no-udp-relayโ do not allow UDP relay endpoints defined in RFC 5766, use only TCP relay endpoints as defined in RFC 6062.--no-tcp-relayโ do not allow TCP relay endpoints defined in RFC 6062, use only UDP relay endpoints as defined in RFC 5766.--no-stdout-logโ flag to prevent stdout log messages. by default, all log messages are going to both stdout and to the configured log file. with this option everything will be going to the log file only (unless the log file itself is stdout).--syslogโ with this flag, all log will be redirected to the system log (syslog).--syslog-facility<value>โ set syslog facility for syslog messages. default is''.--simple-logโ this flag means that no log file rollover will be used, and the log file name will be constructed as-is, without PID and date appendage. this option can be used, for example, together with thelogrotatetool. it's giving minimalism. ๐--log-min-level<level>โ bestie, this is the volume knob for your logs ๐ข Only messages at or above this level get emitted. Valid levels, most-to-least chatty:debug(everything, and yes this is the default),info,warning,error(errors only). If you type a level it doesn't recognize, it just ignores it and throws a warning. ๐--new-log-timestampโ turns on the full ISO-8601 timestamp in all the logs. timestamps? iconic. ๐ฐ๏ธโจ--new-log-timestamp-format<format>โ sets the timestamp format (instrftime(1)format, so you know exactly what you're doing ๐ ).--log-bindingโ logs the STUN binding request. It's disabled by default now to dodge DoS attacks. ๐ก๏ธ--secure-stunโ requires authentication of the STUN Binding request. By default, clients get to have anonymous access to the STUN Binding functionality (the audacity, honestly).-S,--stun-onlyโ runs as a STUN server only, so every TURN request gets ignored. This is the option to suppress TURN functionality โ only STUN requests get processed. โ--no-stunโ runs as a TURN server only, so all STUN requests get ignored. This one suppresses STUN functionality โ only TURN requests get processed.--allow-loopback-peersโ allows peers on the loopback addresses (127.x.x.xand::1). Only allow it for testing in a development environment! In production it adds a possible security vulnerability, and so due to security reasons, it is not allowed to use it together with emptycli-password. ๐จ--no-multicast-peersโ disallows peers on well-known broadcast addresses (224.0.0.0and above, andFFXX:*).--mobilityโ Mobility with ICE (MICE) specs support. ๐ง--cliโ turns ON the CLI support. By default it is always OFF. See also the options--cli-ipand--cli-port.--no-cliโ turns OFF the CLI support. Since the CLI is OFF by default, this flag is only useful to override aclisetting from the configuration file.--server-relayโ Server relay. NON-STANDARD AND DANGEROUS OPTION. Only for those applications when we want to run server applications on the relay endpoints. This option eliminates the IP permissions check on the packets incoming to the relay endpoints. Seehttp://tools.ietf.org/search/rfc5766#section-17.2.3. ๐ฌ--udp-self-balanceโ (recommended for older Linuxes only) automatically balances UDP traffic over auxiliary servers (if configured). The load balancing uses theALTERNATE-SERVERmechanism. The TURN client must support300 ALTERNATE-SERVERresponse for this functionality. โ๏ธ--check-origin-consistencyโ the flag that sets the origin consistency check: across the session, all requests must have the same mainORIGINattribute value (if theORIGINwas initially used by the session).--drop-invalid-packetsโ drops invalid packets early. Enabled by default. ๐๏ธ--drop-invalid-packets-logโ logs invalid packets. The default behaviour is to not log invalid packets.--udp-recvmmsgโ Linux-only batched UDP receive viarecvmmsg()on the shared fan-in sockets (the client listener and, with--multiplex-peer, the per-thread relay socket). Enabled by default on Linux; pass--udp-recvmmsg=false(or=0) to disable. ๐ง--udp-recvmmsg-logโ logs Linuxrecvmmsgbatch occupancy stats every 10 seconds.--udp-gsoโ enables Linux UDP-GSO (UDP_SEGMENTcmsg) on the relay send path. When asendmmsgbatch shares destination and segment size, one network-stack traversal carries N datagrams. Requires--multiplex-peer(which is what enables thesendmmsgbatching GSO piggybacks on); passing--udp-gsoalone is a silent no-op. ๐--multiplex-peerโ Linux only. Enables peer-side multiplexing relay mode (non-standard, optional). Replaces the per-allocation relay-port bind with a pair of shared UDP sockets per relay thread (one IPv4, one IPv6) covering all TURN sessions on that thread; sessions are demultiplexed by exact peerIP:portlookup. Lifts the ~16 k allocation cap imposed by the relay port range and cuts kernel-side UDP rcvbuf drops dramatically. Impliessendmmsgbatching;--udp-recvmmsg(on by default) supplies therecvmmsgwindow the batching piggybacks on. Note: EVEN-PORT allocate requests are rejected with 400 in this mode; clients that need EVEN-PORT must use the legacy path. Seedocs/multiplex-peer.mdfor design and trade-offs. ๐ฅ--multiplex-peer-port<port>โ Linux only. Base UDP port for multiplex-peer relay sockets (default:3480, valid range1-65000). Thread i binds<base>+2i(IPv4) and<base>+2i+1(IPv6); a 4-thread server consumes ports<base>..<base>+7. Total ports consumed =relay_threads * 2. ๐งฎ--respond-http-unsupportedโ returns an HTTP response with a400status code to HTTP connections made to ports not supporting HTTP. The default behaviour is to immediately close the connection.--prometheusโ enables prometheus metrics. By default it is disabled. It would listen on port9641under the path/metricsโ also the path/on this port can be used as a health check. Unavailable on apt installations. ๐--prometheus-username-labelsโ enables labeling prometheus traffic metrics with client usernames. Labeling with client usernames is disabled by default, because this may cause memory leaks when using authentication with ephemeral usernames (e.g. TURN REST API). ๐ง--prometheus-portโ Prometheus listener port (Default:9641).--prometheus-address<address>โ Prometheus listening address (Default: any).--prometheus-path<path>โ Prometheus serve path (Default:/metrics).--versionโ prints version and exits. โ๏ธ-hโ Help.
Options with values: โจ
--stale-nonce[=<value>]โ uses extra security with a nonce value having limited lifetime, in seconds (default600secs). Set it to0for unlimited nonce lifetime.--max-allocate-lifetimeโ sets the maximum value for the allocation lifetime. Defaults to3600secs.--channel-lifetimeโ sets the lifetime for channel binding, defaults to600secs. This value MUST not be changed for production purposes. โ ๏ธ--permission-lifetimeโ sets the value for the lifetime of the permission. Defaults to300secs. This MUST not be changed for production purposes. โ ๏ธ-d,--listening-deviceโ listener interface device. (NOT RECOMMENDED. Optional functionality, Linux only.) Theturnserverprocess must have root privileges to bind the listening endpoint to a device. Ifturnservermust run as a process without root privileges, then just do not use this setting. ๐-L,--listening-ipโ listener IP address of relay server. Multiple listeners can be specified, for example:
-L ip1 -L ip2 -L ip3
If no IP(s) specified, then all IPv4 and IPv6 system IPs will be used for listening. The same ip(s) can be used as both listening and relay ip(s). ๐ก
-p,--listening-portโ TURN listener port for UDP and TCP listeners (Default:3478). Note: actually, TLS & DTLS sessions can connect to the "plain" TCP & UDP port(s), too โ if allowed by configuration.--tls-listening-portโ TURN listener port for TLS and DTLS listeners (Default:5349). Note: actually, "plain" TCP & UDP sessions can connect to the TLS & DTLS port(s), too โ if allowed by configuration. The TURN server "automatically" recognizes the type of traffic. Actually, two listening endpoints (the "plain" one and the "tls" one) are equivalent in terms of functionality; but we keep both endpoints to satisfy the RFC 5766 specs. For secure TCP connections, we currently support SSL version 3 and TLS versions 1.0, 1.1, 1.2. For secure UDP connections, we support DTLS version 1. ๐--alt-listening-portโ alternative listening port for UDP and TCP listeners; default (or zero) value means "listening port plus one". This is needed for STUNCHANGE_REQUESTโ in RFC 5780 sense or in old RFC 3489 sense โ for NAT behavior discovery. The TURN Server supportsCHANGE_REQUESTonly if it is started with more than one listening IP address of the same family (IPv4 or IPv6). TheCHANGE_REQUESTis only supported by UDP protocol, other protocols are listening on that endpoint only for "symmetry". ๐ช--alt-tls-listening-portโ alternative listening port for TLS and DTLS protocols. Default (or zero) value means "TLS listening port plus one".--tcp-proxy-portโ support connections from TCP loadbalancer on this port. The loadbalancer should use the binary proxy protocol. (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)--aux-serverโ auxiliary STUN/TURN server listening endpoint. Aux servers have almost full TURN and STUN functionality. The (minor) limitations are:- Auxiliary servers do not have alternative ports and they do not support STUN RFC 5780 functionality (
CHANGE REQUEST). - Auxiliary servers also are never returning
ALTERNATIVE-SERVERreply.
- Auxiliary servers do not have alternative ports and they do not support STUN RFC 5780 functionality (
Valid formats are 1.2.3.4:5555 for IPv4 and [1:2::3:4]:5555 for IPv6. There may be multiple aux-server options, each will be used for listening to client requests.
-i,--relay-deviceโ relay interface device for relay sockets (NOT RECOMMENDED. Optional, Linux only).-E,--relay-ipโ relay address (the local IP address that will be used to relay the packets to the peer). Multiple relay addresses may be used:
-E ip1 -E ip2 -E ip3
The same IP(s) can be used as both listening IP(s) and relay IP(s). If no relay IP(s) specified, then the turnserver will apply the default policy: it will decide itself which relay addresses to be used, and it will always be using the client socket IP address as the relay IP address of the TURN session (if the requested relay address family is the same as the family of the client socket). ๐ฐ๏ธ
-X,--external-ipโ okay so bestie, this one is for when your TURN server is hiding behind NAT and needs to tell the truth about where it actually lives ๐ธ. In that situation, if you use-Xin the form-X <ip>then that ip will be reported as the relay IP address of all allocations of its own address family (a relay of the other family gets reported under its own address, no cap). Heads up though: this scenario works only in a simple case when one single relay address is being used, and noCHANGE_REQUESTfunctionality is required ๐ญ. That single relay address has to be mapped by NAT to the 'external' IP. The"external-ip"value, if not empty, is returned in theXOR-RELAYED-ADDRESSfield. For that 'external' IP, NAT must forward ports directly (relayed port12345must be always mapped to the same 'external' port12345โ fr fr, no switching it up ๐ ). In the more complex case when more than one IP address is involved, that option must be used several times, and each entry must have the form-X <public-ip/private-ip>, to map all the involved addresses.CHANGE_REQUEST(RFC5780 or RFC3489) NAT discovery STUN functionality will work correctly, if the addresses are mapped properly, even when the TURN server itself is behind a NAT โจ. By default, this value is empty, and no address mapping is used.-m,--relay-threadsโ the number of relay threads to handle the established connections (in addition to the authentication thread and the listener thread) ๐ง. If you explicitly set it to0then the application runs the relay process in a single thread, in the same thread as the listener process (the authentication thread will still be a separate thread, she's independent ๐ ). If it's not set, then a default optimal algorithm will be employed (OS-dependent, iykyk). And on the older Linux systems (before Linux kernel 3.9), the number of UDP threads is always one thread per network listening endpoint โ unless-m 0or-m 1is set.--cpus <number>โ override the system CPU count detection ๐ซถ. Use this number instead of the auto-detected CPU count. It's useful in virtualized or containerized environments where the visible CPU count does not match what the cgroup actually allows. The vibes were lying to you, so now you can just say the truth yourself โจ.--min-portโ lower bound of the UDP port range for relay endpoints allocation ๐. Default value is49152, according to RFC 5766.--max-portโ upper bound of the UDP port range for relay endpoints allocation ๐. Default value is65535, according to RFC 5766.--sock-buf-sizeโ set socket buffer size to a new value (in bytes) ๐.-u,--userโ long-term security mechanism credentials user account, in the column-separated formusername:key๐. Multiple user accounts may be used on the command line, stack 'em up. The key is either the user password, or the key is generated by theturnadmincommand. In that second case, the key must be prepended with0xsymbols. The key is calculated over the user name, the user realm, and the user password. Lowkey important: this setting may not be used with TURN REST API ๐.-r,--realmโ the default realm to be used for the users when no explicit origin/realm relationship was found in the database, or if the TURN server is not using any database at all (just the command-line settings and theuserdbfile) ๐. Must be used with the long-term credentials mechanism or with TURN REST API, periodt.-C,--rest-api-separatorโ this is the timestamp/username separator symbol (character) in TURN REST API ๐ซ. The default value is:.-q,--user-quotaโ per-user allocations quota: how many concurrent allocations a user can create ๐. This option can also be set through the database, for a particular realm.-Q,--total-quotaโ total allocations quota: a global limit on concurrent allocations ๐ฅ. This option can also be set through the database, for a particular realm.-s,--max-bpsโ max bytes-per-second bandwidth a TURN session is allowed to handle (input and output network streams are treated separately, so she's counting them one at a time ๐ ). Anything above that limit will be dropped or temporarily suppressed (within the available buffer limits). This option can also be set through the database, for a particular realm.-B,--bps-capacityโ maximum server capacity ๐. This is the total bytes-per-second bandwidth the TURN server is allowed to allocate for the sessions, combined (input and output network streams are treated separately).--static-auth-secretโ static authentication secret value (a string) for TURN REST API only ๐. If not set, then the turn server will try to use the dynamic value in theturn_secrettable in the user database (if present). The database-stored value can be changed on-the-fly by a separate program, so this is why that other mode is dynamic โ she's alive, she's moving ๐. Multiple shared secrets can be used (both in the database and in the "static" fashion).--no-auth-pingsโ disable periodic health checks to 'dynamic' auth secret tables ๐ฉบ.--no-dynamic-ip-listโ do not use the dynamic allowed/denied peer ip list ๐ .--no-dynamic-realmsโ do not use dynamic realm assignment and options ๐ .--server-nameโ server name used for the oAuth authentication purposes ๐ฆ. The default value is the realm name.--certโ certificate file, PEM format ๐. Same file search rules applied as for the configuration file. If both--no-tlsand--no-dtlsoptions are specified, then this parameter is not needed. Default value isturn_server_cert.pem.--pkeyโ private key file, PEM format ๐. Same file search rules applied as for the configuration file. If both--no-tlsand--no-dtlsoptions are specified, then this parameter is not needed. Default value isturn_server_pkey.pem.--raw-public-keysโ raw public keys support โจ. On/off switch for RFC-7250 aka raw public keys. Coturn must be built against openSSL version at least3.2.1.--pkey-pwdโ if the private key file is encrypted, then this password to be used ๐คซ.--cipher-listโ allowed OpenSSL cipher list for TLS/DTLS connections ๐. Default value is"DEFAULT"for TLS/DTLS versions up toTLSv1.2/DTLSv1.2, and the library default ciphersuites forTLSv1.3.--CA-fileโ CA file in OpenSSL format ๐. Forces the TURN server to verify the client SSL certificates. By default, no CA is set and no client certificate check is performed.--ec-curve-nameโ curve name for EC ciphers, if supported by the OpenSSL library (TLS and DTLS) ๐ธ. The default value isprime256v1, if pre-OpenSSL 1.0.2 is used. With OpenSSL 1.0.2+, an optimal curve will be automatically calculated, if not defined by this option.--dh-fileโ use a custom DH TLS key, stored in PEM format in the file ๐๏ธ. Flags--dh566and--dh1066are ignored when the DH key is taken from a file.-l,--log-fileโ option to set the full path name of the log file ๐. By default, the turnserver tries to open a log file in/var/log/turnserver,/var/log,/var/tmp,/tmpand.(current) directories (whichever file open operation succeeds first, that file will be used). With this option you can set the definite log file name. The special names are"stdout"and"-"โ they will force everything to the stdout. Also,"syslog"name will redirect everything into the system log (syslog), as if the option--syslogwas set. In the runtime, the logfile can be reset with theSIGHUPsignal to the turnserver process ๐--alternate-serverโ option to set the "redirection" mode ๐. The value of this option will be the address of the alternate server for UDP & TCP service in the form of<ip>[:<port>]. The server will send this value in the attributeALTERNATE-SERVER, with error300, onALLOCATErequest, to the client. The client will receive only values with the same address family as the client network endpoint address family. See RFC 5389 and RFC 5766 forALTERNATE-SERVERfunctionality description. The client must use the obtained value for subsequent TURN communications. If more than one--alternate-serveroption is provided, then the functionality can be more accurately described as "load-balancing" than a mere "redirection" ๐ . If the port number is omitted, then the default port number3478for the UDP/TCP protocols will be used. Colon (:) characters in IPv6 addresses may conflict with the syntax of the option. To alleviate this conflict, literal IPv6 addresses are enclosed in square brackets in such resource identifiers, for example:
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:3478
Multiple alternate servers can be set. They will be used in the round-robin manner ๐. All servers in the pool are considered of equal weight and the load will be distributed equally. For example, if we have 4 alternate servers, then each server will receive 25% of ALLOCATE requests. An alternate TURN server address can be used more than one time with the alternate-server option, so this can emulate "weighting" of the servers โ iconic behaviour honestly โจ.
--tls-alternate-serverโ option to set an alternative server for TLS & DTLS services in the form of<ip>:<port>๐. If the port number is omitted, then the default port number5349for the TLS/DTLS protocols will be used. See the previous option for the functionality description.-O,--redis-statsdbโ Redis status and statistics database connection string, if used (default โ empty, no Redis stats DB used) ๐. This database keeps allocations status information, and it can be also used for publishing and delivering traffic and allocation event notifications. This database option can be used independently of the--redis-userdboption, and actually Redis can be used for status/statistics and SQLite or MySQL or MongoDB or PostgreSQL can be used for the user database โ mix and match, bestie ๐. The connection string has the same parameters as theredis-userdbconnection string.--max-allocate-timeoutโ max time, in seconds, allowed for full allocation establishment โณ. Default is60seconds.--drain-min-allocationsโ in drain mode (entered onSIGUSR1), shut down once the number of active allocations drops to this value or below ๐. Default is0(wait until all allocations are gone).--denied-peer-ip=<IPaddr[-IPaddr]>--allowed-peer-ip=<IPaddr[-IPaddr]>โ bestie this is the allow list, the VIP section ๐ You use it to ban or allow specific ip addresses, or whole ranges of ip addresses. And here's the little plot twist: if an ip address shows up as both allowed and denied, then allowed wins. Always. It's giving "you're on the list, babe, come through." Super handy when you wanna ban a whole range of ip addresses except for a few special little ips living inside that range. Also iconic when you don't want turn server users to be able to reach machines that are reachable by the turn server but would otherwise be unreachable from the internet (like, say, when the turn server is sitting behind a NAT ๐ซฃ). And psst โ the"white"and"black"peer IP ranges can also be dynamically changed in the database. The allowed/denied addresses (white/black lists) rules are very simple, fr fr:- If there is no rule for an address, then it is allowed;
- If there is an
"allowed"rule that fits the address then it is allowed โ no matter what; - If there is no
"allowed"rule that fits the address, and if there is a"denied"rule that fits the address, then it is denied.
--pidfileโ the file name where the pid of the process gets stored ๐ Default is/var/run/turnserver.pid(if a superuser account is used) or/var/tmp/turnserver.pid.--acme-redirect <URL>โ redirect ACME/RFC8555 (like Let's Encrypt challenge) requests, i.e. HTTP GET requests matching'^/.well-known/acme-challenge/(.*)'to<URL>$1with$1 == (.*). No validation of<URL>will be done, so make sure you do not forget the trailing slash ๐ If<URL>is an empty string (the default value), no special handling of such requests will be done.--proc-userโ user name to run the process as. After the initialization, the turnserver process will make an attempt to change the current user ID to that user โจ--proc-groupโ group name to run the process as. After the initialization, the turnserver process will make an attempt to change the current group ID to that group โจ-K,--keep-address-familyโ DEPRECATED and will be removed in favor of--allocation-default-address-family!! ๐ญ TURN server allocates address family according to TURN Client <=> Server communication address family. !! It breaks RFC6156 section-4.2 (violates default IPv4) !! ๐จ-A,--allocation-default-address-family=<ipv4|ipv6|keep>โ default is IPv4. TURN server allocates address family according to TURN client requested address family. If address family not requested explicitly by the client, then it falls back to this default. The standard RFC explicitly defines that this default must be IPv4, so use other option values with care! ๐--cli-ipโ local system IP address to be used for the CLI management interface. The turnserver process can be accessed for management with telnet, at this IP address and on the CLI port (see the next parameter ๐). Default value is127.0.0.1. You can use telnet or putty (in telnet mode) to access the CLI management interface ๐ฅ๏ธ--cli-portโ CLI management interface listening port. Default is5766.--cli-passwordโ CLI access password. Default is empty (no password) ๐ For the security reasons, it is recommended to use the encrypted form of the password (see the-Pcommand in the turnadmin utility). The dollar signs in the encrypted form must be escaped โ ๏ธ--cli-max-output-sessionsโ maximum number of output sessions in thepsCLI command. This value can be changed on-the-fly in CLI. The default value is256.--web-adminโ enable Turn Web-admin support. By default it is disabled ๐ซ--web-admin-ip=<IP>โ local system IP address to be used for Web-admin server endpoint. Default value is127.0.0.1.--web-admin-port=<port>โ Web-admin server port. Default is8080.--web-admin-listen-on-workersโ enable for web-admin server to listen on STUN/TURN workers' STUN/TURN ports. By default it is disabled for security reasons! ๐ (This behavior used to be the default behavior, and was enabled by default. Not anymore bestie.)--rfc5780โ enable RFC5780 (NAT behavior discovery). Originally, if there are more than one listener address from the same address family, then by default the NAT behavior discovery feature was enabled. This option enables this original behavior, because the NAT behavior discovery adds attributes to response, and this increases the possibility of an amplification attack ๐ฌ Strongly encouraged to use this option to decrease gain factor in STUN binding responses.--no-rfc5780โ DEPRECATED and now the default behaviour. See--rfc5780.--stun-backward-compatibilityโ add the deprecated MAPPED-ADDRESS attribute to STUN Binding responses, in addition to the XOR-MAPPED-ADDRESS attribute that is always sent. Only needed for clients that cannot parse XOR-MAPPED-ADDRESS. Strongly encouraged to keep this option off to decrease gain factor in STUN binding responses ๐--rfc3489-compatibilityโ DEPRECATED. Enable handling of obsolete RFC 3489 ("classic" STUN) Binding requests, which carry no magic cookie. RFC 5389 deprecated these mechanisms and RFC 8489 dropped them entirely. This option is scheduled for removal in the next major release, with no replacement. ๐ญ
Before this option existed, the RFC 3489 request path was controlled by --stun-backward-compatibility. Operators who set that option in order to serve classic-STUN clients should now set --rfc3489-compatibility instead, or both options to retain the exact previous behavior.
--unauthorized-ratelimitโ enable per-source rate limiting of UDP 401 Unauthorized responses. This mitigates reflection and amplification attacks that spoof a victim's source address to receive authentication challenges. Disabled by default ๐ก๏ธ--unauthorized-ratelimit-rps=<count>โ maximum number of UDP 401 Unauthorized responses sent per source IP per second. Default is10.--stateless-nonceโ issue 401/438 challenge nonces as authenticated timestamp cookies (issue time plus an HMAC over the client address, keyed by a per-process secret) instead of storing a random nonce in per-client session state. Unauthenticated UDP requests are then answered without allocating a session, bounding server memory under spoofed-source floods of structurally valid STUN messages ๐ง โจ Wire-compatible with standard TURN clients. Enabled by default; disable with--stateless-nonce=false, which restores the stored random nonce and the legacy 16-character challenge in place of the 24-character one.--stateless-nonce-secret=<secret>โ derive the stateless-nonce signing key from this secret instead of a random per-process key (implies--stateless-nonce). Servers sharing the secret validate each other's nonces, so challenges survive restarts and work across a load-balanced fleet ๐ซถ Use a long, high-entropy string and keep fleet clocks NTP-synced.
๐ฅ LOAD BALANCE AND PERFORMANCE TUNING ๐ฅ
This topic is covered in the wiki page, and bestie it is the wiki page, no cap:
https://github.com/coturn/coturn/wiki/turn_performance_and_load_balance
๐ WEBRTC USAGE ๐
Okay so this is a set of notes for the WebRTC users, and y'all are my favorites so listen up ๐
- WebRTC uses long-term authentication mechanism, so you have to use
-aoption (or--lt-cred-mech). WebRTC relaying will not work with anonymous access, periodt. With-aoption, do not forget to set the default realm (-roption). You will also have to set up the user accounts, and for that you have a number of options:
a. command-line options (-u).
b. a database table (SQLite or PostgreSQL or MySQL or MongoDB). You will have to set keys with turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords in the database ๐ซ
c. Redis key/value pair(s), if Redis is used. You can use either keys or open passwords with Redis; see turndb/testredisdbsetup.sh file.
d. You also can use the TURN REST API. You will need shared secret(s) set either through the command line option, or through the config file, or through the database table or Redis key/value pairs.
- Usually WebRTC uses fingerprinting (
-f) ๐ซ -voption may be nice to see the connected clients ๐-Xis needed if you are running your TURN server behind a NAT.--min-portand--max-portmay be needed if you want to limit the relay endpoints ports number range ๐ข
โจ TURN REST API โจ
okay so this is where it gets spicy ๐ฅ โ in WebRTC, the browser gets its TURN connection info from the web server. That info is secure information bestie, because it literally contains the TURN credentials. And since those credentials get transmitted over the public networksโฆ yeah, that's a potential security breach ๐ญ.
So here's the girl math: if you absolutely have to send valuable info over the public network, then that info needs a limited lifetime. That way, whoever snatches it without permission can only do limited damage. iconic damage control, honestly.
And THAT is how the whole TURN REST API idea was born โ time-limited TURN credentials โจ. This security mechanism rides on top of the long-term credentials mechanism. The main idea: the web server hands the credentials to the client, but those credentials can only be used for a limited time by an application that needs to create a TURN server connection.
The "classic" long-term credentials mechanism (LTCM) is described here:
For authentication, each user must know two things: the username and the password. Optionally, the user must supply the ORIGIN value, so the server can figure out the realm to use for that user. The nonce and the realm values get supplied by the TURN server. But LTCM says nothing about the nature or the persistence of the username and password โ and that little gap is exactly what the REST API exploits, no cap ๐
.
So in the TURN REST API, there are no persistent passwords for users. A user just has the username. The password is always temporary, generated by the web server on-demand when the user hits the WebRTC page. And honestly? It's a temporary one-time session only username that gets handed to the user too.
The temporary user is generated like this:
temporary-username="timestamp" + ":" + "username"
where username is the persistent user name, and the timestamp format is just seconds since 1970 โ the exact same value the time(NULL) function returns.
The temporary password is obtained as an HMAC-SHA1 function over the temporary username, with the shared secret as the HMAC key, and then the result is encoded:
temporary-password = base64_encode(hmac-sha1(shared-secret, temporary-username))
Both the TURN server and the web server know the same shared secret. How that shared secret gets distributed among the involved entities? That's left to the WebRTC deployment details โ it's beyond the scope of the TURN REST API, so don't @ us ๐.
So yeah, a timestamp is used for the temporary password calculation, and that timestamp can be retrieved straight from the temporary username. This info is valuable, but only temporary โ only while the timestamp hasn't expired. And without knowing the shared secret, a new temporary password simply cannot be generated. periodt ๐.
This is all formally described in Justin's Uberti TURN REST API document, which you can grab by following the link "TURN REST API" on the TURN Server project's page https://github.com/coturn/coturn/.
Once the client (browser) application has the temporary username and password, the rest is just the "classic" long-term credentials mechanism. For the developers out there, here's the step-by-step, bestie ๐ซถ:
- a new TURN client sends a request command to the TURN server. Optionally, it adds the
ORIGINfield to it. - the TURN server sees that this is a new client and the message is not authenticated.
- the TURN server generates a random nonce string, and returns the error
401to the client, with nonce and realm included. If theORIGINfield was present in the client request, it may affect the realm value that the server chooses for the client. - the client sees the
401error and it extracts two values from the error response: the nonce and the realm. - the client uses username, realm and password to produce a key:
key = MD5(username ":" realm ":" SASLprep(password))
(SASLprep is described here: http://tools.ietf.org/html/rfc4013)
- the client forms a new request, adds username, realm and nonce to the request. Then, the client calculates and adds the integrity field to the request. This is the trickiest part of the whole process, and it's described at the end of section 15.4:
http://tools.ietf.org/html/rfc5389#section-15.4 - the client, optionally, adds the fingerprint field. This may also be a tricky procedure, described in section 15.5 of the same document. WebRTC usually uses fingerprinted TURN messages.
- the TURN server receives the request, reads the username.
- then the TURN server checks that the nonce and the realm in the request are the valid ones.
- then the TURN server calculates the key.
- then the TURN server calculates the integrity field.
- then the TURN server compares the calculated integrity field with the received one โ they must be the same. If the integrity fields differ, then the request is rejected. ๐
In subsequent communications, the client may go with exactly the same sequence, but for optimization the client usually โ having already got the info about realm and nonce โ pre-calculates the integrity string for each request, so the 401 error response becomes unnecessary. The TURN server may use the --stale-nonce option for extra security: after some time, the nonce expires and the client will get a 438 error response with the new nonce, and the client will have to start using that new nonce.
In subsequent communications, the server and the client will always assume the same password โ the original password becomes the session parameter and is never expiring. So the password doesn't change while the session is valid and unexpired. So if the session is properly maintained, it may go forever, even if the user password has already been changed (in the database). The session is simply using the old password. Once the session gets disconnected, the client will have to use the new password to re-connect (if the password has been changed). that's just how she goes ๐ฆ.
An example where a new shared secret is generated every hour by the TURN server box and then supplied to the web server, remotely, is provided in the script examples/scripts/restapi/shared_secret_maintainer.pl .
A very important thing: the nonce must be totally random and it must be different for different clients and different sessions. do NOT skip this one bestie ๐ค
๐๏ธ DATABASES ๐๏ธ
For the user database, the turnserver has the following options:
- Users can be set in the command line, with multiple
-uor--useroptions. Obviously, only a few users can be set that way, and their credentials are fixed for theturnserverprocess lifetime. - Users can be stored in SQLite DB. The default SQLite database file is
/var/db/turndbor/usr/local/var/db/turndbor/var/lib/turn/turndb. - Users can be stored in PostgreSQL database, if the
turnserverwas compiled with PostgreSQL support. Each timeturnserverchecks user credentials, it reads the database (asynchronously, of course, so the current flow of packets is not delayed in any way), so any change in the database content is immediately visible by theturnserver. This is the way if you need the best scalability. The schema for the database can be found inschema.sqlfile. For long-term credentials, you have to set the "keys" for the users; the "keys" are generated by theturnadminutility. For the key generation, you need username, password and the realm. All users in the database must use the same realm value; if down the road you decide to change the realm name, then you will have to re-generate all user keys (that can be done in a batch script). See the fileturndb/testsqldbsetup.sqlas an example. - The same is true for MySQL database. The same schema file is applicable. The same considerations are applicable.
- The same is true for the Redis database, but the Redis database has a different schema โ it can be found (in the form of explanation) in
schema.userdb.redis. Also, in Redis you can store both "keys" and open passwords (for long term credentials) โ the "open password" option is less secure but more convenient for low-security environments. See the fileturndb/testredisdbsetup.shas an example. - If a database is used, then users can be divided into multiple independent realms. Each realm can be administered separately, and each realm can have its own set of users and its own performance options (
max-bps,user-quota,total-quota). - If you use MongoDB, the database will be setup for you automatically. slay, no setup era โจ.
- Of course, the
turnservercan be used in non-secure mode, when users are allowed to establish sessions anonymously. But in most cases (like WebRTC) that will not work.
For the status and statistics database, there are two choices:
- The simplest choice is not to use it. Do not set
--redis-statsdboption, and this functionality will be simply ignored. - If you choose to use it, then set the
--redis-statsdboption. This may be the same database as in--redis-userdboption, or it may be a different database. You may want to use a different database for security or convenience reasons. Also, you can use different database management systems for the user database and for the status and statistics database. For example, you can use MySQL as the user database, and you can use Redis for the statistics. Or you can use Redis for both.
So, we have 6 choices for the user management, and 2 choices for the statistics management. These two are totally independent. So, you have overall 6*2=12 ways to handle persistent information, choose any for your convenience ๐.
You do not have to handle the database information "manually" โ the turnadmin program can handle everything for you. For PostgreSQL and MySQL you will just have to create an empty database with schema.sql SQL script. With Redis, you do not have to do even that โ just run turnadmin and it will set the users for you (see the turnadmin manuals). If you are using SQLite, then the turnserver or turnadmin will initialize the empty database, for you, when started. The TURN server installation process creates an empty initialized SQLite database in the default location (/var/db/turndb or /usr/local/var/db/turndb or /var/lib/turn/turndb, depending on the system).
ALPN โจ
okay so bestie, if your build was compiled with OpenSSL 1.0.2 or newer, the server can speak ALPN, and the two labels it knows are "stun.turn" and "stun.nat-discovery". ๐
here's the tea: when the server gets a TLS/DTLS ClientHello that has one or both of those ALPN labels in it, it picks the first stun.* label and sends that back in the ServerHello, in the ALPN extension field. ๐ฆ
but if there's no stun.* label anywhere in there? then the server justโฆ doesn't put the ALPN info in the ServerHello at all. no label, no mention, periodt. ๐
LIBRARIES ๐
so the build process is out here making you stuff. in the lib/ sub-directory it creates the TURN client messaging library. ๐
in the include/ sub-directory, that's where the necessary include files get placed.
the C++ wrapper for all that messaging functionality lives in the TurnMsgLib.h header โ and if you want to see actual C++ code in the wild, there's an example sitting in the stunclient.c file. iconic. โญ
DOCS ๐
after installation, run this bestie:
$ man turnserver
or, if you're chillin in the project root directory:
$ man -M man turnserver
and boom, there's your man page. ๐ซถ
also โ in the docs/html subdirectory of the original archive tree you'll find the client library reference. once it's installed it gets placed in PREFIX/share/doc/turnserver/html. ๐
LOGS ๐
when the TURN Server starts up, it tries so hard to create a log file called turn_<pid>.log in these directories:
/var/log/log//var/tmp/tmp- current directory
and if all of those attempts fail (because of the system permission settings, not because the server didn't try ๐ญ) then all log messages get sent only to the standard output of the process.
you can control this whole vibe with the --log-file, --syslog and --no-stdout-log options. ๐ธ
HTTPS MANAGEMENT INTERFACE ๐
the turnserver process serves up an HTTPS Web access as a statistics and basic management interface. the turnserver listens for incoming HTTPS admin connections on the same ports as the main TURN/STUN listener. the Web admin pages are basic and self-explanatory, no cap. ๐
to actually make the HTTPS interface active, the database table admin_user has to be populated with the admin user account(s). an admin user can be a superuser (if not assigned to a particular realm) or a restricted user (if assigned to a realm). and those restricted admin users? they can only do limited actions, and only within their corresponding realms. main character energy but scoped. ๐
TELNET CLI ๐ป
the turnserver process also provides a telnet CLI access as a statistics and basic management interface. by default it starts a telnet CLI listener on IP 127.0.0.1 and port 5766. ๐ฆ
you can change that with the command-cline options of the turnserver process (see the --cli-ip and --cli-port options, iykyk).
and the full list of telnet CLI commands? that's provided in the "help" command output in the telnet CLI itself. just ask it, bestie. โจ
CLUSTERS ๐
TURN Server can absolutely be a part of a cluster installation. but here's the catch ๐ซ โ to support the "even port" functionality (that's the RTP/RTCP streams pairs) the client requests coming from a particular IP must be delivered to the same TURN Server instance. so it requires some networking setup massaging for the cluster.
the reason? the RTP and RTCP relaying endpoints have to be allocated on the same relay IP. it would be possible to design a scheme with the application-level requests forwarding (and maybe that happens later ๐) but it would affect the performance. so. yeah. ๐
FILES ๐
/etc/turnserver.conf/var/db/turndb/usr/local/var/db/turndb/var/lib/turn/turndb/usr/local/etc/turnserver.conf
DIRECTORIES ๐๏ธ
/usr/local/share/turnserver/usr/local/share/doc/turnserver/usr/local/share/examples/turnserver
STANDARDS ๐
- obsolete STUN RFC 3489
- new STUN RFC 5389
- TURN RFC 5766
- TURN-TCP extension RFC 6062
- TURN IPv6 extension RFC 6156
- STUN/TURN test vectors RFC 5769
- STUN NAT behavior discovery RFC 5780
SEE ALSO ๐
turnadmin, turnutils
WEB RESOURCES ๐
project page:
https://github.com/coturn/coturn/
Wiki page:
https://github.com/coturn/coturn/wiki
forum:
https://groups.google.com/forum/?fromgroups=#!forum/turn-server-project-rfc5766-turn-server
AUTHORS ๐
See the AUTHORS.md file in the coturn source distribution.
and that's the whole page bestie, we made it to the end ๐ this version is from the 17 May 2026 source, filed under TURN(1) โ go forth and relay, you absolute icon. ๐ ๐ฆโจ
๐ฆ where this page comes from
- arch rolling: coturn 4.18.0-2 ยท LicenseRef-coturn
- epel 10: coturn 4.18.0-1.el10_3 ยท BSD-3-Clause AND MIT
- epel 9: coturn 4.18.0-1.el9 ยท BSD-3-Clause AND MIT
- fedora 43: coturn 4.18.0-1.fc43 ยท BSD-3-Clause AND MIT
- fedora 44: coturn 4.18.0-1.fc44 ยท BSD-3-Clause AND MIT
- ubuntu stonking: coturn 4.18.0-1
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms