Merecat httpd ∴ Embedded Web Server
Merecat started out as a pun at Mongoose, but is now useful for actual web serving purposes. It is however not a real Meerkat, merely yet another copycat, forked from the great thttpd created by Jef Poskanzer.
Merecat httpd expands on the features originally offered by thttpd, but still has a limited feature set:
- Virtual hosts
- Basic
.htpassdand.htaccesssupport - URL-traffic-based throttling
- CGI/1.1
- HTTP/1.1 Keep-alive
- Built-in gzip deflate using zlib
- HTTPS support using OpenSSL/LibreSSL, works with Let's Encrypt!
- Dual server support, both HTTP/HTTPS from one process
- HTTP redirect, to gently redirect from HTTP server to HTTPS
- Reverse proxy (
proxy-pass), to front local app servers like nginx does - Native PHP support, using
php-cgiif enabled inmerecat.conf
The resulting footprint (~140 kiB) makes it quick and suitable for small and embedded systems!
Merecat is available as free/open source software under the simplified
2-clause BSD license. For more information, see the manual
page merecat(8), or the FAQ.
The rest of this README covers some basic functions and recommendations. For more in-depth use-case examples, see the following HowTos:
- https://troglobit.com/howtos/merecat-basic-cig-in-c/
- https://troglobit.com/howtos/merecat-and-lets-encrypt/
- https://troglobit.com/howtos/merecat-and-ikiwiki/
- https://troglobit.com/howtos/merecat-and-cgit/
Docker
Try out Docker Merecat safely isolated from the rest of the system, with easy deployment.
Authentication
To protect a directory in your ~USERNAME/public_html/, create the file
.htpasswd using the included htpasswd tool:
user@example:~/> cd public_html/Downloads
user@example:~/public_html/Downloads/> htpasswd -c .htpasswd friend
Changing password for user friend
New password: *****
Re-type new password: *****
Enable this feature, and user home directories, with the configure
script. See more on this in the Features section below.
Virtual Hosts
Setting up virtual hosts on a server can be a bit of a hassle with other web servers. With Merecat you simply create directories for each host in the web server root:
/var/www/
|-- icons/
|-- cgi-bin/
|-- errors/
| `-- err404.html
|-- ftp.example.com/
`- www.example.com/
Edit /etc/merecat.conf:
virtual-host = true
cgi "/cgi-bin/*|**.cgi" {
enabled = true
}
Now the web server root, /var/www/, no longer serves files, only
virtual host directories do, execpt for the shared files in icons/,
cgi-bin/, and errors/.
Merecat scrubs the environment before forking CGI children, so variables
from the shell or systemd EnvironmentFile are not visible to CGI
scripts. Use setenv to inject custom variables:
cgi "/cgi-bin/*|**.cgi" {
enabled = true
setenv = { "GIT_PROJECT_ROOT=/srv/repos", "GIT_HTTP_EXPORT_ALL=1" }
}
On Linux bind mounts can be used to set up FTP and web access to the
same files. Example /etc/fstab:
/srv/ftp /var/www/ftp.example.com none defaults,bind 0 0
Optimizing Performance
There are many tricks to optimizing the performance of your web server.
One of the most important ones is browser caching. Merecat supports
both ETag: and Cache-Control:, however to enable the latter you need
to define the max-age setting in /etc/merecat.conf:
max-age = 3600 # One hour
The value is completely site dependent. For an embedded system you might want to set it to the maximum value, whereas for other scenarios you will likely want something else. By default this is disabled (0).
Another trick is to employ gzip compression. Merecat has built-in
support for serving HTML, CSS, and other text/* files if there is a
.gz version of the same file. Here is an example of how to compress
relevant files:
root@example:~/> cd /var/www/
root@example:/var/www/> for file in `find . -name '*.html' -o -name '*.css'`; do \
gzip -c $file > $file.gz; done
This approach is more CPU friendly than letting Merecat "deflate" files on the fly, which it otherwise does.
HTTPS Support
If configure finds OpenSSL installed, HTTPS support is enabled, this
can be disabled using --without-ssl. However, to gain access to the
SSL/TLS settings you also need support for merecat.conf, so you must
install libConfuse. See below for all Build Requirements.
The HTTPS support has SSLv2, SSLv3, and TLSv1 disabled (hard coded) by default. Only TLSv2 and later will be enabled and negotiated on a per client basis.
To set up Merecat for HTTPS the following /etc/merecat.conf settings
must be enabled:
server secure {
port = 443
ssl {
certfile = /etc/letsencrypt/live/example.com/fullchain.pem
keyfile = /etc/letsencrypt/live/example.com/privkey.pem
dhfile = /etc/letsencrypt/live/example.com/dhparam.pem
}
}
Let's Encrypt
Merecat fully supports Let's Encrypt certificates, including HTTP-01 renewals. Use the server location directive:
server default {
port = 80
location "/.well-known/acme-challenge/**" {
path = "letsencrypt/.well-known/acme-challenge/"
}
redirect "/**" {
code = 301
location = "https://$host$request_uri$args"
}
}
The path must be relative to the server root directory. Use bind
mounts to get /var/lib/letsencrypt into your server root. This way
we can ensure certbot only writes to its own directory and cannot
write to any file in the server root.
Then run certbot with the following arguments and then add all virtual
hosts you want to support from Merecat:
root@example:/var/www/> certbot certonly --webroot --webroot-path /var/lib/letsencrypt
For a HowTo see:
Self-signed Certificate
To create a self signed certificate and enable perfect forward secrecy,
PFS, i.e. Diffie-Helman paramters (optional), use the openssl tool as
shown below. Notice the use of a sub-shell with openssl.cnf where
most of the certificate settings are, and more importantly notice the
use of subjectAltName, or SAN. The latter is required by most
browsers today.
root@example:/var/www/> mkdir private certs
root@example:/var/www/> openssl req -x509 -newkey rsa:4096 -nodes \
-keyout private/server.key -new -out certs/server.pem \
-subj /CN=www.acme.com -reqexts SAN -extensions SAN \
-sha256 -days 3650 -config <(cat /etc/ssl/openssl.cnf \
<(printf '[SAN]\nsubjectAltName=DNS:www.acme.com'))
root@example:/var/www/> openssl dhparam -out certs/dhparm.pem 4096
HTTP Redirect
For a setup with two servers, the following example can be used to run HTTPS on port 4443, HTTP on port 8080 and redirect to the HTTPS server on any access:
server secure {
port = 4443
ssl {
certfile = certs/server.pem
keyfile = private/server.key
dhfile = certs/dhparm.pem
}
}
server default {
port = 8080
redirect "/**" {
code = 303
location = "https://$host:4443$request_uri$args"
}
}
Supported HTTP redirect codes are: 301, 302, 303, and 307.
The location setting supports three nginx style variables as shown in the example. Please note the quotes around the pattern, or the .conf parser will think the pattern is a C-style comment.
Build Requirements
Merecat depends on a few external libraries, if enabled, e.g. OpenSSL, zlib, and libConfuse. On Debian/Ubuntu systems you can install the dependencies with:
user@example:~/> sudo apt install pkg-config libconfuse-dev libssl-dev zlib1g-dev
If you build the deps. from source, they may default to use an install
prefix of /usr/local. Non Debian/Ubuntu systems rarely support this
GNU standard, so here is how you reference it for the Merecat
configure script:
user@example:~/merecat/> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
To build Merecat without support for /etc/merecat.conf:
user@example:~/merecat/> ./configure --without-config
If you build from GIT sources and not a released tarball, then remember:
user@example:~/merecat/> ./autogen.sh
To install httpd into /usr/sbin/, default index and icons into
/var/www, and config file to /etc/merecat.conf:
user@example:~/merecat/> ./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc
user@example:~/merecat/> make
user@example:~/merecat/> sudo make install
Cross compiling Merecat for an another target is possible by setting the
--host flag to the configure script. This is well documented in the
GNU Documentation. Note: usually the --build system is
automatically detected.
Merecat builds are silent by default. For detailed compiler output, disable silent mode with
configure --disable-silent-rules, or build withmake V=1.
Features
Merecat consists of a front-end, merecat.c, and a standalone HTTP
library, libhttpd.c, which can be tweaked in various ways and used
for embedding a web server in another application if needed.
The most common options are available from the merecat command line
and the merecat.conf configuration file. Other, less common options,
can be enabled using the configure script:
--enable-builtin-icons Enable built-in icons for dir listings
--enable-htaccess Enable .htaccess files for access control
--enable-htpasswd Enable .htpasswd files for authentication
--enable-public-html Enable $HOME/public_html as ~USERNAME/
--enable-msie-padding Add padding to error messages for Internet Explorer
--disable-dirlisting Disable directory listings when no index file is found
--without-config Disable /etc/merecat.conf support using libConfuse
--without-ssl Disable HTTPS support, default: enabled
--without-symlinks Disable httpd and in.httpd symlinks to merecat
--without-zlib Disable mod_deflate (gzip) using zlib
The source file merecat.h has even more features that can be tweaked,
some of those are mentioned in the man page, but the header file has
very useful comments as well.
Origin & References
Merecat is a stiched up fork of sthttpd with lots of lost patches found lying around the web. The sthttpd project in turn is a fork from the original thttpd -- the tiny/turbo/throttling HTTP server.
- thttpd was created by Jef Poskanzer mailto:jef@mail.acme.com
- sthttpd was spawned by Anthony G. Basile mailto:blueness@gentoo.org
- Merecat is maintained by Joachim Wiberg mailto:troglobit@gmail.com
Copyright (C) 1995-2015 Jef Poskanzer <jef@mail.acme.com> Copyright (C) 2016-2021 Joachim Wiberg <troglobit@gmail.com> All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Contributing to Merecat httpd
We welcome any and all help in the form of bug reports, fixes, patches for new features, preferably as GitHub pull requests. Other methods are of course also possible: emailing the maintainer a patch or even a raw file, or simply emailing a feature request or an alert of a problem. However, email questions/requests/alerts always risk memory exhaustion on the part of the maintainer(s).
If you are unsure of what to do, or how to implement an idea or bug fix,
open an issue with the title "[RFC: Unsure if this is a bug ... ?",
or similar, so we can discuss it. Talking about the code first is the best
way to get started before submitting a pull request.
Either way, when sending an email, patch, or pull request, start by stating the version the change is made against, what it does, and most importantly -- why.
Please take care to ensure you follow the project coding style and the commit message format. If you follow these recommendations you help the maintainer(s) and make it easier for them to include your code.
Coding Style
Tip: Always submit code that follows the style of surrounding code!
First of all, lines are allowed to be longer than 72 characters these days. In fact, there exist no enforced maximum, but keeping it around 100 chars is OK.
The coding style itself is otherwise strictly Linux KNF.
Commit Messages
Commit messages exist to track why a change was made. Try to be as clear and concise as possible in your commit messages, and always, be proud of your work and set up a proper GIT identity for your commits:
git config --global user.name "Jane Doe"
git config --global user.email jane.doe@example.com
Example commit message from the Pro Git online book, notice
how git commit -s is used to automatically add a Signed-off-by:
Brief, but clear and concise summary of changes
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as
the subject of an email and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); tools like rebase can get confused if
you run the two together.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded
by a single space, with blank lines in between, but conventions
vary here
Signed-off-by: Jane Doe <jane.doe@example.com>
Code of Conduct
It is expected of everyone engaging in the project to, in the words of Bill & Ted; be excellent to each other.
Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery
- Personal attacks
- Trolling or insulting/derogatory comments
- Public or private harassment
- Publishing other's private information, such as physical or electronic addresses, without explicit permission
- Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the Contributor Covenant, version 1.2.0.
Security Policy
Supported Versions
Merecat httpd is a small project, as such we have no possibility to support older versions. The only supported version is the latest released on GitHub:
https://github.com/troglobit/merecat/releases
Reporting a Vulnerability
Contact the project's main author and owner to report and discuss vulnerabilities. See the README in the projects top directory, also part of the distribution archive.