Man Linux: Main Page and Category List

NAME

       /etc/yaws/yaws.conf - Configuration file for the yaws web server

DESCRIPTION

       Yaws  is  fast  lightweight  web  server. It reads a configuration file
       called yaws.conf to control its operations. The configuration  contains
       two  distinct  parts  a global part which affects all the virtual hosts
       and a server part where options for each virtual host is supplied.

GLOBAL PART

       logdir = Directory
              All yaws logs will be written to files in this directory.  There
              are several different log files written by yaws.

              report.log  - this is a text file that contains all error logger
              printouts from yaws.

              Host.access - for each virtual  host  served  by  yaws,  a  file
              Host.access  will  be  written  which  contains an access log in
              Common Log Format.

              trace.http - this file  contains  the  HTTP  trace  if  that  is
              enabled

              auth.log  -  If  configured, all http auth related messages goes
              here.

              trace.traffic - this file contains the traffic trace if that  is
              enabled

              The default value for logdir is "."

        ebin_dir = Directory
              This  directive  adds Directory to the Erlang search path. It is
              possible to have several of these command in  the  configuration
              file. The default value is "yaws_dir"/examples/ebin

        id = String
              It is possible run multiple yaws servers on the same machine. We
              use the id of a yaws server to control it  using  the  different
              control commands such as:

              # /usr/local/bin/yaws --id foobar --stop

              To  stop the Yaws server with id "foobar". Each Yaws server will
              write its internals data into a file called  $HOME/.yaws/yaws/ID
              where  ID  the  identity of the server. Yaws also creates a file
              called  ${VARDIR}/run/yaws/ctl-${ID}  which  contain  the   port
              number  where  the server is listening for control commands. The
              default id is "default".

        include_dir = Directory
              This directive adds Directory to the path of  directories  where
              the  Erlang  compiler searches for include files. We need to use
              this if we want to include .hrl files in our yaws  Erlang  code.
              The default value is "yaws_dir"/examples/include.

        max_num_cached_files = Integer
              Yaws will cache small files such as commonly accessed GIF images
              in RAM.  This directive sets a maximum number on the  number  of
              cached files.  The default value is 400.

        max_num_cached_bytes = Integer
              This  directive  controls  the  total  amount  of  RAM which can
              maximally be used for cached RAM files.  The  default  value  is
              1000000, 1 megabyte.

        max_size_cached_file = Integer
              This  directive  sets  a  maximum size on the files that are RAM
              cached by yaws.  The default value i 8000, 8 kBytes.

        cache_refresh_secs = Integer
              The RAM cache is used to serve pages that sit in the  cache.  An
              entry  sits  in  cache  at  most  cache_refresh_secs  number  of
              seconds. The default is 30. This means that when the content  is
              updated  under  the  docroot,  that change doesn’t show until 30
              seconds have passed. While developing a yaws  site,  it  may  be
              convenient  to  set  this  value to 0. If the debug flag (-d) is
              passed to the yaws start script, this value is automatically set
              to 0.

       trace  = false | traffic | http
              This  enables  traffic or http tracing. Tracing is also possible
              to enable with a command line flag to yaws. Default is false.

       use_old_ssl = true | false
              This re-enables the old OTP ssl implementation.  By  default  we
              use the new ssl implementation.

        auth_log  = true | false
              Enable or disable the auth log. Default is true.

        max_connections = nolimit | <int>
              Set this value to control the maximum number of connections from
              HTTP clients into the server. This is implemented by closing the
              last socket if the limit threshold is reached.

        log_wrap_size = Integer
              The logs written by yaws are all wrap logs, the default value at
              the size where they wrap around and the original gets renamed to
              File.old is 1000000, 1 megabyte. This value can changed.

              If we set the value to 0 the logs will never wrap. If we want to
              use Yaws in combination with a more traditional log wrapper such
              as  logrotate,  set  the  size  to  0  and  Yaws will reopen the
              logfiles once they have be renamed/removed.

       log_resolve_hostname = true | false
              By default the client host IP is  not  resolved  in  the  access
              logs.

       fail_on_bind_err = true | false
              Fail  completely  or  not  if yaws fails to bind a listen socket
              Default is true.

       enable_soap = true | false
              If true, a soap server will  be  started  at  startup  of  Yaws.
              Default is false.

       soap_srv_mods = ListOfModuleSetting
              If   enable_soap   is   true,   a   startup   yaws  will  invoke
              yaws_soap_srv:setup() to setup modules set here.   ModuleSetting
              is  either  a  triad  like  <Mod,  HandlerFunc,  WsdlFile>  or a
              quadruple form like <Mod, HandlerFunc, WsdlFile,  Prefix>  which
              specifies  the  prefix.  A  prefix  will  be used as argument of
              yaws_soap_lib:initModel() and then be used as  a  XML  namespace
              prefix.  Note, the WsdlFile here should be an absolute-path file
              in local file systems.

              For example, we can specify

                   soap_srv_mods=<Mod1,     HandlerFunc,      WsdlFile1><Mod2,
              HandlerFunc, WsdlFile2, SpecifiedPrefix>...

       php_exe_path = Path
              The  name  of  (and possibly path to) the php executable used to
              interpret php scripts (if allowed).  Default is  php_exe_path  =
              php-cgi.

        copy_error_log  = true | false
              Enable  or  disable  copying  of  the  error log. When we run in
              embedded mode, there may very well be some other systems process
              that  is  responsible for writing the errorlog to a file whereas
              when we run in normal standalone mode,  we  typically  want  the
              Erlang  errorlog written to a report.log file.  Default value is
              true.

       runmod = ModuleName
              At startup yaws will invoke  ModuleName:start()  in  a  separate
              process. It is possible to have several runmods.  This is useful
              if we want to reuse the yaws startup shell script  for  our  own
              application.

        pick_first_virthost_on_nomatch = true | false
              When  Yaws gets a request, it extracts the Host: header from the
              client request to choose a virtual server  amongst  all  servers
              with  the  same  IP/Port  pair.   This  configuration  parameter
              decides whether yaws should pick the first (as  defined  in  the
              yaws.conf  file)  if no name match or not.  In real live hosting
              scenarios  we  typically  want  this  to  be  false  whereas  in
              testing/development  scenarios it may be convenient to set it to
              true. Default is true.

        use_fdsrv = true | false
              This feature makes it possible to bind to ports < 1024 even when
              we’re  not  running  as  root.  It  requires the Jungerl package
              called fd_server to be properly installed. The  feature  doesn’t
              work  with  SSL.  Default  is  false.   The  use of fdsrv is not
              encouraged, see http://yaws.hyber.org/privbind.yaws

        subconfig = File
              Load specified config file.

        subconfigdir = Directory
              Load all config file in specified directory.

