--- /dev/null
+= Modules in Version 4
+
+As of Version 3, all of the modules have been places in the
+`mods-available/` directory. This practice follows that used by other
+servers such as Nginx, Apache, etc. The `modules` directory should not
+be used.
+
+Modules are enabled by creating a file in the mods-enabled/ directory.
+You can also create a soft-link from one directory to another:
+
+```
+$ cd mods-enabled/
+$ ln -s ../mods-available/foo
+```
+
+This will enable module `foo`. Be sure that you have configured the
+module correctly before enabling it, otherwise the server will not
+start. You can verify the server configuration by running
+`radiusd -XC`.
+
+A large number of modules are enabled by default. This allows the server
+to work with the largest number of authentication protocols. Please be
+careful when disabling modules. You will likely need to edit the
+`sites-enabled/` files to remove references to any disabled modules.
+
+== Conditional Modules
+
+FreeRADIUS allows modules to be conditionally loaded. This is useful
+when you want to have a virtual server which references a module, but
+does not require it. Instead of editing the virtual server file, you can
+just conditionally enable the module.
+
+Modules are conditionally enabled by adding a `-` before their name in
+a virtual server. For example, you can do:
+
+```
+server {
+ recv Access-Request {
+ ...
+ ldap
+ -sql
+ ...
+ }
+}
+```
+
+This says `require the LDAP module, but use the SQL module only if it
+is configured.`
+
+This feature is not very useful for production configurations. It is,
+however, very useful for the default examples that ship with the server.
+
+== Ignoring module
+
+If you see this message::
+
+```
+Ignoring module (see mods-available/README.adoc)
+```
+
+Then you are in the right place. Most of the time this message can be
+ignored. The message can be fixed by find the references to `-module`
+in the virtual server, and deleting them.
+
+Another way to fix it is to configure the module, as described above.
+
+== Simplification
+
+Allowing conditional modules simplifies the default virtual servers that
+are shipped with FreeRADIUS. This means that if you want to enable LDAP
+(for example), you no longer need to edit the files in
+`sites-available/` in order to enable it.
+
+Instead, you should edit the `mods-available/ldap` file to point to
+your local LDAP server. Then, enable the module via the soft-link method
+described above.
+
+Once the module is enabled, it will automatically be used in the default
+configuration.
+
+== List of available modules
+
+* <<abfab_psk_sql.adoc#,abfab_psk_sql>>
+* <<always.adoc#,always>>
+* <<attr_filter.adoc#,attr_filter>>
+* <<cache.adoc#,cache>>
+* <<cache_eap.adoc#,cache_eap>>
+* <<cache_tls.adoc#,cache_tls>>
+* <<chap.adoc#,chap>>
+* <<cipher.adoc#,cipher>>
+* <<client.adoc#,client>>
+* <<couchbase.adoc#,couchbase>>
+* <<csv.adoc#,csv>>
+* <<cui.adoc#,cui>>
+* <<date.adoc#,date>>
+* <<delay.adoc#,delay>>
+* <<detail.adoc#,detail>>
+* <<detail.example.com.adoc#,detail example com>>
+* <<detail.log.adoc#,detail log>>
+* <<dhcp_sqlippool.adoc#,dhcp_sqlippool>>
+* <<dhcpv4.adoc#,dhcpv4>>
+* <<digest.adoc#,digest>>
+* <<eap.adoc#,eap>>
+* <<eap_inner.adoc#,eap_inner>>
+* <<echo.adoc#,echo>>
+* <<escape.adoc#,escape>>
+* <<etc_group.adoc#,etc_group>>
+* <<exec.adoc#,exec>>
+* <<expiration.adoc#,expiration>>
+* <<expr.adoc#,expr>>
+* <<files.adoc#,files>>
+* <<idn.adoc#,idn>>
+* <<isc_dhcp.adoc#,isc_dhcp>>
+* <<json.adoc#,json>>
+* <<krb5.adoc#,krb5>>
+* <<ldap.adoc#,ldap>>
+* <<linelog.adoc#,linelog>>
+* <<logintime.adoc#,logintime>>
+* <<logtee.adoc#,logtee>>
+* <<lua.adoc#,lua>>
+* <<mac2ip.adoc#,mac2ip>>
+* <<mac2vlan.adoc#,mac2vlan>>
+* <<mruby.adoc#,mruby>>
+* <<mschap.adoc#,mschap>>
+* <<ntlm_auth.adoc#,ntlm_auth>>
+* <<opendirectory.adoc#,opendirectory>>
+* <<pam.adoc#,pam>>
+* <<pap.adoc#,pap>>
+* <<passwd.adoc#,passwd>>
+* <<perl.adoc#,perl>>
+* <<python.adoc#,python>>
+* <<radius.adoc#,radius>>
+* <<radutmp.adoc#,radutmp>>
+* <<redis.adoc#,redis>>
+* <<redis_ippool.adoc#,redis_ippool>>
+* <<rediswho.adoc#,rediswho>>
+* <<rest.adoc#,rest>>
+* <<smbpasswd.adoc#,smbpasswd>>
+* <<soh.adoc#,soh>>
+* <<sometimes.adoc#,sometimes>>
+* <<sql.adoc#,sql>>
+* <<sqlcounter.adoc#,sqlcounter>>
+* <<sqlippool.adoc#,sqlippool>>
+* <<sradutmp.adoc#,sradutmp>>
+* <<stats.adoc#,stats>>
+* <<unbound.adoc#,unbound>>
+* <<unix.adoc#,unix>>
+* <<unpack.adoc#,unpack>>
+* <<utf8.adoc#,utf8>>
+* <<wimax.adoc#,wimax>>
+* <<winbind.adoc#,winbind>>
+* <<yubikey.adoc#,yubikey>>
--- /dev/null
+== Virtual Servers
+
+FreeRADIUS 4.0 supports virtual servers. This is probably the single
+largest change that is NOT backwards compatible with 1.x.
+
+The virtual servers do NOT have to be set up with the `sites-available`
+and `sites-enabled` directories. You can still have one "radiusd.conf"
+file, and put the server configuration there:
+
+```
+...
+server {
+ recv Access-Request {
+ ...
+ }
+ authenticate pap {
+ ...
+ }
+ ...
+}
+...
+```
+
+The power of virtual servers lies in their ability to separate policies.
+A policy can be placed into a virtual server, where it is guaranteed to
+affect only the requests that are passed through that virtual server. In
+1.x, the policies were global, and it sometimes took much effort to
+write a policy so that it only applied in certain limited situations.
+
+=== What do we mean by "virtual server"?
+
+A virtual server is a (nearly complete) RADIUS server, just like a
+configuration for FreeRADIUS 1.x. However, FreeRADIUS can now run
+multiple virtual servers at the same time. The virtual servers can even
+proxy requests to each other!
+
+The simplest way to create a virtual server is to take the all of the
+request processing sections from radius.conf, ("authorize" ,
+"authenticate", etc.) and wrap them in a "server \{}" block, as
+above.
+
+You can create another virtual server by:
+
+* defining a new "server foo \{…}" section in `radiusd.conf`
+* Putting the normal "authorize", etc. sections inside of it
+* Adding a "listen" section _inside_ of the "server" section.
+
+e.g.
+
+```
+...
+server foo {
+ listen {
+ ipaddr = 127.0.0.1
+ port = 2000
+ type = auth
+ }
+
+ recv Access-Request {
+ update control {
+ Cleartext-Password := "bob"
+ }
+ pap
+ }
+
+ authenticate pap {
+ pap
+ }
+}
+...
+```
+
+With that text added to `radiusd.conf`, run the server in debugging mode
+(`radiusd -X`), and in another terminal window, type:
+
+```
+$ radtest bob bob localhost:2000 0 testing123
+```
+
+You should see the server return an Access-Accept.
+
+=== Capabilities and limitations
+
+The only sub-sections that can appear in a virtual server section are:
+
+```
+listen
+client
+authorize
+authenticate
+post-auth
+pre-proxy
+post-proxy
+preacct
+accounting
+session
+```
+
+All other configuration parameters (modules, etc.) are global.
+
+Inside of a virtual server, the authorize, etc. sections have their
+normal meaning, and can contain anything that an authorize section could
+contain in 1.x.
+
+When a "listen" section is inside of a virtual server definition, it
+means that all requests sent to that IP/port will be processed through
+the virtual server. There cannot be two "listen" sections with the
+same IP address and port number.
+
+When a "client" section is inside of a virtual server definition, it
+means that that client is known only to the "listen" sections that are
+also inside of that virtual server. Not only is this client definition
+available only to this virtual server, but the details of the client
+configuration is also available only to this virtual server.
+
+i.e. Two virtual servers can listen on different IP address and ports,
+but both can have a client with IP address 127.0.0.1. The shared secret
+for that client can be different for each virtual server.
+
+=== More complex "listen" capabilities
+
+The "listen" sections have a few additional configuration items that
+were not in 1.x, and were not mentioned above. These configuration items
+enable almost any mapping of IP / port to clients to virtual servers.
+
+The configuration items are:
+
+```
+virtual_server = <name>
+
+ If set, all requests sent to this IP / port are processed
+ through the named virtual server.
+
+ This directive can be used only for "listen" sections
+ that are global. i.e. It CANNOT be used if the
+ "listen" section is inside of a virtual server.
+
+clients = <name>
+
+ If set, the "listen" section looks for a "clients" section:
+
+ clients <name> {
+ ...
+ }
+
+ It looks inside of that named "clients" section for
+ "client" subsections, at least one of which must
+ exist. Each client in that section is added to the
+ list of known clients for this IP / port. No other
+ clients are known.
+
+ If it is set, it over-rides the list of clients (if
+ any) in the same virtual server. Note that the
+ clients are NOT additive!
+
+ If it is not set, then the clients from the current
+ virtual server (if any) are used. If there are no
+ clients in this virtual server, then the global
+ clients are used.
+
+ i.e. The most specific directive is used:
+ * configuration in this "listen" section
+ * clients in the same virtual server
+ * global clients
+
+ The directives are also *exclusive*, not *additive*.
+ If you have one client in a virtual server, and
+ another client referenced from a "listen" section,
+ then that "listen" section will ONLY use the second
+ client. It will NOT use both clients.
+```
+
+=== More complex "client" capabilities
+
+The "client" sections have a few additional configuration items that
+were not in 1.x, and were not mentioned above. These configuration items
+enable almost any mapping of IP / port to clients to virtual servers.
+
+The configuration items are:
+
+```
+virtual_server = <name>
+
+ If set, all requests from this client are processed
+ through the named virtual server.
+
+ This directive can be used only for "client" sections
+ that are global. i.e. It CANNOT be used if the
+ "client" section is inside of a virtual server.
+```
+
+If the "listen" section has a "server" entry, and a matching client
+is found ALSO with a "server" entry, then the clients server is used
+for that request.
+
+=== Worked examples
+
+Listening on one socket, and mapping requests from two clients to two
+different servers.
+
+```
+listen {
+ ...
+}
+client one {
+ ...
+ virtual_server = server_one
+}
+client two {
+ ...
+ virtual_server = server_two
+}
+server server_one {
+ recv Access-Request {
+ ...
+ }
+ ...
+}
+server server_two {
+ recv Access-Request {
+ ...
+ }
+ ...
+}
+```
+
+This could also be done as:
+
+```
+listen {
+ ...
+ virtual_server = server_one
+}
+client one {
+ ...
+}
+client two {
+ ...
+ virtual_server = server_two
+}
+server server_one {
+ recv Access-Request {
+ ...
+ }
+ ...
+}
+server server_two {
+ recv Access-Request {
+ ...
+ }
+ ...
+}
+```
+
+In this case, the default server for the socket is "server_one", so
+there is no need to set that in the client "one" configuration. The
+"server_two" configuration for client "two" over-rides the default
+setting for the socket.
+
+Note that the following configuration will NOT work:
+
+```
+listen {
+ ...
+ virtual_server = server_one
+}
+client one {
+ ...
+}
+server server_one {
+ recv Access-Request {
+ ...
+ }
+ ...
+}
+server server_two {
+ client two {
+ ...
+ }
+ recv Access-Request {
+ ...
+ }
+ ...
+}
+```
+
+In this example, client "two" is hidden inside of the virtual server,
+where the "listen" section cannot find it.
+
+=== Outlined examples
+
+This section outlines a number of examples, with alternatives.
+
+* one server, multiple sockets
+** multiple "listen" sections in a "server" section
+* one server per client
+** define multiple servers
+** have a global "listen" section
+** have multiple global "clients", each with "virtual_server = X"
+* two servers, each with their own sockets
+** define multiple servers
+** put "client" sections into each "server"
+** put a "listen" section into each "server"
++
+Each server can list the same client IP, and the secret can be
+different.
+* two sockets, sharing a list of clients, but pointing to different
+servers
+** define global "listen" sections
+** in each, set "virtual_server = X"
+** in each, set "clients = Y"
+** define "clients Y" section, containing multiple clients.
++
+This also means that you can have a third socket, which doesn’t share
+any of these clients.
+
+=== How to decide what to do
+
+If you want _completely_ separate policies for a socket or a client,
+then create a separate virtual server. Then, map the request to that
+server by setting configuration entries in a "listen" section or in a
+"client" section.
+
+Start off with the common cases first. If most of the clients and/or
+sockets get a particular policy, make that policy the default. Configure
+it without paying attention to the sockets or clients you want to add
+later, and without adding a second virtual server. Once it works, then
+add the second virtual server.
+
+If you want to re-use the previously defined sockets with the second
+virtual server, then you will need one or more global "client"
+sections. Those clients will contain a "virtual_server = …" entry that
+will direct requests from those clients to the appropriate virtual
+server.
+
+=== List of provided virtual servers
+
+* <<abfab-tls.adoc,abfab tls>>
+* <<abfab-tr-idp.adoc,abfab tr idp>>
+* <<arp.adoc,arp>>
+* <<bfd.adoc,bfd>>
+* <<buffered-sql.adoc,buffered sql>>
+* <<challenge.adoc,challenge>>
+* <<channel_bindings.adoc,channel_bindings>>
+* <<check-eap-tls.adoc,check eap tls>>
+* <<coa.adoc,coa>>
+* <<control-socket.adoc,control socket>>
+* <<control-socket.orig.adoc,control socket orig>>
+* <<copy-acct-to-home-server.adoc,copy acct to home server>>
+* <<decoupled-accounting.adoc,decoupled accounting>>
+* <<default.adoc,default>>
+* <<default.orig.adoc,default orig>>
+* <<default.rej.adoc,default rej>>
+* <<detail.adoc,detail>>
+* <<detail-debugging.adoc,detail debugging>>
+* <<dhcp.adoc,dhcp>>
+* <<dhcp.orig.adoc,dhcp orig>>
+* <<dhcp.relay.adoc,dhcp relay>>
+* <<dynamic-clients.adoc,dynamic clients>>
+* <<example.adoc,example>>
+* <<inner-tunnel.adoc,inner tunnel>>
+* <<ldap_sync.adoc,ldap_sync>>
+* <<originate-coa.adoc,originate coa>>
+* <<proxy.adoc,proxy>>
+* <<proxy-inner-tunnel.adoc,proxy inner tunnel>>
+* <<radius-acct.adoc,radius acct>>
+* <<robust-proxy-accounting.adoc,robust proxy accounting>>
+* <<soh.adoc,soh>>
+* <<status.adoc,status>>
+* <<tacacs.adoc,tacacs>>
+* <<tls.adoc,tls>>
+* <<tls-cache.adoc,tls cache>>
+* <<virtual.example.com.adoc,virtual example com>>
+* <<vmps.adoc,vmps>>