Seth Woolley's Man Viewer

thttpd(8) - thttpd - tiny/turbo/throttling HTTP server - man 8 thttpd

([section] manual, -k keyword, -K [section] search, -f whatis)
man plain no title

thttpd(8)                                                            thttpd(8)

       thttpd - tiny/turbo/throttling HTTP server

       thttpd  [-C  configfile]  [-p  port]  [-d dir] [-dd data_dir] [-r|-nor]
       [-s|-nos] [-v|-nov] [-g|-nog] [-u user] [-c cgipat] [-t throttles]  [-h
       host(1,5)]  [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage] [-V]

       thttpd is a simple, small, fast, and secure HTTP  server.   It  doesn't
       have  a  lot  of special features, but it suffices for most uses of the
       web, it's about as fast as  the  best  full-featured  servers  (Apache,
       NCSA,  Netscape), and it has one extremely useful feature (URL-traffic-
       based throttling) that no other server currently has.

       -C     Specifies a config-file to read.  All options can be set(7,n,1 builtins)  either
              by  command-line  flags  or  in(1,8)  the config(1,5) file.  See below for

       -p     Specifies an alternate port number to listen(1,2,7) on.  The default is
              80.   The  config-file  option name for this flag is "port", and
              the config.h option is DEFAULT_PORT.

       -d     Specifies a directory to chdir() to at startup.  This is  merely
              a  convenience  -  you could just as easily do a cd in(1,8) the shell
              script that invokes the program.  The  config-file  option  name
              for  this  flag  is  "dir", and the config.h options are WEBDIR,

       -r     Do a chroot(1,2)() at initialization time(1,2,n), restricting file(1,n) access(2,5) to
              the  program's  current  directory.   If  -r  is the compiled-in
              default, then -nor disables it.  See  below  for  details.   The
              config-file  option  names for this flag are "chroot(1,2)" and "noch-
              root", and the config.h option is ALWAYS_CHROOT.

       -dd    Specifies a directory to chdir() to after chrooting.  If  you're
              not chrooting, you might as well do a single chdir() with the -d
              flag.  If you are chrooting, this lets you put the web files  in(1,8)
              a  subdirectory  of the chroot(1,2) tree, instead of in(1,8) the top level
              mixed in(1,8) with the chroot(1,2) files.  The config-file option name for
              this flag is "data_dir".

       -nos   Don't  do  explicit  symbolic  link(1,2)  checking.  Normally, thttpd
              explicitly expands any symbolic links  in(1,8)  filenames,  to  check
              that the resulting path stays within the original document tree.
              If you want to turn off this check and save some CPU  time(1,2,n),  you
              can  use  the -nos flag, however this is not recommended.  Note,
              though, that if(3,n) you are using the  chroot(1,2)  option,  the  symlink
              checking  is  unnecessary  and is turned off, so the safe way to
              save those CPU cycles is to use chroot.  The config-file  option
              names for this flag are "symlinkcheck" and "nosymlinkcheck".

       -v     Do el-cheapo virtual(5,8) hosting.  If -v is the compiled-in default,
              then -nov disables it.  See below for details.  The  config-file
              option  names  for  this flag are "vhost" and "novhost", and the
              config.h option is ALWAYS_VHOST.

       -g     Use a global passwd(1,5) file.  This means that  every  file(1,n)  in(1,8)  the
              entire  document  tree is protected by the single .htpasswd file(1,n)
              at the  top  of  the  tree.   Otherwise  the  semantics  of  the
              .htpasswd file(1,n) are the same.  If this option is set(7,n,1 builtins) but there is
              no .htpasswd file(1,n) in(1,8) the top-level directory, then  thttpd  pro-
              ceeds  as  if(3,n) the option was not set(7,n,1 builtins) - first looking for a local
              .htpasswd file(1,n), and if(3,n) that doesn't exist  either  then  serving
              the  file(1,n)  without  any  password.   If  -g  is  the compiled-in
              default, then -nog disables it.  The  config-file  option  names
              for  this  flag are "globalpasswd" and "noglobalpasswd", and the
              config.h option is ALWAYS_GLOBAL_PASSWD.

       -u     Specifies what user  to  switch(1,n)  to  after  initialization  when
              started  as  root.   The  default  is "nobody".  The config-file
              option name for this flag is "user", and the config.h option  is

       -c     Specifies  a  wildcard  pattern  for  CGI programs, for instance
              "**.cgi" or "/cgi-bin/*".  See below for details.   The  config-
              file(1,n)  option  name  for  this flag is "cgipat", and the config.h
              option is CGI_PATTERN.

       -t     Specifies a file(1,n) of throttle settings.  See below  for  details.
              The config-file option name for this flag is "throttles".

       -h     Specifies  a  hostname to bind(2,n,1 builtins) to, for multihoming.  The default
              is to bind(2,n,1 builtins) to all hostnames supported on the local machine.  See
              below for details.  The config-file option name for this flag is
              "host(1,5)", and the config.h option is SERVER_NAME.

       -l     Specifies a file(1,n) for logging.  If no -l argument  is  specified,
              thttpd  logs  via  syslog(2,3,5,3 Sys::Syslog)().   If  "-l  /dev/null" is specified,
              thttpd doesn't log at all.  The config-file option name for this
              flag is "logfile".

       -i     Specifies  a  file(1,n)  to  write(1,2)  the process-id to.  If no file(1,n) is
              specified, no process-id is written.  You can use this  file(1,n)  to
              send(2,n) signals to thttpd.  See below for details.  The config-file
              option name for this flag is "pidfile".

       -T     Specifies the character set(7,n,1 builtins) to use with text  MIME  types.   The
              default  is  iso-8859-1.   The  config-file option name for this
              flag is "charset", and the config.h option is DEFAULT_CHARSET.

       -P     Specifies a P3P server privacy header to be  returned  with  all
              responses.   See  for  details.   Thttpd
              doesn't do anything at all with the string(3,n) except put it in(1,8)  the
              P3P: response header.  The config-file option name for this flag
              is "p3p".

       -M     Specifies the number of seconds to be used in(1,8) a  "Cache-Control:
              max-age"  header  to be returned with all responses.  An equiva-
              lent "Expires" header is also  generated.   The  default  is  no
              Cache-Control  or  Expires  headers, which is just fine for most
              sites.  The config-file option name for this flag is  "max_age".

       -V     Shows the current version(1,3,5) info.

       -D     This  was  originally  just a debugging flag, however it's worth
              mentioning because one of the things it does is  prevent  thttpd
              from  making itself a background daemon.  Instead it runs in(1,8) the
              foreground like a regular program.  This is necessary  when  you
              want  to  run  thttpd  wrapped  in(1,8)  a  little  shell script that
              restarts it if(3,n) it exits.

       All the command-line options can also be set(7,n,1 builtins) in(1,8)  a  config(1,5)  file.   One
       advantage  of  using a config(1,5) file(1,n) is that the file(1,n) can be changed, and
       thttpd will pick up the changes with a restart.

       The syntax of the config(1,5) file(1,n)  is  simple,  a  series  of  "option"  or
       "option=value"  separated  by  whitespace.  The option names are listed
       above with their corresponding command-line flags.

       chroot(1,2)() is a system call that restricts  the  program's  view  of  the
       filesystem  to  the  current  directory  and  directories below it.  It
       becomes impossible for remote users(1,5) to access(2,5) any file(1,n) outside  of  the
       initial directory.  The restriction is inherited by child processes, so
       CGI programs get it too.  This is a very strong security  measure,  and
       is recommended.  The only downside is that only root can call chroot(1,2)(),
       so this means the program must be started as root.  However,  the  last
       thing it does during initialization is to give up root access(2,5) by becom-
       ing another user, so this is safe.

       The program  can  also  be  compile-time  configured  to  always  do  a
       chroot(1,2)(), without needing the -r flag.

       Note that with some other web servers, such as NCSA httpd, setting up a
       directory tree for use with chroot(1,2)() is complicated, involving creating
       a  bunch  of  special  directories  and copying in(1,8) various files.  With
       thttpd it's a lot easier, all you have to do is make sure  any  shells,
       utilities,  and  config(1,5) files used by your CGI programs and scripts are
       available.  If you have CGI disabled, or if(3,n) you make a policy that  all
       CGI programs must be written in(1,8) a compiled language such as C and stat-
       ically linked, then you probably don't have to do any setup(2,8) at all.

       However, one thing you should do is tell syslogd about the chroot(1,2) tree,
       so that thttpd can still generate syslog(2,3,5,3 Sys::Syslog) messages.  Check your system's
       syslodg man(1,5,7) page for how to do this.  In FreeBSD you  would  put  some-
       thing like this in(1,8) /etc/rc.conf:
           syslogd_flags="-l /usr/local/www/data/dev/log"
       Substitute  in(1,8) your own chroot(1,2) tree's pathname, of course.  Don't worry
       about creating the log socket(2,7,n), syslogd wants to do that  itself.   (You
       may need to create the dev directory.)  In Linux the flag is -a instead
       of -l, and there may be other differences.

       Relevant config.h option: ALWAYS_CHROOT.

       thttpd supports the CGI 1.1 spec.

       In order for a CGI program to be run, its name must match  the  pattern
       specified  either  at  compile  time(1,2,n) or on the command line with the -c
       flag.  This is a simple shell-style filename pattern.  You can use * to
       match  any  string(3,n)  not  including  a  slash, or ** to match any string(3,n)
       including slashes, or ? to match any single character.   You  can  also
       use  multiple  such  patterns separated by |.  The patterns get checked
       against the filename part of the incoming URL.  Don't forget  to  quote
       any wildcard characters so that the shell doesn't mess with them.

       Restricting  CGI  programs to a single directory lets the site adminis-
       trator review them for security holes, and is strongly recommended.  If
       there  are individual users(1,5) that you trust, you can enable their direc-
       tories too.

       If no CGI pattern is specified, neither here nor at compile time(1,2,n),  then
       CGI  programs  cannot  be  run at all.  If you want to disable CGI as a
       security measure, that's how you do it, just comment out  the  patterns
       in(1,8) the config(1,5) file(1,n) and don't run with the -c flag.

       Note:  the current working directory when a CGI program gets(3,n) run is the
       directory that the CGI program lives in.  This isn't  in(1,8)  the  CGI  1.1
       spec, but it's what most other HTTP servers do.

       Relevant   config.h   options:  CGI_PATTERN,  CGI_TIMELIMIT,  CGI_NICE,

       Basic Authentication is available as an option  at  compile  time.   If
       enabled,  it  uses  a  password  file(1,n) in(1,8) the directory to be protected,
       called .htpasswd by default.  This file(1,n) is formatted  as  the  familiar
       colon-separated  username/encrypted-password pair, records delimited by
       newlines.  The protection does not carry over to  subdirectories.   The
       utility  program  htpasswd(1)  is  included  to  help create and modify
       .htpasswd files.

       Relevant config.h option: AUTH_FILE

       The throttle file(1,n) lets you set(7,n,1 builtins)  maximum  byte  rates  on  URLs  or  URL
       groups.   You can optionally set(7,n,1 builtins) a minimum rate too.  The format of the
       throttle file(1,n) is very simple.  A # starts a comment, and  the  rest  of
       the  line  is ignored.  Blank lines are ignored.  The rest of the lines
       should consist of a pattern, whitespace, and a number.  The pattern  is
       a  simple  shell-style filename pattern, using ?/**/*, or multiple such
       patterns separated by |.

       The numbers in(1,8) the file(1,n) are byte rates, specified in(1,8) units(1,7) of bytes per
       second.  For comparison, a v.90 modem gives about 5000 B/s depending on
       compression, a double-B-channel ISDN line about 12800  B/s,  and  a  T1
       line  is  about 150000 B/s.  If you want to set(7,n,1 builtins) a minimum rate as well,
       use number-number.

         # throttle file(1,n) for

         **              2000-100000  # limit total web usage to 2/3 of our T1,
                                      # but never go below 2000 B/s
         **.jpg|**.gif   50000   # limit images to 1/3 of our T1
         **.mpg          20000   # and movies to even less(1,3)
         jef/**          20000   # jef's pages are too popular

       Throttling is  implemented  by  checking  each  incoming  URL  filename
       against  all  of the patterns in(1,8) the throttle file.  The server accumu-
       lates statistics on how much bandwidth each pattern has  accounted  for
       recently  (via a rolling average).  If a URL matches a pattern that has
       been exceeding its specified limit, then the data returned is  actually
       slowed  down,  with  pauses between each block.  If that's not possible
       (e.g. for CGI programs) or if(3,n) the bandwidth has gotten way larger  than
       the  limit,  then  the  server returns a special code saying 'try again

       The minimum rates are implemented similarly.  If too  many  people  are
       trying  to  fetch  something at the same time(1,2,n), throttling may slow down
       each connection so much that it's not really useable.  Furthermore, all
       those  slow  connections  clog(1,3) up the server, using up file(1,n) handles and
       connection slots.  Setting a minimum rate  says  that  past  a  certain
       point  you  should  not even bother - the server returns the 'try again
       later" code and the connection isn't even started.

       There is no provision for setting a maximum  connections/second  throt-
       tle,  because  throttling a request uses as much cpu(5,8,8 cpu-ldap) as handling it, so
       there would be no point.  There is also no provision for throttling the
       number of simultaneous connections on a per-URL basis.  However you can
       control the overall number of connections for  the  whole  server  very
       simply,  by  setting the operating system's per-process file(1,n) descriptor
       limit before starting thttpd.  Be sure to set(7,n,1 builtins) the hard limit,  not  the
       soft limit.

       Multihoming  means  using one machine to serve multiple hostnames.  For
       instance, if(3,n) you're an internet provider and you want  to  let  all  of
       your   customers   have   customized  web  addresses,  you  might  have,, and  your  own,  all
       running  on  the same physical hardware.  This feature is also known as
       "virtual(5,8) hosts".  There are three steps to setting this up.

       One, make DNS entries for all of the hostnames.  The current way to  do
       this, allowed by HTTP/1.1, is to use CNAME aliases, like so: IN A IN CNAME IN CNAME
       However,  this  is  incompatible  with older HTTP/1.0 browsers.  If you
       want to stay compatible, there's  a  different  way  -  use  A  records
       instead, each with a different IP address, like so: IN A IN A IN A
       This  is  bad  because  it  uses  extra IP addresses, a somewhat scarce
       resource.  But if(3,n) you want people with older browsers  to  be  able  to
       visit your sites, you still have to do it this way.

       Step two.  If you're using the modern CNAME method of multihoming, then
       you can skip this step.  Otherwise, using the older multiple-IP-address
       method  you must set(7,n,1 builtins) up IP aliases or multiple interfaces for the extra
       addresses.  You can use ifconfig(8)'s alias command to tell the machine
       to answer to all of the different IP addresses.  Example:
         ifconfig le0
         ifconfig le0 alias
         ifconfig le0 alias
       If  your OS's version(1,3,5) of ifconfig doesn't have an alias command, you're
       probably   out   of    luck    (but    see

       Third  and  last,  you must set(7,n,1 builtins) up thttpd to handle the multiple hosts.
       The easiest way is with the  -v  flag,  or  the  ALWAYS_VHOST  config.h
       option.   This works with either CNAME multihosting or multiple-IP mul-
       tihosting.  What it does is send(2,n) each incoming request to  a  subdirec-
       tory  based  on  the hostname it's intended for.  All you have to do in(1,8)
       order to set(7,n,1 builtins) things up is to create those subdirectories in(1,8) the  direc-
       tory where thttpd will run.  With the example above, you'd do like so:
       If  you're  using  old-style  multiple-IP multihosting, you should also
       create symbolic links from the numeric addresses to the names, like so:
         ln -s
         ln -s
         ln -s
       This lets the older HTTP/1.0 browsers find the right subdirectory.

       There's  an  optional  alternate step three if(3,n) you're using multiple-IP
       multihosting: run a separate thttpd process for  each  hostname,  using
       the  -h flag to specify which one is which.  This gives you more flexi-
       bility, since you can run each of these processes in(1,8) separate  directo-
       ries, with different throttle files, etc.  Example:
         thttpd -r -d /usr/www -h
         thttpd -r -d /usr/www/joe -u joe -h
         thttpd -r -d /usr/www/jane -u jane -h
       But  remember,  this  multiple-process  method does not work with CNAME
       multihosting - for that, you must use a single thttpd process with  the
       -v flag.

       thttpd lets you define your own custom error(8,n) pages for the various HTTP
       errors.  There's a separate file(1,n) for each error(8,n) number, all  stored  in(1,8)
       one  special  directory.  The directory name is "errors", at the top of
       the web directory tree.  The error(8,n) files should be named(5,8) "errNNN.html",
       where  NNN is the error(8,n) number.  So for example, to make a custom error(8,n)
       page for the authentication failure error(8,n), which  is  number  401,  you
       would  put  your HTML into the file(1,n) "errors/err401.html".  If no custom
       error(8,n) file(1,n) is found for a given error(8,n) number, then the  usual  built-in
       error(8,n) page is generated.

       If  you're  using the virtual(5,8) hosts option, you can also have different
       custom error(8,n) pages for each different virtual(5,8) host.  In this  case  you
       put  another  "errors"  directory in(1,8) the top of that virtual(5,8) host(1,5)'s web
       tree.  thttpd will look(1,8,3 Search::Dict) first in(1,8) the virtual(5,8) host(1,5) errors directory, and
       then  in(1,8)  the server-wide errors directory, and if(3,n) neither of those has
       an appropriate error(8,n) file(1,n) then it will generate the built-in error.

       Sometimes another site on the net will embed your image files in(1,8)  their
       HTML files, which basically means they're stealing your bandwidth.  You
       can prevent them from doing this by using non-local referer  filtering.
       With  this  option,  certain files can only be fetched via a local ref-
       erer.  The files have to be referenced by a local web page.  If  a  web
       page  on  some  other  site  references  the  files, that fetch will be
       blocked.  There are three config-file variables for this feature:

       urlpat A wildcard pattern for the URLs that should require a local ref-
              erer.   This  is typically just image files, sound files, and so
              on.  For example:
              For most sites, that one setting is all you need to enable  ref-
              erer filtering.

              By  default, requests with no referer at all, or a null referer,
              or a referer with no apparent hostname, are allowed.  With  this
              variable set(7,n,1 builtins), such requests are disallowed.

              A wildcard pattern that specifies the local host(1,5) or hosts.  This
              is used to determine if(3,n) the host(1,5) in(1,8) the referer is local or not.
              If not specified it defaults to the actual local hostname.

       thttpd is very picky about symbolic links.  Before delivering any file(1,n),
       it first checks each element in(1,8) the path to  see  if(3,n)  it's  a  symbolic
       link(1,2), and expands them all out to get the final actual filename.  Along
       the way it checks for things like links with ".."  that  go  above  the
       server's  directory,  and absolute symlinks (ones that start with a /).
       These are prohibited as security holes, so the server returns an  error(8,n)
       page  for  them.  This means you can't set(7,n,1 builtins) up your web directory with a
       bunch of symlinks pointing to individual users(1,5)' home  web  directories.
       Instead  you  do it the other way around - the user web directories are
       real subdirs of the main web directory, and in(1,8)  each  user's  home  dir
       there's a symlink pointing to their actual web dir.

       The  CGI  pattern is also affected - it gets(3,n) matched against the fully-
       expanded filename.  So, if(3,n) you have a single CGI directory but then put
       a  symbolic  link(1,2)  in(1,8) it pointing somewhere else, that won't work.  The
       CGI program will be treated as a  regular  file(1,n)  and  returned  to  the
       client, instead of getting run.  This could be confusing.

       thttpd  is  also  picky  about  file(1,n)  permissions.  It wants data files
       (HTML, images) to be world readable.  Readable by the  group  that  the
       thttpd process runs as is not enough - thttpd checks explicitly for the
       world-readable bit.  This is so that no one ever gets(3,n)  surprised  by  a
       file(1,n)  that's  not set(7,n,1 builtins) world-readable and yet somehow is readable by the
       HTTP server and therefore the *whole* world.

       The same logic applies to directories.  As with the standard Unix  "ls"
       program,  thttpd  will only let you look(1,8,3 Search::Dict) at the contents of a directory
       if(3,n) its read(2,n,1 builtins) bit is on; but as with data files, this must be the  world-
       read(2,n,1 builtins) bit, not just the group-read bit.

       thttpd  also  wants the execute bit to be *off* for data files.  A file(1,n)
       that is marked executable but doesn't match the CGI pattern might be  a
       script  or  program  that got accidentally left in(1,8) the wrong directory.
       Allowing people to fetch the contents of the file(1,n) might be  a  security
       breach,  so this is prohibited.  Of course if(3,n) an executable file(1,n) *does*
       match the CGI pattern, then it just gets(3,n) run as a CGI.

       In summary, data files should  be  mode  644  (rw-r--r--),  directories
       should  be  755  (rwxr-xr-x)  if(3,n)  you  want  to  allow indexing and 711
       (rwx--x--x) to disallow it, and CGI programs should be mode 755  (rwxr-
       xr-x) or 711 (rwx--x--x).

       thttpd  does all of its logging via syslog(2,3,5,3 Sys::Syslog)(3).  The facility it uses is
       configurable.  Aside from error(8,n) messages, there  are  only  a  few  log
       entry types of interest, all fairly similar to CERN Common Log Format:
         Aug  6 15:40:34 acme thttpd[583]: - - "GET /file(1,n)" 200 357
         Aug  6 15:40:43 acme thttpd[583]: - - "HEAD /file(1,n)" 200 0
         Aug  6 15:41:16 acme thttpd[583]: referer -> /dir
         Aug  6 15:41:16 acme thttpd[583]: user-agent Mozilla/1.1N
       The  package  includes  a script for translating these log entries info(1,5,n)
       CERN-compatible files.  Note that thttpd does not translate numeric  IP
       addresses  into domain names.  This is both to save time(1,2,n) and as a minor
       security measure (the numeric address is harder to spoof).

       Relevant config.h option: LOG_FACILITY.

       If you'd rather log directly to a file(1,n), you can use the -l command-line
       flag.  But note that error(8,n) messages still go to syslog.

       thttpd handles a couple of signals, which you can send(2,n) via the standard
       Unix kill(1,2,1 builtins)(1) command:

              These  signals  tell  thttpd  to  shut  down  immediately.   Any
              requests in(1,8) progress get aborted.

       USR1   This  signal(2,7) tells thttpd to shut down as soon as it's done ser-
              vicing all current requests.  In addition, the network socket(2,7,n) it
              uses  to  accept(2,8)  new connections gets(3,n) closed immediately, which
              means a fresh thttpd can be started up immediately.

       USR2   This signal(2,7) tells thttpd to generate the statistics syslog(2,3,5,3 Sys::Syslog)  mes-
              sages  immediately,  instead  of  waiting for the regular hourly

       HUP    This signal(2,7) tells thttpd to close(2,7,n) and re-open  its  (non-syslog)
              log  file(1,n),  for  instance if(3,n) you rotated the logs and want it to
              start using the new one.  This is a little tricky to set(7,n,1 builtins) up cor-
              rectly, for instance if(3,n) you are using chroot(1,2)() then the log file(1,n)
              must be within the chroot(1,2) tree, but it's definitely doable.

       redirect(8),   ssi(8),   makeweb(1),   htpasswd(1),    syslogtocern(8),
       weblog_parse(1), http_get(1)

       Many  thanks  to contributors, reviewers, testers: John LoVerso, Jordan
       Hayes, Chris Torek, Jim Thompson, Barton  Schaffer,  Geoff  Adams,  Dan
       Kegel,  John  Hascall, Bennett Todd, KIKUCHI Takahiro, Catalin Ionescu.
       Special thanks to Craig Leres for substantial  debugging  and  develop-
       ment, and for not complaining about my coding style very much.

       Copyright    1995,1998,1999,2000 by Jef Poskanzer <>.  All
       rights reserved.

                               29 February 2000                      thttpd(8)

References for this manual (incoming links)