SERVER PART

       Yaws can virthost several web servers on the same IP address as well as
       several  web  servers  on  different  IP  addresses.  This includes SSL
       servers.

       Each virtual  host  is  defined  within  a  matching  pair  of  <server
       ServerName>  and  </server>.  The  ServerName  will  be the name of the
       webserver.

       The following directives are allowed inside a server definition.

       port = Port
              This makes the server listen on Port. Default is 8000.

       listen = IpAddress
              This makes the  server  listen  on  IpAddress  When  virthosting
              several  servers  on  the  same  ip/port address, if the browser
              doesn’t send a Host: field, yaws  will  pick  the  first  server
              specified  in  the  config file.  If the specified ip address is
              0.0.0.0 yaws will listen  on  all  local  IP  addresses  on  the
              specified port. Default is 0.0.0.0.

       listen_backlog = Integer
              This  sets  the  TCP listen backlog for the server to define the
              maximum length the queue of pending connections may grow to. The
              default is the same as the default provided by gen_tcp:listen/2,
              which is 5.

       rhost = Host[:Port]
              This forces all local redirects issued by the server  to  go  to
              Host.   This  is  useful  when  yaws  listens to a port which is
              different from the port that the user connects to. For  example,
              running  yaws  as  a  non-privileged user makes it impossible to
              listen to port 80, since that port  can  only  be  opened  by  a
              privileged  user.  Instead  yaws  listens  to a high port number
              port, 8000, and iptables are used to redirect traffic to port 80
              to port 8000 (most NAT:ing firewalls will also do this for you).

       rscheme = http | https
              This forces all local redirects issued by the server to use this
              method.  This  is  useful when an SSL off-loader, or stunnel, is
              used in front of yaws.

       access_log = true | false
              Setting this directive to false turns  of  traffic  logging  for
              this virtual server. The default value is true.

       dir_listings = true | true_nozip | false
              Setting  this  directive  to  false  disallows the automatic dir
              listing feature of Yaws. A status code  403  Forbidden  will  be
              sent.   Set  to  true_nozip  to avoid the auto-generated all.zip
              entries. Default is false.

       extra_cgi_vars = .....
              Add additional CGI or FastCGI variables. For example:

              <extra_cgi_vars dir=’/path/to/some/scripts’>
              var = val
              ...
              </extra_cgi_vars>

       statistics  = true | false
              Turns on/off statistics gathering for a virtual server.  Default
              is false.

       fcgi_app_server = Host:Port
              The  hostname  and  TCP  port  number of the FastCGI application
              server.  The TCP port number  is  not  optional.   There  is  no
              default value.

       fcgi_trace_protocol = true | false
              Enable  or  disable tracing of FastCGI protocol messages as info
              log messages.  Disabled by default.

       fcgi_log_app_error = true | false
              Enable or disable logging of application error messages:  output
              to stderr and non-zero exit value.  Disabled by default.

       deflate = true | false
              Turns  on  or  off  deflate compression for a server. Default is
              false.

        docroot = Directory ...
              This makes the server serve all its content from Directory.

              It is possible to pass a space separated list of directories  as
              docroot.  If  this  is the case, the various directories will be
              searched in order for the requested file. This also  works  with
              the  ssi  and yssi constructs where the full list of directories
              will be searched for files to ssi/yssi include.

       partial_post_size = Integer | nolimit
              When a yaws file  receives  large  POSTs,  the  amount  of  data
              received in each chunk is determined by the this parameter.  The
              default value is 10240.

       dav = true | false
              Turns on the DAV protocol for this server. The  dav  support  in
              yaws is highly limited. If dav is turned on, .yaws processing of
              .yaws pages is turned off. Default  is  false.   Setting  it  to
              nolimit  is  potentially dangerous. There is a hardcoded timeout
              on POST reads at 30 seconds.  If the read is not done within the
              timeout, the POST will fail.

       tilde_expand = true|false
              If  this  value  is  set  to  false  yaws  will  never  do tilde
              expansion.  The  default  is  false.  tilde_expansion   is   the
              mechanism whereby a URL on the form http://www.foo.com/~username
              is changed into a request where the docroot for that  particular
              request  is  set to the directory ~username/public_html/ Default
              is false.

       allowed_scripts = ListOfSuffixes
              The allowed  script  types  for  this  server.   Recognized  are
              ‘yaws’, ‘cgi’, ‘fcgi’, ‘php’.  Default is allowed_scripts = yaws
              php cgi fcgi .

              Note: for fcgi scripts, the FastCGI application server  is  only
              called if a local file with the .fcgi extension exists. However,
              the contents of the local .fcgi file are ignored.

       tilde_allowed_scripts = ListOfSuffixes
              The allowed script types for this server when executing files in
              a  users  public_html  folder   Recognized  are  ‘yaws’,  ‘cgi’,
              ‘fcgi’, ‘php’.  Default is tilde_allowed_scripts = i.e. empty

       appmods = ListOfModuleNames
              If any the names in ListOfModuleNames appear  as  components  in
              the  path for a request, the path request parsing will terminate
              and that module will be  called.  There  is  also  an  alternate
              syntax  for specifying the appmods if we don’t want our internal
              erlang module names to be exposed in  the  URL  paths.   We  can
              specify

                 appmods = <Path1, Module1> <Path2, Modules2> ...

              Assume     for     example     that     we    have    the    URL
              http://www.hyber.org/myapp/foo/bar/baz?user=joe  while  we  have
              the  module  foo defined as an appmod, the function foo:out(Arg)
              will be invoked instead of searching the filesystems  below  the
              point foo.

              The Arg argument will have the missing path part supplied in its
              appmoddata field.

              It is also possible to exclude certain directories  from  appmod
              processing.  This  is  particulaly  interesting for ’/’ appmods.
              Here is an example:

                 appmods = </, myapp exclude_paths icons js top/static>

              The above configuration will invoke the ’myapp’ erlang module on
              everything  except  any file found in directories, ’icons’, ’js’
              and ’top/static’ relative to the docroot.

       errormod_404 = Module
              It is possible to set a special  module  that  handles  404  Not
              Found messages.

              The  function  Module:out404(Arg,  GC,  SC) will be invoked. The
              arguments are

              Arg is a #arg{} record

              GC is a #gconf{} record (defined in yaws.hrl)

              SC is a #sconf{} record (defined in yaws.hrl)

              The function can and must do the same things that a normal out/1
              does.

       errormod_401 = Module
              It  is  possible  to  set  a  special  module  that  handles 401
              Unauthorized messages. This can for example be used to display a
              login page instead.

              The  function  Module:out401(Arg) will be invoked. The arguments
              are

              Arg is a #arg{} record

              The function can and must do the same things that a normal out/1
              does.

       errormod_crash = Module
              It  is  possible  to  set a special module that handles the HTML
              generation of server crash messages. The default is  to  display
              the  entire  formated crash message in the browser. This is good
              for debugging but not in production.

              The function Module:crashmsg(Arg, SC, Str) will be  called.  The
              Str is the real crash message formated as a string.

              The function must return, {content,MimeType,Cont} or {html, Str}
              or {ehtml, Term}. That data will be shipped to the client.

       arg_rewrite_mod = Module
              It is possible to install a module that  rewrites  all  the  Arg
              #arg{}  records  at an early stage in the yaws server.  This can
              be used  to  do  various  things  such  as  checking  a  cookie,
              rewriting paths etc.

       start_mod = Module
              Defines  a  user  provided  callback  module.  At startup of the
              server, Module:start/1 will  be  called.   The  #sconf{}  record
              (defined  in  yaws.hrl) will be used as the input argument. This
              makes it possible for a  user  application  to  synchronize  the
              startup  with  the  yaws  server as well as getting hold of user
              specific  configuration  data,  see  the  explanation  for   the
              <opaque> context.

       revproxy = Prefix Url
              Make  yaws  a reverse proxy. The Prefix is a path inside our own
              docroot and the Url argument is an url pointing to a website  we
              want to "mount" under the path which is Prefix.

              Example: revproxy = /tmp/foo http://yaws.hyber.org

              Makes the hyber website appear under /tmp/foo

              It  is possible to have multiple reverse proxies inside the same
              server.

              WARNING, this feature is yet not in production quality.

       fwdproxy = true|false
              Make yaws a forward proxy. By enabling this option you  can  use
              yaws   as  a  proxy  for  outgoing  web  traffic,  typically  by
              configuring the proxy settings in a  web-browser  to  explicitly
              target yaws as its proxy server.

              WARNING, this feature is yet not in production quality.

       servername = Name
              If  we’re  virthosting everal servers and want to force a server
              to match  specific  Host:  headers  we  can  do  this  with  the
              "servername" directive. This name doesn’t necessarily have to be
              the same as the the name inside <server  Name>  in  certain  NAT
              scenarios. Rarely used feature.

        <ssl>  .... </ssl>
              This begins and ends an SSL configuration for this server.  It’s
              possible to virthost several SSL servers on the  same  IP  given
              that  they  all  share  the  same certificate configuration.  In
              general it is complicated to virthost several SSL servers on the
              same  IP  address  since the certificate is typically bound to a
              domainname in the common name  part  of  the  certificate.   One
              solution  (the  only?)  to this problem is to have a certificate
              with           multiple           subjectAltNames.           See
              http://wiki.cacert.org/VhostTaskForce#Interoperability_Test

        keyfile = File
              Specifies   which   file   contains  the  private  key  for  the
              certificate.  If not specified then the certificate file will be
              used.

        certfile = File
              Specifies which file contains the certificate for the server.

        cacertfile = File
              A  file  containing  trusted  certificates  to use during client
              authentication and to use when attempting to  build  the  server
              certificate  chain.   The  list  is  also  used  in  the list of
              acceptable client CAs passed to the client when a certificate is
              requested.

        verify = 1 | 2 | 3
              Specifies  the  level  of verification the server does on client
              certs.  1 means nothing, 2 means the the  server  will  ask  the
              client  for  a cert but not fail if the client does not supply a
              client cert, 3 means that the  server  requires  the  client  to
              supply a client cert.

        depth = Int
              Specifies the depth of certificate chains the server is prepared
              to follow when verifying client  certs.  For  the  OTP  new  ssl
              implementation  it  is  also used to specify how far the server,
              i.e. we, shall follow the SSL certificates  we  present  to  the
              clients.  Hence,  using  self signed certs, we typically need to
              set this to 0.

        password = String
              String If the private key is encrypted on disc, this password is
              the 3Dee key to decrypt it.

        ciphers = String
              This  string  specifies the SSL cipher string. The syntax of the
              SSL cipher string is a little horrible sublanguage of  its  own.
              It is documented in the ssl man page for "ciphers".

        </ssl>
              Ends an SSL definition

       <redirect> ... </redirect>
              Defines  a  redirect  mapping.  The  following items are allowed
              within a matching pair of <redirect> and </redirect> delimiters.

              We can have a series of

               Path = URL or

               Path = file

              All   accesses  to  Path  will  be  redirected  to  URL/Path  or
              alternatively to scheme:host:port/file/Path if a file  is  used.
              Note  that  the original path is appended to the redirected url.
              So if we for example have:

              <redirect>
                /foo = http://www.mysite.org/zapp
                /bar = /tomato.html
              </redirect>

              Asumming this config resides on a site called http://abc.com, We
              have the following redirects:

              http://abc.com/foo -> http://www.mysite.org/zapp/foo

              http://abc.com/foo/test -> http://www.mysite.org/zapp/foo/test

              http://abc.com/bar -> http://abc.com/bar

              http://abc.com/bar/x/y/z -> http://abc.com/bar/x/y/z

              Sometimes  we  do not want to have the original path appended to
              the redirected path. To get that behaviour we specify the config
              with ’==’ instead of ’=’.

              <redirect>
                /foo == http://www.mysite.org/zapp
                /bar = /tomato.html </redirect>

              Now   a   request   for   http://abc.com/foo/x/y/z  simply  gets
              redirected to http://www.mysite.org/zapp. This is typically used
              when  we  simply  want  a  static  redirect at some place in the
              docroot.

              When we specify a file as target for  the  redirect,  the  redir
              will be to the current http(s) server.

       <auth> ... </auth>
              Defines  an  auth  structure.  The  following  items are allowed
              within a matching pair of <auth> and </auth> delimiters.

       dir = Dir
              Makes Dir to be controlled bu WWW-authenticate headers. In order
              for   a  user  to  have  access  to  WWW-Authenticate  controled
              directory, the user must supply a  password.  The  Dir  must  be
              specified relative to the docroot.

       realm = Realm
              In the directory defined here, the WWW-Authenticate Realm is set
              to this value.

       authmod = AuthMod
              If an auth module is defined then AuthMod:auth(Arg,  Auth)  will
              be  called  for all access to the directory. The auth/2 function
              should return one of:  true,  false,  {false,  Realm},  {appmod,
              Mod}.   If {appmod, Mod} is returned then a call to Mod:out(Arg)
              will be used to deliver the content.

              This  can,  for   example,   be   used   to   implement   cookie
              authentication.   The  auth()  callback  would  check if a valid
              cookie header is  present,  if  not  it  would  return  {appmod,
              ?MODULE}  and the out/1 function in the same module would return
              {redirect_local, "/login.html"}.

       user = User:Password
              Inside this directory, the user User  has  access  if  the  user
              supplies  the  password Password in the popup dialogue presented
              by the browser.  We can obviously have several  of  these  value
              inside a single <auth> </auth> pair.

              The  usage  of  User:Password  in  the  actual  config  file  is
              deprecated as of release 1.51. It is preferred to have the users
              in  a  file  called  .yaws_auth  in  the  actual  directory. The
              .yaws_auth file has to be file parseable by file:consult/1

              Each row of the file must contain terms on the form

              {User, Password}.

              Where both User and Password should be strings.  The  .yaws_auth
              file  mechanism  is not (yet) recursive. Thus any subdirectories
              to Dir are not automatically also protected.

              The .yaws_auth file is never visible in a dir listing

       pam service = pam-service
              If the item pam is part of the auth structure,  Yaws  will  also
              try  to  authenticate the user using "pam" using the pam service
              indicated. Usual services are typically found under  /etc/pam.d.
              Usual values are "system-auth" etc.

              pam  authentication is performed by an Erlang port program which
              is typically installed as suid root by the yaws install  script.

       </auth>
              Ends an auth definition

        <opaque>  .... </opaque>
              This  begins  and  ends an opaque configuration context for this
              server, where ’Key = Value’ directives can be  specified.  These
              directives  are ignored by yaws (hence the name opaque), but can
              be accessed as a  list  of  tuples  {Key,Value}  stored  in  the
              #sconf.opaque  record  entry.  See  also  the description of the
              start_mod directive.

              This mechanism can be used  to  pass  data  from  a  surrounding
              application into the individual .yaws pages.

