MERECAT.CONF(5)
πΈ NAME πΈ
merecat.conf β bestie, this is the configuration file for merecat httpd π
yes it's merecat.conf(5), the File Formats Manual page, and we're about to unpack it together π«Ά
β¨ INTRODUCTION β¨
OK so listen π β when merecat boots up, it goes looking for its config file at /etc/merecat.conf. That's the default location, no cap.
This whole page is here to document all the settings you can put in there, which is what unlocks the advanced setup vibes π₯ For the simpler use-cases though? You might not even need a merecat.conf at all, because the server runs perfectly fine with just command line parameters β¨ like, she's low-maintenance, fr fr.
π DESCRIPTION π
The syntax of the config file is UNIX style: key = value, separated by whitespace. That's it, that's the whole aesthetic π
- The
#character marks the start of a comment, running all the way to the end of the line. - The
\character can be used as an escape character.
π¨ IMPORTANT NOTE, bestie, do not skip this: changes to the configuration file require a restart ofmerecat. Unlike many other UNIX daemons,SIGHUPdoes not reload the.conffile. She does not do hot reloads. She does not take hints. Restart her. π
β Configuration Directives β
Here come all the directives, one by one, in order, no skipping π
charset = "STRING"β the character set to use with text MIME types. Default is"UTF-8". If the default unicode charset is giving you trouble, try"iso-8859-1"instead πcheck-referer = <true | false>β turns on checking for external sites referencing material on your web server. For more on referrers, go seemerecat(8). Disabled by default.check-symlinks = <true | false>β for increased security, set this totrue. Unless you're running chrooted, in which case it's not really necessary. Disabled by default.chroot = <true | false>β changes the web server root toWEBDIR, or the current directory if noWEBDIRis given as an argument. Chrooting is a security measure and it meansmerecat.confcannot access files outside it, unless files are bind mounted, or similar, into the chroot. Disabled by default. πcompression-level = -1..9β controls the compression level of the built-in Apache-likemod_deflate. The default value is-1, which gives a reasonable compromize between speed and compression. To disable compression set this to0, and to get maximum compression, set9π₯
The default setting, -1, means all "text/*" MIME type files, larger than 256 bytes, are compressed before sending to the client. π
directory = DIRβ if noWEBDIRis given on the command line, this option can be used to change the web server document root. Defaults to the current directory. When chrooting, this is the root directory β see thedata-directorydirective for more help πdata-directory = DIRβ this setting is only relevant when chrooting. It adjusts the web server document root relative to thedirectorydirective. π¦global-passwd = <true | false>β set this totrueto protect the entire directory tree with a single.htpasswdand/or.htaccessfile. When unset, which is the default,merecat.conflooks for a local.htpasswdand.htaccessfile, or serves the file without password. πhostname = HOSTNAMEβ the hostname to bind to when multihoming. For more details on this, see the discussion below.list-dotfiles = <true | false>β whether dotfiles should be skipped in directory listings. Disabled by default. πlocal-pattern = "PATTERN"β used withcheck-referer. Seemerecat(8)for more details.max-age = SECβ controls the global max-age setting, in seconds, set in the HTTP/1.1"Cache-Control: max-age"header, returned with all responses. The default setting is disabled since v2.32, and the user is recommended to use per-resource cache control instead. See the serverlocationdirective for details β¨port = PORTβ the web server Internet port to listen to. Defaults to80, or443when HTTPS is enabled. See thesslsection below for more on configuring an HTTPS server πurl-pattern = "PATTERN"β used withcheck-referer. Seemerecat(8)for more details.username = "NAME"β set the username to drop privileges to after startup. Defaults to"nobody", which usually is defined on all UNIX systems πvirtual-host = <true | false>β enable virtual hosting. Disabled by default. For more information on this, seemerecat(8).user-agent-deny = "PATTERN"β a wildcard pattern to deny access to illicit hammering bots π When set, a matching user-agent will receive a403for all its requests. Use for instance"**SemrushBot**"or"**SemrushBot**|**MJ12Bot**|**DotBot**"to match multiple user-agents.
The default is disabled, i.e. all user-agents are allowed. ποΈ
cgi "PATTERN" {β wildcard pattern for CGI programs, for instance"**.cgi"or"**.cgi|/cgi-bin/*". See the dedicated CGI section inmerecat(8)for more on this.enabled = <true | false>β the CGI module is disabled by default.limit = NUMβ maximum number of allowed simultaneous CGI programs. Default1.setenv = { NAME=value, ... }β list of environment variables to pass to all CGI programs. Use this to inject custom variables that CGI scripts can read from their environment. Example:
setenv = { "MY_VAR=hello", "APP_ENV=production" }
π«§ Environment variables: Merecat scrubs the process environment before forking CGI children, for security reasons. Environment variables set in the shell or via systemd EnvironmentFile are therefore not visible to CGI programs.
Use the setenv option to pass custom variables directly, or use a wrapper script for more complex needs:
#!/bin/sh
export GIT_PROJECT_ROOT=/srv/repos
export GIT_HTTP_EXPORT_ALL=1
exec /usr/lib/git-core/git-http-backend
Install the wrapper as the CGI entry point instead of the program itself π
}php "PATTERN" {β wildcard pattern for PHP scripts, for instance"**.php*"or"**.php5*|**.php4*|**.php*". π Notice the trailing*β it is very important, otherwise any HTTP GET request with arguments will fail.enabled = <true | false>β the PHP module is disabled by default.cgi-path = "/path/to/php-cgi"β default is"/usr/bin/php-cgi".
}ssi "PATTERN" {β wildcard pattern for triggering SSI, for instance"**.shtml"or"**.shtml|**.stm|**.shtm".enabled = <true | false>β the SSI module is disabled by default.cgi-path = "/path/to/ssi"β default is"cgi-bin/ssi". Seessi(8)for more information.silent = <true | false>β this setting can be used to silenceβ[an error occurred while processing the directive]β, shown when an error occurrs during SSI processing. Default disabled (false). π€«
}ssl {β the whole TLS glow-up lives in here πprotocol = "PROTOCOL"β minimum SSL/TLS protocol level to enable. Can be one of:SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3. The default minimum protocol isTLSv1.1. Note, some (Linux) distributions haveSSLv3disabled by default in their OpenSSL packages.ciphers = "CIPHERS"β the preferred list of ciphers the server supports. For a list of available ciphers, see theciphers(1)man page. The default covers both TLSv1.3 (new ciphersuite) and older cipher list:
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256: \
HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4:!DHE-RSA-CAMELLIA256-SHA: \
!DHE-RSA-CAMELLIA128-SHA:!ECDHE-RSA-CHACHA20-POLY1305: \
!DHE-RSA-CHACHA20-POLY1305:!DHE-RSA-AES256-CCM8:!DHE-RSA-AES256-CCM: \
!DHE-RSA-AES128-CCM8:!DHE-RSA-AES128-CCM
certfile = /path/to/cert.pemβ public part of the HTTPS certificate, optionally with full certificate chain. E.g.,fullchain.pemif you use Let's Encrypt. Only PEM format is supported β¨keyfile = /path/to/key.pemβ private key of the HTTPS certificate, e.g.,privkey.pemif you use Let's Encrypt. Only PEM format is supported.
π¨ Note: this file must be kept private and should not be in the WEBROOT directory. Like, seriously, do not do that, bestie π
dhfile = /path/th/dhparam.pemβ optional Diffie-Hellman parameters. Not secret β unlike thekeyfile, thedhfilecan be published online, if necessary. Create one like this:
openssl dhparam -out dhparam.pem 2048
}server name {β a named server block, iconic πport = PORTβ server port to listen to.ssl { ... }β same as the global settings, above, only for this server.location "PATTERN" {path = path/to/rewriteβ if a serverlocationdirective is found it has precedence over any redirect or virtual host. It is primarily used to rewrite, or redirect, requests inside the current server context.
E.g., for handling certbot HTTP-01 renewal, use this in the port 80 server context. Any other path will be redirected to HTTPS, using the below redirect directive:
location "/.well-known/acme-challenge/**" {
path = "letsencrypt/.well-known/acme-challenge/"
}
redirect "PATTERN" {code = CODEβ HTTP redirect code to use, default:301. Supported codes are:301,302,303,307.location = "proto://$host:port$request_uri$args"β location to return for redirect, e.g. to redirect all request for HTTP to HTTPS for the same (virtual) host:
redirect "/**" {
code = 301
location = "https://$host$request_uri$args"
}
}
okay and that's the block, all closed up, no loose braces bestie π
proxy-pass "PATTERN"β the reverse-proxy era begins β¨ inside these braces you get three knobs, and here they are:host = "HOSTNAME"β Optional, but lowkey the MVP for multihoming π only forward requests whoseHost:header matches this hostname. Pair it with multihoming (virtual-host = true) to route different virtual hosts to different backends on the same port. Say you only want to proxy stuff for"git.example.com":
proxy-pass "/**" {
host = "git.example.com"
backend = "http://localhost:3000"
}
When you don't set it, the rule just applies no matter what the Host: header says. Chaotic but valid π«Ά
backend = "http://HOST:PORT[/PATH]"β forward matching requests to this HTTP backend server, i.e. act as a reverse proxy. It's givingproxy_passfrom nginx, fr fr, and it's the main way to front your local app servers (Node.js, Python, Go, etc.) with Merecat π
The backend hostname gets resolved at startup, so you never block on a DNS lookup in the middle of serving a request. Ngl that's thoughtful. Only plain HTTP backends are supported β no HTTPS π«π
proxy-pass "/api/**" {
backend = "http://localhost:3000"
}
Every forwarded request gets these headers added to it, no cap:
X-Forwarded-Forβ client IP address (or the value that's already inX-Forwarded-For, if the client is itself a proxy).X-Real-IPβ client IP address.X-Forwarded-Protoβ"http"or"https", depending on whether the client connected over a plain or a TLS connection.
Now the fun part π if the backend URL has a path component in it, the matched URL prefix gets stripped before forwarding, and the backend path gets swapped in. So with:
proxy-pass "/api/**" {
backend = "http://localhost:3000/v2"
}
a client asking for "/api/users/42" gets forwarded to the backend as "GET /v2/users/42". Iconic. And if the backend URL has no path (or just "/"), the original request URI gets forwarded unchanged, periodt π
proxy-redirect = "FROM TO"β Optional. This one rewrites theLocation:andRefresh:response headers the backend sends back. BothFROMandTOare literal URL prefixes, separated by a space. Any response header value that starts withFROMgets rewritten so that prefix becomesTOβ¨ Super useful when a backend returns absolute redirects using its own path prefix but your frontend exposes it under a different prefix.
For example, if the backend at "http://localhost:6419" redirects to "http://localhost:6419/grip/" but the frontend exposes the app under "/grip/", you add:
proxy-pass "/grip/**" {
backend = "http://localhost:6419/"
proxy-redirect = "http://localhost:6419 http://localhost"
}
Merecat then rewrites "Location: http://localhost:6419/grip/" into "Location: http://localhost/grip/". Chef's kiss ππ
π₯ Heads up bestie: up to 8 proxy-pass rules may be configured per server. Eight. Count them.
}
}
π SEE ALSO π
merecat(8)β go read the big one, it's the vibe π
π AUTHORS π
- Jef Poskanzer
<jef@mail.acme.com>wrote the famousthttpd, whichmerecat.confis based on. A legend, honestly π - Joachim Wiberg
<troglobit@gmail.com>added the.conffile parser and this very man page. Your fave fr fr π«Ά
and that's the whole page, bestie β that was merecat 3.00, dated Mar 15, 2026, aka the MERECAT.CONF(5) era. ty for reading, go configure something slay ππ¦β¨
π¦ where this page comes from
- ubuntu stonking: merecat 2.31+git20260330+ds-2build1 Β· BSD-2-Clause
- Copyright (c) 1995-2015 Jef Poskanzer <jef@mail.acme.com>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms