tipidee
Software
skarnet.org
The /etc/tipidee.conf configuration file
Goal and usage
/etc/tipidee.conf is a text file written by the web administrator
to configure the tipideed server. After writing
or modifying this file, the administrator is expected to run the
tipidee-config program, that will read
/etc/tipidee.conf and output a /etc/tipidee.conf.cdb file
that will be suitable for tipideed to use.
tipidee-config provides sane defaults,
so an empty /etc/tipidee.conf file is perfectly usable
for purely static installations. But an empty file still needs to be
created, unless tipidee-config is run
with the -i /dev/null option.
Description
The /etc/tipidee.conf file contains a series of lines; every line is an
instruction. Lines do not wrap around and there is no quoting, so a newline is
always the end of an instruction. Empty lines, or lines containing only
whitespace, or lines beginning with # (comments), are ignored.
If a line contains a # that is not in the middle or end of a word, the
rest of the line is also considered a comment, and ignored.
Words on a line are separated by whitespace (spaces or tabs).
Instructions are one directive, the first word in the line, followed by
one or more arguments. Most directives take a fixed number of
arguments; some of them take a variable number. There are several types
of directives.
Preprocessing directives
These are meta-directives: they do not control tipideed's
behaviour directly, but tell tipidee-config to
include other files. They allow administrators and packagers to write modular, pluggable
configuration files. Preprocessing directives always start with a !
(exclamation point, or bang) character.
You will probably never see preprocessing directives in simple configuration files.
They are meant for bigger or more generic configurations.
The !include directive
!include file
- This directive will replace itself with the contents of file.
- file can be a relative or absolute path. If relative, then
it is relative to the directory of the file being currently processed, i.e.
the file containing the !include directive. In other words, things
will work as you intuitively expect.
The !includedir directive
!includedir dir
- This directive will include every file in directory dir.
- File names starting with a . (dot) will be ignored (i.e. not included).
- The inclusion order is deterministic: file names are sorted according to the C locale.
- dir can be a relative or absolute path. If relative, then
it is relative to the directory of the file being currently processed, i.e.
the file containing the !includedir directive. In other words, things
will work as you intuitively expect.
The !included: directive
!included: unique
!included: multiple
- This directive is usually written at the beginning of a file. Only one
such directive per file is allowed.
- !included: governs what happens when a file is included
more than once.
- If a file contains an !included: unique line, then all
inclusions of this file after the first one will be ignored: the contents
of the file will appear only once.
- If a file contains an !included: multiple line, then the
file will be expanded into its contents every time the file is
included.
- If a file does not contain an !included: directive, then
including it twice is an error, and
tipidee-config-preprocess,
the program in charge of the preprocessing directives, will complain and
exit.
- Don't forget the : (colon) at the end of the !included:
directive!
Simple global settings
Global directives control global aspects of tipideed
— values that apply to the server itself, no matter what domain it is
serving.
Some global directives are introduced by their own keywords, see below.
Others are simple configuration values that would clutter up the
directive namespace, so we put them together under a unique umbrella,
the global directive.
global takes two arguments: the name of a setting and its value.
read_timeout
global read_timeout t
- t is a non-negative integer, in milliseconds. It represents
the maximum duration that a client is allowed to be idle.
- If t milliseconds elapse without the client sending a request,
tipideed will assume it is done, close the
connection and exit. Also, if t milliseconds elapse while the client
is sending a request, and the request is still not complete,
tipideed will also close the connection.
- The default is 0, meaning infinite: tipideed
will never slam the door into a client's face, even if the client is
excessively slow or fails to close a connection it's not using anymore.
- A good setting is global read_timeout 60000, closing connections
after one minute of inactivity.
write_timeout
global write_timeout t
- t is a non-negative integer, in milliseconds. It represents
the maximum duration that tipideed will accept
to wait when sending data to the client.
- If t milliseconds elapse while tipideed
is sending data to the client, tipideed will
give up and exit with an error message.
- This typically happens when the network is congested, and the kernel's
socket send buffers are full. It could also mean that a client is failing to
read the data it has requested; or that the data is very large and
taking time to transfer.
- The default is 0, meaning infinite: tipideed
will wait forever until the network uncongests and its client starts to behave.
- An example setting is global write_timeout 600000, closing connections
if a transfer takes more than 10 minutes; but servers serving large files to
clients on slow connections will want a larger value.
cgi_timeout
global cgi_timeout t
- t is a non-negative integer, in milliseconds. It represents
the maximum duration that a CGI script spawned by
tipideed is allowed to run.
- If t milliseconds elapse while a CGI script is running, and
tipideed hasn't gotten a full response yet,
the script will be killed, and tipideed will
send a 504 (Gateway Timeout) response to the client.
- The default is 0, meaning infinite: tipideed
will wait forever until CGI scripts write their output.
- An example setting is global cgi_timeout 10000, giving any
CGI scripts 10 seconds to complete — most users aren't willing to wait
more than a few seconds for a page to render anyway.
max_request_body_length
global max_request_body_length n
- n is a non-negative integer, in bytes. It represents the
maximum size that tipideed will accept for
the body of an HTTP request.
- If the client sends a request with a body larger than n bytes,
tipideed will send a 413 (Content Too Large)
response and close the connection.
- The default is 8192, which is large enough for most.
- An example setting is global max_request_body_length 500,
when the administrator knows that no script on the site needs an input of
more than 500 bytes and anything larger is malicious.
max_cgi_body_length
global max_cgi_body_length n
- n is a non-negative integer, in bytes. It represents the
maximum size that tipideed will accept for
a CGI script's answer that it needs to process.
- If a CGI script writes more than n bytes to its stdout,
tipideed will send a 502 (Bad Gateway)
response to the client and die with an error message.
- This limit does not apply to NPH scripts, which send their stdout
directly to the client without any processing by tipideed.
- The default is 4194304 (4 mebibytes).
- An example setting is global max_cgi_body_length 100000000,
when the administrator knows that CGI scripts can write up to 100 megabytes.
Note that the CGI specification forces web servers to read the whole CGI
output in memory, so the larger the value, the more RAM
tipideed may consume in order to hold CGI
output data. And this is "private dirty" memory, i.e. memory that
really counts towards resource use on your server, so be careful with
that setting — and with the CGI scripts you choose to run.
executable_means_cgi
global executable_means_cgi value
- value is a non-negative integer. If it is nonzero, then
all the documents that have an executable bit for "others" will be
considered CGI scripts by default.
- This is useful when your CGI scripts are scattered among your
documents and you cannot gather them under a hierarchy like /cgi-bin/.
- On the other hand, it should only be used by administrators who keep a
tight control on their documents. It is dangerous to activate this option
with dynamically managed content, because there could be files created with
the wrong permissions and improperly identified as CGI scripts, resulting in
failures or even security holes.
- The classification of a given executable file as a CGI script
can be overridden by a local noncgi directive, see below. Such
a directive can protect dynamically managed content that is restricted
to a given hierarchy.
XXX_no_translate
global XXX_no_translate value
- This directive is dangerous and significantly changes the behaviour of tipideed,
which is why it is marked with the XXX_ prefix. If you are not 100% certain
that you need it, do not use it.
- value is a non-negative integer. If it is nonzero, then:
- Symbolic links are not resolved when tipidee looks for resources
or error pages. This means that host names and resource paths will be looked up
in the configuration database as they are given by the client, not as they appear
in the filesystem.
- In particular, a same resource could have different attributes depending on how
it is accessed: it could be seen as a CGI script from one URI and as a regular file from
another.
- This also means that if your configuration file needs local directives, you must
specify them for every host/port combination your server is listening on.
- If tipideed is not chrooted, symbolic links may point outside of the
server root: this will not be checked. This allows you to serve data from other parts
of the filesystem.
The index-file directive
index-file file1 file2 ...
index-file is a global directive, the first one in this
list that is introduced by its own keyword and does not use global.
- The index-file directive has a variable number of
arguments. file1, file2, and so on are the names of the
files that should be used to try and complete the URI when a client request
resolves to a directory.
- For instance: index-file index.cgi index.html index.htm
means that when tipideed is asked to serve
http://example.com, it will first try to serve as if the request
had been http://example.com/index.cgi, then
http://example.com/index.html, then http://example.com/index.htm.
The first resource found is the one that is served; if none of the
resources exist, tipideed responds 404 (Not Found).
- This is valid for any subdirectory: http://example.com/foo, if the
/foo resource resolves to a directory, is expanded to
http://example.com/foo/index.cgi, then (if not found)
http://example.com/foo/index.html, then (if not found)
http://example.com/foo/index.htm.
- The default is index-file index.html, meaning that
only the index.html file will be looked up when a resource resolves
to a directory.
The log directive
log is a global directive, introduced by the
keyword log. It allows the user to control what will appear in
tipideed's log output.
log nothing
log keyword1 keyword2 ...
- tipideed writes all its logs to stderr.
It prints fatal error messages
with the prefix "tipideed: pid pid: fatal: ",
and warning messages
with the prefix "tipideed: pid pid: warning: ".
In normal operation, if everything goes well, you should never see
any of these.
- Depending on what the log directive says, it also prints
informational messages related to what it's doing. These informational
messages all have the prefix "tipideed: pid pid: info: ".
- One line when tipideed starts and one
when it exits, if the log directive includes the start keyword.
- Up to three lines per client request, controlled by the request,
resource and answer keywords. If you have a CGI script outputting
local redirections (which is rare), there may be several resource lines.
- If no log directive has been provided, the default is
log request answer answer_size.
Here is the full list of keywords and what they do:
- nothing
- Don't log anything else than warning and error messages. This
keyword cannot be given with other keywords.
- start
- Log a start line when tipideed starts
and an exit exitcode line when it exits.
- ip
- Add an ip client_ip field to the start line.
This is potentially PII, so make sure to stay compliant with your local laws if you activate it.
client_ip is read from the TCPREMOTEIP environment variable.
This keyword has no effect when given without the start keyword.
- hostname
- Add a host client_hostname field to the start line.
This is potentially PII, so make sure to stay compliant with your local laws if you activate it.
client_hostname is read from the TCPREMOTEHOST environment variable if it exists, or made up from
TCPREMOTEIP otherwise. Make sure to invoke
s6-tcpserver-access before
tipideed in order to get meaningful values for this field.
This keyword has no effect when given without the start keyword.
- host_as_prefix
- Prepend all request, resource and answer
lines with a host host field. (This field will not be repeated in the request
line, so it changes the order of the fields in that line.) host is the virtual host the request is addressed
to. host_as_prefix is useful when you want to log entries for different virtual hosts to
different locations: for instance, if you're using
s6-log, and want entries for example.com and
example.org to be logged to different backends, you would use the host_as_prefix directive,
and use
- +"^tipidee: pid [[:digit:]]*: info: host example\\.com "
in your logging script
to select example.com-related lines, and
- +"^tipidee: pid [[:digit:]]*: info: host example\\.org "
to select example.org-related lines. Note that warning and error messages would still need an additional
backend, as well as potential start and exit lines.
- request
- Log a request line when tipideed
receives a request from its client. The line looks like request method host host path "path"
http version. The path is decoded, but if there are non-printable characters in it, they are
encoded as hexadecimal values \0xab. If the request line includes a query, a query query field
is added before the http field.
- referrer
- Add a referrer "referrer" field to the request line, for
requests that include a Referer: header. referrer is quoted like path, to avoid
malicious clients messing with log lines.
This keyword has no effect when given without the request keyword.
- user-agent
- Add a user-agent "user-agent" field to the request line, for
requests that include a User-Agent: header. user-agent is quoted like path, to avoid
malicious clients messing with log lines.
This keyword has no effect when given without the request keyword.
- x-forwarded-for
- Add an x-forwarded-for "xff" field to the request line, for
requests that include an X-Forwarded-For: header. xff is quoted like path and user-agent,
for the same reasons.
This keyword has no effect when given without the request keyword.
Note that if the connection is proxied, the start line, if any, will only have information about
the proxy, and only x-forwarded-for will have information about the client. Also note that
the information in an X-Forwarded-For: header is potentially PII, so make sure to stay
compliant with your local laws if you activate the option.
- resource
- Log a resource line when tipideed
has found a resource corresponding to the URI and is willing to serve it. The line looks like
resource file type type.
file is the path to the served file; the first component of that path is always
the document root of the virtual host. type
is nph for an NPH script, cgi for a CGI script, or the Content-Type for a regular file.
If it's a CGI or NPH script being called with a non-empty PATH_INFO, an additional path_info path_info
field is added to the log line.
If a served CGI script outputs a local redirection, several resource lines may appear for
a single request.
- answer
- Log an answer line when tipideed
answers the currently processed request. The line looks like answer status, where status is
the 3-digit status code returned to the client. Note that there will be no answer line
when a NPH script is being run (because tipideed execs into the
NPH script).
- answer_size
- Add a size size field to the answer line,
containing the Content-Length of the answer.
This keyword has no effect when given without the answer keyword.
- debug
- Log debug information. You should not need this in regular use.
The content-type directive
content-type is a global directive, introduced by the
keyword content-type. It allows
the user to define mappings from a document's extension to a standard Content-Type.
content-type type extension1 extension2 ...
- Files ending with extension1, extension2, and so on, will be served
to clients with the Content-Type: type header.
- Extensions must be listed with their initial dot.
- Example: content-type text/html .html .htm means that files
ending in .html or .htm should be served as text/html.
- As a special case, content-type some/thing "" means that files without an
extension should be served as some/thing.
- tipidee already comes with a
large
list of default Content-Type mappings; this directive should only be necessary if you're
serving files with uncommon extensions or have specific needs.
custom-header is global directive, introduced by the
keyword custom-header. It allows
the user to define custom headers that are to be added to every response.
It takes a subcommand, that is used to define what should be done with
the header:
custom-header add name value
custom-header always name value
custom-header remove name
custom-header never name
- custom-header add tells tipidee to add a header named name
with the value value to all its answers. A CGI script can override value
by providing its own name header.
- custom-header always is like custom-header add, except a CGI script
cannot override value, which will always be used.
- custom-header remove tells tipidee to not provide a name
header. This is only useful for a few overridable headers that tipidee provides by default,
such as Content-Security-Policy or Referrer-Policy. If a CGI script
provides such a header, the CGI header will be used despite the directive.
- custom-header never is like custom-header remove, except even a
CGI script cannot provide a name header, which will be stripped from its output.
- Some headers cannot be customized. tipidee-config
will reject an attempt to add, or remove, a Connection header, for instance.
Local directives
All the other directives are local: they only apply to the current domain.
Except for domain, they can only be used after a domain directive.
domain
domain domain
- domain is a special directive in that it is stateful. Instead of
having a direct effect on the configuration, it merely defines the domain that
the next local directives will apply to. domain example.com means
that a subsequent cgi /cgi-bin/ line will declare that a resource
under //example.com/cgi-bin/ is a CGI script.
- The current domain remains defined and active until the next
domain directive.
- Global directives are unaffected by the current domain. It is good
practice to declare global directives before the first domain
line, but it is not mandatory.
- If your resources are accessible via several URIs, the declared domain
should be the canonical one, i.e. the name of the real
directory hosting them, and not the symlinks. E.g. if you are serving files in
the real directory /home/www/docs/example.com, with example.com:80
and example.com:443 being symlinks to example.com, then
domain example.com is the correct declaration for settings that will apply
to these files. And if you are hosting a different set of documents in the real
directory /home/www/docs/example.com:81, and example.com:444 is
a symlink to example.com:81, then these will be affected by the settings
declared under domain example.com:81.
- The point of all this is to make virtual hosting as flexible as possible,
allowing you to have different configurations for different virtual hosts —
including serving different sets of documents for the same host on different ports!)
— without needing to duplicate the configuration when you are serving the same
sets of documents over several ports, e.g. when you're serving both HTTP and HTTPS.
- Complex configurations can benefit from the !include or
!includedir primitives, by putting the configuration related to one domain
in a dedicated file, and having the main /etc/tipidee.conf only declare
global configuration and include all the domain-specific files.
cgi
cgi directory
cgi file
- The cgi directory directive tells
tipideed that under the current domain,
all the files under directory (and its whole sub-hierarchy)
are CGI scripts. directory is absolute (it must start with
a slash, referring to the document root for the current domain), and
must end with a slash as well.
- The cgi file directive tells
tipideed that under the current domain,
file is a CGI script, regardless of its location.
file is absolute (it must start with
a slash, referring to the document root for the current domain), but
must not end with a slash.
- A common use is: cgi /cgi-bin/
- By default, no CGI directories or files are defined, so an
empty tipidee configuration will only serve static files.
noncgi
noncgi directory
noncgi file
- The noncgi directory directive tells
tipideed that under the current domain,
all the files under directory (and its whole sub-hierarchy)
are not CGI scripts.
- The noncgi file directive tells
tipideed that under the current domain,
file is not a CGI script, regardless of its location.
- This is a rare directive, only useful if for some reason you have
a static document under /cgi-bin or equivalent.
nph-prefix
nph-prefix prefix
- This directive tells tipideed that
CGI scripts (recognized as such by a cgi directive) whose name
starts with prefix are
non-parsed header
scripts.
- Common usage is nph-prefix nph- — paired with cgi /cgi-bin/,
this means that under the current domain, scripts of the form
/cgi-bin/nph-foobar are NPH.
nph
nph directory
nph file
- This is an alternative way of specifying which scripts are
NPH.
This directive says that CGI scripts under directory are NPH
(provided they're also recognized as CGI), and that file is NPH
(provided it's also recognized as CGI).
- For instance, having both cgi /cgi-bin/ and nph /cgi-bin/
means that all the CGI scripts under /cgi-bin are considered NPH.
nonnph
nonnph directory
nonnph file
- This is the opposite, saying that CGI scripts under directory,
or CGI script file, are not NPH.
- This is a rare directive, only useful if the vast majority of your
scripts, but not all of them, are NPH.
basic-auth
basic-auth directory
basic-auth file
- This directive tells tipideed that
file file, or all files under directory, are protected
by Basic HTTP
authentication.
- This feature is currently unimplemented, so
tipidee-config will print a warning if
it finds such a directive in your configuration file.
- Implementation of this feature has been delayed because it needs an
additional database to store the resource:user:password tuples,
with more restricted permissions than /etc/tipidee.conf.cdb, since
passwords are confidential information. This is planned in a future version
of tipidee. And yes, existing web servers that make the administrator store
cleartext passwords in the generic configuration file are terrible.
no-auth
no-auth directory
no-auth file
- This is the opposite, saying that files under directory,
or specific file file, do not require authentication.
- This is a rare directive, only useful if you have a whole directory
under basic-auth but want to carve exceptions.
file-type
file-type directory type
file-type file
type
- file-type is similar to content-type,
but local. For files under directory, or for specific file file, it
overrides the default Content-Type associated with their extension, and gives them the
Content-Type type instead.
- file-type /source/ text/plain will serve all files under the current
domain under the /source directory as text/plain.
- file-type /source/file.html text/html will serve /source/file.html
under the current domain as text/html, even with the previous more generic
rule applying to /source.
redirect
redirect resource rtype target
- resource is the URI to redirect, relative to the current domain.
For instance, if the current domain is example.com and resource
is foobar.html, then a request for http://example.com/foobar.html
will be redirected to target.
- rtype is the type of redirection. It is one of the following four numbers:
- 308: permanent redirection
- 307: temporary redirection
- 301: permanent redirection
while allowing the client to change the request method. You generally should not need this.
- 302: temporary redirection
while allowing the client to change the request method. You generally should not need this.
- target is the target of the redirection. It must be a full URL starting
with http:// or https://. (If you want local redirection under the
same virtual domain, this directive is not what you want: instead, you can make a
symbolic link in your filesystem.)
- Unlike files or directories given as arguments in other local directives,
resource does not need to exist in the filesystem.
tipideed processes redirections before looking
up resources in the filesystem. This is more efficient, but comes with a caveat:
a file will only be served if there is no redirection directive for that resource,
so make sure to keep your configuration file up-to-date.
- This also means that the "real directory" rule does not apply to redirections.
Instead, you can declare a redirection under the example.com:80 domain, whether
or not /home/www/docs/example.com:80 is a real directory; the redirection
will only apply to requests received on port 80 (and not, for instance, to
requests received on port 443). But if you declare a redirection under the
example.com domain, it will apply to requests received on any port.
custom-response
custom-response status file
- custom-response allows you to customize the contents of HTTP error
responses for the current domain.
- status is the 3-digit HTTP response code you want to specify a custom response for.
- file is the file containing the body of the HTTP response that will be
sent to the client if tipideed finds that it must answer
with a status code.
- file is used relative to tipideed's working directory (even if
it is given absolute). It does not have to be under the current domain's document root:
it is not a resource, and is not handled as such.
However, file cannot go up the filesystem hierarchy: it will always
be under tipideed's working directory.
- The Content-Type for file is determined by its extension,
and mappings you add via content-type directives will work. However,
since file is not a resource, file-type
directives will not work, even if file is under the current virtual
domain's document root. Don't try to be smart with this. Just name your
custom files e404.html or something.
- The instruction is only valid for status responses to requests
targetting the current domain. You can specify another custom-response,
or even the same one, after the next domain directive.
- An example: custom-response 404 /errors/404.html under
a domain example.com line will mean that the errors/404.html
file will be served as the text/html body of any "404 Not Found" response
tipideed may send to requests addressed to example.com. The
errors subdirectory is at the same level as the example.com
subdirectory.
- If tipideed cannot open file, it will log a warning message
and answer the client with a basic builtin response.
- Not every HTTP status code is used by tipideed. Nothing will happen
if you define custom responses for codes that aren't used.