EXAMPLES

       The following example defines a single server on port 80.

       logdir = /var/log/yaws
       <server www.mydomain.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www
       </server>

       And  this example shows a similar setup but two web servers on the same
       IP address

       logdir = /var/log/yaws
       <server www.mydomain.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www
       </server>

       <server www.funky.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www_funky_org
       </server>

       An example with www-authenticate and no access logging at all.

       logdir = /var/log/yaws
       <server www.mydomain.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www
               access_log = false
               <auth>
                   dir = secret/dir1
                   realm = foobar
                   user = jonny:verysecretpwd
                   user = benny:thequestion
                   user = ronny:havinganamethatendswithy
              </auth>

       </server>

       An example specifying  a user defined module to be called
       at startup, as well as some user specific configuration.

       <server www.funky.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www_funky_org
               start_mod = btt
               <opaque>
                       mydbdir = /tmp
                       mylogdir = /tmp/log
               </opaque>
       </server>

       An example specifying the GSSAPI/SPNEGO module (authmod_gssapi)  to  be
       used  for authentication. This module requires egssapi version 0.1~pre2
       or later available at http://www.hem.za.org/egssapi/.

       The Kerberos5 keytab is specified  as  ’keytab  =  File’  directive  in
       opaque.  This  keytab  should  contain  the  keys  of  the HTTP service
       principal, ’HTTP/www.funky.org’ in this example.

       <server www.funky.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www_funky_org
               start_mod = authmod_gssapi
               <auth>
                       authmod = authmod_gssapi
                       dir = secret/dir1
               </auth>
               <opaque>
                       keytab = /etc/yaws/http.keytab
               </opaque>
       </server>

       And finally a slightly more complex example with  two  servers  on  the
       same IP, and one SSL server on a different IP.

       When  there  are  more  than  one  server on the same IP, and they have
       different names the server must be able to choose one of  them  if  the
       client  doesn’t  send  a  Host:  header. yaws will choose the first one
       defined in the conf file.

       logdir = /var/log/yaws
       max_num_cached_files = 8000
       max_num_cached_bytes = 6000000

       <server www.mydomain.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www
       </server>

       <server www.funky.org>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www_funky_org
       </server>

       <server www.funky.org>
               port = 443
               listen = 192.168.128.32
               docroot = /var/yaws/www_funky_org
               <ssl>
                  keyfile = /etc/funky.key
                  certfile = /etc/funky.cert
                  password = gazonk
               </ssl>
       </server>

       Finally an example with virtual directories, vdirs.

       <server server.domain>
               port = 80
               listen = 192.168.128.31
               docroot = /var/yaws/www
               arg_rewrite_mod = yaws_vdir
               <opaque>
                 vdir = "/virtual1/ /usr/local/somewhere/notrelated/to/main/docroot"
                 vdir = "/myapp/ /some/other/path can include/spaces"
                 vdir = "/icons/  /usr/local/www/yaws/icons"
               </opaque>
        </server>

       The  first  defined  vdir  can   then   be   accessed   at   or   under
       http://server.domain/virtual1/  or http://server.domain/virtual1

AUTHOR

       Written by Claes Wikstrom

SEE ALSO

       yaws(1) erl(1)