redbean makes it possible to share web applications that run offline as
a single-file αcτµαlly pδrταblε εxεcµταblε zip archive which
contains your assets. All you need to do is download
the redbean.com
program below, change the filename to .zip,
add your content in a zip editing tool, and then change the extension
back to .com.
redbean can serve 1 million+ gzip encoded responses per second on a cheap personal computer. That performance is thanks to zip and gzip using the same compression format, which enables kernelspace copies. Another reason redbean goes fast is that it's a tiny static binary, which makes fork memory paging nearly free.
redbean is also easy to modify to suit your own needs. The program itself is written as a single .c file. It embeds the Lua programming language and SQLite which let you write dynamic pages.
this is an old version
click here for the latest redbean
redbean-1.5.com
1.6m - PE+ELF+MachO+ZIP+SH
a4189a6f9d540e5f400bbe40319b262dc622d64e32985a066e6f0b82ea06cd0d
redbean-1.5.com.dbg
13m - ELF debugger data (optional)
e16be021cee775620600fdd1df64362f5433c80b1f4f227cd5c8128af3f01d0c
redbean.c
source code
curl https://redbean.dev/redbean-latest.com >redbean.com curl https://redbean.dev/redbean-latest.com.dbg >redbean.com.dbg chmod +x redbean.com ./redbean.com -v redbean.com -v # windows command prompt workaround bash -c './redbean.com -v' # zsh/fish workaround (we upstreamed patches!)
Here's basic overview of how you'd go about using redbean alongside InfoZIP which is a free tool that comes included with most UNIX systems.
echo '<b>hello</b>' >hello.html zip redbean.com hello.html ./redbean.com -vv & curl http://127.0.0.1:8080/hello.html <b>hello</b> echo 'Write("<b>hello</b>")' >hello.lua zip redbean.com hello.lua printf 'GET /hello.lua\n\n' | nc 127.0.0.1 8080 <b>hello</b>
One GUI-like feature redbean itself offers is the ability to
LaunchBrowser()
at startup,
which can be called from your
your /.init.lua
file.
redbean-demo-1.5.com
1.6m - PE+ELF+MachO+ZIP+SH
e49697d524b623b55d98b227ba6742f7e577bbe757e15f57137ac8e56241fd10
redbean-demo-1.5.com.dbg
13m - ELF debugger data (optional)
472b6f1069305a7ffbe17bc3143065fcef2ad249e0b5009775a3dcb66aeb5bcf
redbean-asan-1.5.com (huge but nearly memory safe)
4.9m - PE+ELF+MachO+ZIP+SH
520fc0af54d78ca25160bae31d85d9cfe8d48da06d862238ea9699ab0bd67094
redbean-asan-1.5.com.dbg
23m - ELF debugger data (optional)
61bae4c22a7bdb1f6dc8d4514fcab138bd2689fd141e7737962ec0be55074098
redbean-original-1.5.com (no ssl, lua, or sqlite)
415k - PE+ELF+MachO+ZIP+SH
b4016a01c8d69f74254239a943d853ecefa08d4dd38926566c1257898c5fef09
redbean-original-1.5.com.dbg
4.6m - ELF debugger data (optional)
cc1036edcc2f3ab0f7ed54d2806ba7265afd01939ed9ef639e02890ad976dafd
redbean-static-1.5.com (no lua or sqlite)
794k - PE+ELF+MachO+ZIP+SH
4fcbd99da400cabac25c2a0ea6358d04be00b4e08dc05397a81b0d83f408ff41
redbean-static-1.5.com.dbg
7.0m - ELF debugger data (optional)
d10d0c4e207503bdaca77f767bf8387d22895505979c7d1a2c677bc166601912
redbean-unsecure-1.5.com (no ssl)
1.3m - PE+ELF+MachO+ZIP+SH
c57fdc08a59cb6560af9a1eb1ebd03767bb5ab6827922046b9b5e86ba804514e
redbean-unsecure-1.5.com.dbg
11m - ELF debugger data (optional)
1c40cb1203fbd9452f612b0184369fb0067598cf8beb706d9212a107929aec2c
redbean-original-tinylinux-1.5.com (no ssl/lua/sqlite/zlib, linux-only)
223k - ELF+ZIP
9937fb83d7a0d9300b1b586b285db2cbb9791d88913a8a2d069fd87178ccf396
redbean-original-tinylinux-1.5.com.dbg
2.7m - ELF debugger data (optional)
fe7d89d4071163ae10d46e4f7341597215366d49d86aa2e189f56bca53b243f5
sqlite3.com (vacuum, analyze, script, etc. your redbean db)
1.7m - PE+ELF+MachO+ZIP+SH
cd3b969977c9bc2b7356312f95390cec1cf75817d055df5b0676b8d675db15d3
sqlite3.com.dbg
12m - ELF debugger data (optional)
7de970fe87e7118047f24bacbcfc228e78e402e3f00bd27dc75e8f557b49543d
zip.com (InfoZIP APE build for editing ZIP contents)
472k - PE+ELF+MachO+ZIP+SH
5c22e6feaf4587297a771d3abfc66ebbf33cde5296c83c80844b806fe09ed413
zip.com.dbg
3.5m - ELF debugger data (optional)
5602d9a523a44ab22233c8ec08471b365c451ed7f7796b092653f21b5256122a
git clone https://github.com/jart/cosmopolitan && cd cosmopolitan make -j8 o//tool/net/redbean.com o//tool/net/redbean.com -vv
You can launch redbean in your terminal in the most verbose way possible by doing the following:
./redbean.com -vvmbag # starts server verbosely open http://127.0.0.1:8080/ # shows zip listing page CTRL-C # 1x: graceful shutdown CTRL-C # 2x: forceful shutdown
Visit http://redbean.justine.lol/ to see a live demo of redbean-demo-1.0.com.
Assets can be added to the zip archive as follows:
zip redbean.com index.html # adds file zip -r redbean.com mirrored-website # adds directory echo comment | zip -c redbean.com foo.html # adds file w/ comment
By default, anything you add to the archive gets compressed. Sometimes you don't want that to happen. A good example is video files. The web browser will want to send HTTP range requests to seek in the video, in which case redbean requires that the asset be uncompressed.
zip -0 redbean.com video.mp4 # adds file without compression
You can run redbean interactively in your terminal as follows:
redbean.com -vv CTRL-C # 1x: graceful shutdown CTRL-C # 2x: forceful shutdown
The index.lua
and index.html
names are special
since they're used to automatically figure out how to serve directories.
Such files can appear in any directory, however the root directory is
special. The default action for /
is to show a listing page
showing the contents of your zip central directory.
The listing page only applies to the root directory. However the default index page applies to subdirectories too. In order for it to work, there needs to be an empty directory entry in the zip. That should already be the default practice of your zip editor.
redbean normalizes the trailing slash for you automatically:
$ printf 'GET /a.example HTTP/1.0\n\n' | nc 127.0.0.1 8080 HTTP/1.0 307 Temporary Redirect Location: /a.example/
Virtual hosting is accomplished this way too. The Host is simply prepended to the path, and if it doesn't exist, it gets removed.
$ printf 'GET / HTTP/1.1\nHost:a.example\n\n' | nc 127.0.0.1 8080 HTTP/1.1 200 OK Link: <http://127.0.0.1/a.example/index.html>; rel=\"canonical\"
If you mirror a lot of websites within your redbean then you can actually tell your browser that redbean is your proxy server, in which redbean will act as your private version of the Internet.
wget \
--mirror \
--convert-links \
--adjust-extension \
--page-requisites \
--no-parent \
--no-if-modified-since \
http://a.example/index.html
zip -r redbean.com a.example/ # default page for directory
printf 'GET http://a.example HTTP/1.0\n\n' | nc 127.0.0.1 8080
HTTP/1.0 200 OK
Link: <http://127.0.0.1/a.example/index.html>; rel="canonical"
If you use a reverse proxy, then redbean recognizes the following provided that the proxy forwards requests over the local network:
X-Forwarded-For: 203.0.113.42:31337 X-Forwarded-Host: foo.example:80
There's a text/plain statistics page called /statusz that makes it easy to track and monitor the health of your redbean:
printf 'GET /statusz\n\n' | nc 127.0.0.1 8080
redbean will display an error page using the /redbean.png logo by default, embedded as a bas64 data uri. You can override the custom page for various errors by adding files to the zip root.
zip redbean.com 404.html # custom not found page
-h | help |
---|---|
-s | increase silence [repeatable] |
-v | increase verbosity [repeatable] |
-d | daemonize |
-u | uniprocess |
-z | print port |
-m | log messages |
-b | log message bodies |
-a | log resource usage |
-g | log handler latency |
-j | enable ssl fetch verify |
-k | disable ssl fetch verify |
-f | log worker function calls |
-B | only use stronger cryptography |
-z | print port [useful with -p0 for automation]
|
-H K:V | sets http header globally [repeatable] |
-t MS | timeout ms or keepalive sec if <0 [default 60000] |
-M INT | tunes max message payload size [default 65536] |
-D DIR | serve assets from local filesystem directory [repeatable] |
-c INT | configures static asset cache-control headers |
-r /X=/Y | redirect /X to /Y [repeatable]
|
-R /X=/Y | rewrite /X to /Y [repeatable]
|
-K PATH | tls private key path [repeatable] |
-C PATH | tls certificate(s) path [repeatable] |
-l ADDR | listen addr [default 0.0.0.0; repeatable] |
-p PORT | listen port [default 8080; repeatable] |
-L PATH | log file location |
-P PATH | pid file location |
-U INT | daemon set user id |
-G INT | daemon set group id |
Any files with the extension .lua
will be dynamically
served by redbean. Here's the simplest possible example:
Write('<b>Hello World</b>')
The Lua Server Page above should be able to perform at 700,000 responses
per second on a Core i9, without any sort of caching. If you want a Lua
handler that can do 1,000,000 responses per second, then try adding the
following global handler to your /.init.lua
file:
function OnHttpRequest()
Write('<b>Hello World</b>')
end
Here's an example of a more typical workflow for Lua Server Pages using the redbean API:
SetStatus(200) SetHeader('Content-Type', 'text/plain; charset=utf-8') Write('<p>Hello ') Write(EscapeHtml(GetParam('name')))
We didn't need the first two lines in the previous example, because they're implied by redbean automatically if you don't set them. Responses are also buffered until the script finishes executing. That enables redbean to make HTTP as easy as possible. In the future, API capabilities will be expanded to make possible things like websockets.
redbean embeds the
Lua standard library.
You can use packages such as
io
to persist and share state across requests and connections, as well as
the StoreAsset
function, and
the lsqlite3
module.
Your Lua interpreter begins its life in the main process at startup in
the .init.lua
, which is likely where
you'll want to perform all your expensive one-time operations like
importing modules. Then, as requests roll in, isolated processes are
cloned from the blueprint you created.
/index.lua
or /index.html
file defined.
ProgramFOO()
functions below. The init module
load happens after redbean's arguments and zip assets have been
parsed, but before calling functions like socket() and fork(). Note
that this path is a hidden file so that it can't be unintentionally
run by the network client.
package.path
to /zip/.lua/?.lua;/zip/.lua/?/init.lua
by default.
Cosmopolitan Libc lets system calls like open
read from
the ZIP structure, if the filename is prefixed
with /zip/
. So this works like magic.
/
listing page icon,
embedded as a base64 URI.
getopt()
in the C code, which stops parsing at the first non-hyphenated arg. In some cases you can use the magic --
argument to delimit C from Lua arguments.
/.init.lua
then redbean will
call it at the ealiest possible moment to hand over control for all
messages (with the exception of OPTIONS *
). See functions
like Route
which asks redbean to do
its default thing from the handler.
SetHeader('Connection','Close')
.
This won't be called in uniprocess mode.
reason
is optional since redbean can fill in the
appropriate text for well-known magic numbers,
e.g. 200
, 404
, etc. This method will reset the
response and is therefore mutually exclusive
with ServeAsset
and other Serve*
functions. If a status setting function isn't called, then the default
behavior is to send 200 OK
.
name
is
case-insensitive and restricted to non-space
ASCII. value
is a UTF-8 string that must be encodable
as ISO-8859-1. Leading and trailing whitespace is trimmed
automatically. Overlong characters are canonicalized. C0 and C1
control codes are forbidden, with the exception of tab. This
function automatically
calls SetStatus(200, "OK")
if
a status has not yet been set. As SetStatus and Serve* functions
reset the response, SetHeader needs to be called after SetStatus and
Serve* functions are called. The header buffer is independent of the
payload buffer. Neither is written to the wire until the Lua Server
Page has finished executing. This function disallows the setting of
certain headers such as and Content-Range
which are
abstracted by the transport layer. In such cases, consider
calling ServeAsset
.
__Host-
and __Secure-
prefixes are supported
and may set or overwrite some of the options (for example, specifying
__Host-
prefix sets the Secure option to true, sets the
path to "/", and removes the Domain option). The following options can
be used (their lowercase equivalents are supported as well):
Expires
sets the maximum lifetime of the cookie as
an HTTP-date timestamp. Can be specified as a Date in the RFC1123
(string) format or as a UNIX timestamp (number of seconds).
MaxAge
sets number of seconds until the cookie
expires. A zero or negative number will expire the cookie
immediately. If both Expires and MaxAge are set, MaxAge has
precedence.
Domain
sets the host to which the cookie will be
sent.
Path
sets the path that must be present in the
request URL, or the client will not send the Cookie header.
Secure
(bool) requests the cookie to be only send to
the server when a request is made with the https: scheme.
HttpOnly
(bool) forbids JavaScript from accessing
the cookie.
SameSite
(Strict, Lax, or None) controls whether a
cookie is sent with cross-origin requests, providing some
protection against cross-site request forgery attacks.
name
is
handled in a case-sensitive manner. This function checks Request-URL
parameters first. Then it
checks application/x-www-form-urlencoded
from the
message body, if it exists, which is common for HTML forms
sending POST
requests. If a parameter is supplied
matching name that has no value, e.g. foo
in ?foo&bar=value
, then the returned value will
be nil
, whereas for ?foo=&bar=value
it
would be ""
. To differentiate between no-equal and
absent, use the HasParam
function. The returned value is decoded from ISO-8859-1 (only in the
case of Request-URL) and we assume that percent-encoded characters
were supplied by the client as UTF-8 sequences, which are returned
exactly as the client supplied them, and may therefore may contain
overlong sequences, control codes, NUL
characters, and
even numbers which have been banned by the IETF. It is the
responsibility of the caller to impose further restrictions on
validity, if they're desired.
&><"'
which
become &><"'
.
This function is charset agnostic and will not canonicalize overlong
encodings. It is assumed that a UTF-8 string will be supplied.
See escapehtml.c.
/.init.lua
.
data:
URIs that do things like embed a PNG file in
a web page.
See encodebase64.c.
#fragment
. The allowed characters
are -/?.~_@:!$&'()*+,;=0-9A-Za-z
and everything
else gets %XX
encoded. Please note
that '&
can still break HTML and
that '()
can still break CSS URLs. This function is
charset agnostic and will not canonicalize overlong encodings. It is
assumed that a UTF-8 string will be supplied.
See kescapefragment.c.
\uxxxx
sequences for all non-ASCII
sequences. HTML entities are also encoded, so the output doesn't
need EscapeHtml
. This
function assumes UTF-8 input. Overlong encodings are canonicalized.
Invalid input sequences are assumed to be ISO-8859-1. The output is
UTF-16 since that's what JavaScript uses. For example, some
individual codepoints such as emoji characters will encode as
multiple \uxxxx
sequences. Ints that are impossible to
encode as UTF-16 are substituted with the \xFFFD
replacement character.
See escapejsstringliteral.c.
-.*_0-9A-Za-z
and everything else
gets %XX
encoded. This function is charset agnostic and
will not canonicalize overlong encodings. It is assumed that a UTF-8
string will be supplied.
See kescapeparam.c.
EscapeSegment
except
slash is allowed. The allowed characters
are -.~_@:!$&'()*+,;=0-9A-Za-z/
and everything else
gets %XX
encoded. Please note that '&
can still break HTML, so the output may
need EscapeHtml
too. Also
note that '()
can still break CSS URLs. This function
is charset agnostic and will not canonicalize overlong encodings. It
is assumed that a UTF-8 string will be supplied.
See kescapepath.c.
EscapePath
except slash
isn't allowed. The allowed characters
are -.~_@:!$&'()*+,;=0-9A-Za-z
and everything else
gets %XX
encoded. Please note that '&
can still break HTML, so the output may
need EscapeHtml
too. Also
note that '()
can still break CSS URLs. This function
is charset agnostic and will not canonicalize overlong encodings. It
is assumed that a UTF-8 string will be supplied.
See kescapesegment.c.
method
(default: "GET"
): sets the
method to be used for the request. The specified method is
converted to uppercase.
body
(default: ""
): sets the body value to be
sent.
followredirect
(default: true
):
forces temporary and permanent redirects to be followed. This
behavior can be disabled by passing false
.
maxredirects
(default: 5
): sets the
number of allowed redirects to minimize looping due to
misconfigured servers. When the number is exceeded, the result
of the last redirect is returned.
Mon, 29 Mar 2021 15:37:13 GMT
.
See formathttpdatetime.c.
ParseIp
for the inverse
operation.
-D
flag is used)
-D
flag is used)
0x01020304,31337
would
represent 1.2.3.4:31337
. This is the same
as GetClientAddr except
it will use the ip:port from the X-Forwarded-For
header, only if IsPrivateIp or IsPrivateIp returns true.
0x01020304,31337
would
represent 1.2.3.4:31337
. Please consider
using GetRemoteAddr
instead, since the latter takes into consideration reverse proxy
scenarios.
0x01020304,8080
would
represent 1.2.3.4:8080
. If -p 0
was
supplied as the listening port, then the port in this string will be
whatever number the operating system assigned.
Date
header, which is now, give or take a second.
The returned value is a UNIX timestamp.
name
is case-insensitive. The
header value
is returned as a canonical UTF-8 string,
with leading and trailing whitespace trimmed, which was decoded from
ISO-8859-1, which is guaranteed to not have C0/C1 control sequences,
with the exception of the tab character. Leading and trailing
whitespace is automatically removed. In the event that the client
suplies raw UTF-8 in the HTTP message headers, the original UTF-8
sequence can be losslessly restored by counter-intuitively recoding
the returned string back to Latin1. If the requested header is
defined by the RFCs as storing comma-separated values (e.g. Allow,
Accept-Encoding) and the field name occurs multiple times in the
message, then this function will fold those multiple entries into a
single string.
GetHeader
API if
possible since it does a better job abstracting these issues.
kLogDebug
>
kLogVerbose
>
kLogInfo
>
kLogWarn
>
kLogError
>
kLogFatal
.
GET
, HEAD
, or POST
in which
case redbean normalizes this value to its uppercase form. Anything else
that the RFC classifies as a "token" string is accepted too, which might
contain characters like &"
.
application/x-www-form-urlencoded
message body in the
order they were received. This may contain duplicates. The inner array
will have either one or two items, depending on whether or not the
equals sign was used.
"/"
. It is further guaranteed that
no "//"
or "/."
exists in the path. The
returned value is returned as a UTF-8 string which was decoded from
ISO-8859-1. We assume that percent-encoded characters were supplied by
the client as UTF-8 sequences, which are returned exactly as the client
supplied them, and may therefore may contain overlong sequences, control
codes, NUL
characters, and even numbers which have been
banned by the IETF. redbean takes those things into consideration when
performing path safety checks. It is the responsibility of the caller to
impose further restrictions on validity, if they're desired.
SetStatus
call) or
nil
if the status hasn't been set yet.
Host
or X-Forwarded-Host
headers, if they exist, and possibly a scheme too if redbean is being used as an HTTP proxy server. In the future this API might change to return an object instead.
9
for HTTP/0.9
, 10
for HTTP/1.0
, or 11
for HTTP/1.1
.application/x-www-form-urlencoded
message body.
/
listing page to not display any paths beginning with prefix. This function should only be called from /.init.lua
.
-D
flag was used. If slurping large file into memory is a concern, then consider using ServeAsset
which can serve directly off disk.
GetLogLevel
. If redbean is running in interactive mode, then this will log to the console. If redbean is running as a daemon or the -L LOGFILE
flag is passed, then this will log to the file. Reasonable values for level
are kLogDebug
>
kLogVerbose
>
kLogInfo
>
kLogWarn
>
kLogError
>
kLogFatal
. The logger emits timestamps in the local timezone with microsecond precision. If log entries are emitted more frequently than once per second, then the log entry will display a delta timestamp, showing how much time has elapsed since the previous log entry. This behavior is useful for quickly measuring how long various portions of your code take to execute.
Mon, 29 Mar 2021 15:37:13 GMT
to a UNIX timestamp. See parsehttpdatetime.c.
scheme
, user
, pass
, host
, port
, path
, params
, fragment
. This parser is charset agnostic. Percent encoded bytes are decoded for all fields. Returned values might contain things like NUL characters, spaces, control codes, and non-canonical encodings. Absent can be discerned from empty by checking if the pointer is set. There's no failure condition for this routine. This is a permissive parser. This doesn't normalize path segments like `.` or `..` so use IsAcceptablePath() to check for those. No restrictions are imposed beyond that which is strictly necessary for parsing. All the data that is provided will be consumed to the one of the fields. Strict conformance is enforced on some fields more than others, like scheme, since it's the most non-deterministically defined field of them all. Please note this is a URL parser, not a URI parser. Which means we support everything the URI spec says we should do except for the things we won't do, like tokenizing path segments into an array and then nesting another array beneath each of those for storing semicolon parameters. So this parser won't make SIP easy. What it can do is parse HTTP URLs and most URIs like data:opaque, better in fact than most things which claim to be URI parsers.
ParseUrl
. The output will always be correctly formatted. The exception is if illegal characters are supplied in the scheme field, since there's no way of escaping those. Opaque parts are escaped as though they were paths, since many URI parsers won't understand things like an unescaped question mark in path.
"1.2.3.4" → 0x01020304
,
or returns -1
for invalid inputs. See also FormatIp
for the inverse operation.
-d
flag was passed to redbean.
-U
flag if called from .init.lua for setuid()
-G
flag if called from .init.lua for setgid()
-P
flag if called from .init.lua for
setting the pid file path on the local file system. It's useful for
reloading daemonized redbean using kill -HUP $(cat /var/run/redbean.pid)
or terminating redbean with kill $(cat /var/run/redbean.pid)
which
will gracefully terminate all clients. Sending the TERM signal twice will cause a
forceful shutdown, which might make someone with a slow internet connection who's
downloading big files unhappy.
-D
flag if called from .init.lua for
overlaying local file system directories. This may be called
multiple times. The first directory programmed is preferred. These
currently do not show up in the index page listing.
-m
flag if called from .init.lua for logging message
headers only.
Server
header, as well as the <h1>
title on the /
listing page. The brand string needs to be a UTF-8 value that's encodable as ISO-8859-1. If the brand is changed to something other than redbean, then the promotional links will be removed from the listing page too. This function should only be called from /.init.lua
.
Cache-Control
and Expires
header generation for static asset serving. A negative value will disable the headers. Zero means don't cache. Greater than zero asks public proxies and browsers to cache for a given number of seconds. This should only be called from /.init.lua
.
GetServerAddr
or the -z
flag to stdout.
301
, 302
, 307
, or 308
then a redirect response will be sent to the client. This should only be called from /.init.lua
.
-C
flag if called
from .init.lua
,
e.g. ProgramCertificate(LoadAsset("/.sign.crt"))
for zip loading or
ProgramCertificate(Slurp("/etc/letsencrypt.lol/fullchain.pem"))
for local file system only.
-K
flag if called
from .init.lua
, e.g.
ProgramPrivateKey(LoadAsset("/.sign.key"))
for zip loading or
ProgramPrivateKey(Slurp("/etc/letsencrypt/privkey.pem"))
for local file system only.
key
may contain 1..32 bytes of
random binary data and identity is usually a short plaintext
string. The first time this function is called, the preshared
key will be added to both the client and the server SSL
configs. If it's called multiple times, then the remaining
keys will be added to the server, which is useful if you want
to assign separate keys to each client, each of which needs a
separate identity too. If this function is called multiple
times with the same identity string, then the latter call
will overwrite the prior. If a preshared key is supplied and
no certificates or key-signing-keys are programmed, then
redbean won't bother auto-generating any serving certificates
and will instead use only PSK ciphersuites.
ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-CHACHA20-POLY1305-SHA256 ECDHE-PSK-AES256-GCM-SHA384 ECDHE-PSK-AES128-GCM-SHA256 ECDHE-PSK-CHACHA20-POLY1305-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-CHACHA20-POLY1305-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-CHACHA20-POLY1305-SHA256 ECDHE-ECDSA-AES128-CBC-SHA256 ECDHE-RSA-AES256-CBC-SHA384 ECDHE-RSA-AES128-CBC-SHA256 DHE-RSA-AES256-CBC-SHA256 DHE-RSA-AES128-CBC-SHA256 ECDHE-PSK-AES256-CBC-SHA384 ECDHE-PSK-AES128-CBC-SHA256 ECDHE-ECDSA-AES256-CBC-SHA ECDHE-ECDSA-AES128-CBC-SHA ECDHE-RSA-AES256-CBC-SHA ECDHE-RSA-AES128-CBC-SHA DHE-RSA-AES256-CBC-SHA DHE-RSA-AES128-CBC-SHA ECDHE-PSK-AES256-CBC-SHA ECDHE-PSK-AES128-CBC-SHA RSA-AES256-GCM-SHA384 RSA-AES128-GCM-SHA256 RSA-AES256-CBC-SHA256 RSA-AES128-CBC-SHA256 RSA-AES256-CBC-SHA RSA-AES128-CBC-SHA PSK-AES256-GCM-SHA384 PSK-AES128-GCM-SHA256 PSK-CHACHA20-POLY1305-SHA256 PSK-AES256-CBC-SHA384 PSK-AES128-CBC-SHA256 PSK-AES256-CBC-SHA PSK-AES128-CBC-SHA ECDHE-RSA-3DES-EDE-CBC-SHA DHE-RSA-3DES-EDE-CBC-SHA ECDHE-PSK-3DES-EDE-CBC-SHA RSA-3DES-EDE-CBC-SHA PSK-3DES-EDE-CBC-SHAThe names above are canonical to redbean. They were programmatically simplified from the official IANA names. This function will accept the IANA names too. In most cases it will accept the OpenSSL and GnuTLS naming convention as well.
OnHttpRequest
handler, since that overrides the serving path entirely. So if the
handler decides it doesn't want to do anything, it can simply call
this function, to hand over control back to the redbean core. By
default, the host and path arguments are supplied from the resolved
GetUrl value. This handler always resolves, since it will generate a
404 Not Found response if redbean couldn't find an appropriate
endpoint.
Route
, except it only implements
the subset of request routing needed for serving virtual-hosted
assets, where redbean tries to prefix the path with the hostname
when looking up a file. This function returns true if the request
was resolved. If it was resolved, then your OnHttpRequest request
handler can still set additional headers.
Route
, except it only implements
the subset of request routing needed for serving assets. This
function returns true if the request was resolved. If it was
resolved, then your OnHttpRequest request handler can still set
additional headers.
-D
is used. This function is mutually
exclusive with SetStatus
and ServeError
.
SetStatus
and ServeAsset
.
level
are kLogDebug
>
kLogVerbose
>
kLogInfo
>
kLogWarn
>
kLogError
>
kLogFatal
.
bsf
bsr
crc32
crc32c
popcnt
Please refer to the LuaSQLite3 Documentation.
redbean supports a subset of what's defined in the upstream LuaSQLite3 project. Most of the unsupported APIs relate to pointers and database notification hooks.
redbean also currently disables SQLite features which don't make sense for production serving, such as ALTER, VACUUM, ANALYZE, etc. For that reason we provide an APE build of the SQLite shell which you can use to administrate your redbean database. See the sqlite3.com download above.
This module exposes an API for POSIX regular expressions which enable you to validate input, search for substrings, extract pieces of strings, etc. Here's a usage example:
# Example IPv4 Address Regular Expression (see also ParseIP
)
p = re.compile([[^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$]])
m,a,b,c,d = p:search(𝑠)
if m then
print("ok", tonumber(a), tonumber(b), tonumber(c), tonumber(d))
else
print("not ok")
end
re.compile
plus regex_t*:search
.
/.init.lua
file. Flags may contain re.BASIC
, re.ICASE
, re.NOSUB
, and/or re.NEWLINE
. See also regcomp() from libc.
nil
) if the pattern doesn't match anything. Otherwise it pushes the matched substring and any parenthesis-captured values too. Flags may contain re.NOTBOL
or re.NOTEOL
to indicate whether or not text should be considered at the start and/or end of a line.
([0-9]*)\.([0-9]*)\.([0-9]*)\.([0-9]*)
whereas with basic syntax it would look like \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)
. This flag may only be used with re.compile
and re.search
.
[a-z]
will mean the same thing
as [A-Za-z]
. This flag may only be used
with re.compile
and re.search
.
re.search
to only report
success and failure. This is reported via the API by returning empty
string for success. This flag may only be used
with re.compile
and re.search
.
re.search
and regex_t*:search
.
re.search
and regex_t*:search
.
Log
.
kLogDebug
. See Log
.
kLogVerbose
. See Log
.
kLogVerbose
. See Log
.
kLogWarn
. See Log
.
kLogError
.
See Log
. Logging anything at this
level will result in a backtrace and process exit.
You can have redbean run as a daemon by doing the following:
redbean.com -vv -d -L redbean.log -P redbean.pid kill -TERM $(cat redbean.pid) # 1x: graceful shutdown kill -TERM $(cat redbean.pid) # 2x: forceful shutdown
It's possible to modify global interpreter state later on in the
server's lifecycle. When running in daemon mode, using kill -HUP
$(pidof redbean.com)
will instruct redbean to run the code
in .reload.lua
from the main process,
will will be lazily propagated to client connections.
You can modify the zip while redbean is running. The zip command by
default will do this by replacing the inode. redbean will detect the
changed inode within a second and broadcast SIGUSR1 to the process group
so the new assets get indexed as soon as possible. It's also possible to
modify the executable assets in place, while the executable is running.
If you do that, then you need to be careful to not disturb the local
file and central directory. What you would do instead is append changed
or new files. Then append a new central directory, along with a new end
of central directory record. Finally, memset(0) the old end of central
directory record. redbean will detect it's gone and reindex. You can
even modify local files in place too. The way you would do that is by
clearing the PK♥♦
magic marker while the file memory is
being mutated, and then putting it back. Any requests that arrive during
the modification will result in a 503 Service Unavailable so your load
balancer can failover.
redbean will grow to whatever number of processes your system limits and
tcp stack configuration allow. Once functions like fork()
and accept()
start to fail, redbean will enter "meltdown
mode" where it interrupts worker processes to immediately close idling
and lagging connections. redbean may need to drop requests by sending
503 Service Unavailable
until congestion subsides. So be
sure your load balancer is configured to immediately failover to another
instance in such cases.
There's a 64kb limit on request message size, where the header portion is further limited to 32kb. We do that to guarantee processes stay tiny. You can tune it using the -M flag. redbean spawns a process for each connection. redbean needs about 200kb of RAM per worker on average. Clients are encouraged to pipeline HTTP requests within the same connection.
redbean rejects requests for hidden files, i.e. any path containing the
substring /.
and requests with denormalized paths,
e.g. /../../etc/passwd
are also categorically rejected.
Furthermore, redbean won't service requests that come in more than 32
fragments. Those few restrictions aside, redbean generally aims to
follow Postel's maxim in the sense that it's liberal in what it accepts
but conservative in what it sends.
If you want Rust-like promises then redbean can be compiled with ASAN memory safety. Cosmopolitan Libc has the only open source implementation of the Address Sanitizer runtime that's intended for production use. It causes redbean worker processes to crash and log a report when bugs like buffer overruns, use-after-free, stack smashing, etc. occur. This has a marginal impact on performance and can be useful in environments where interruptions in service are more desirable than risking the system being compromised. Please be sure to report any bugs you might find. It also helps to have the .com.dbg file in the same directory, so backtraces will show the function names.
redbean should not be productionized on Windows and MacOS. These systems are designed to be used by a single person. Both systems have unreliable file locking which is important for SQLite. On Windows redbean currently runs in uniprocess mode on Windows.
redbean doesn't secure your computer. It does however provide tools we hope will help you do it yourself. For further details on why things need to be this way, please see the disclaimer in the ISC license.
Some computing environments rely on physical security and redbean is a good fit for that. For example, if you need to run a web app on an air-gapped computer running an old version of some other operating system that can't be upgraded, then you load your redbean off a thumb drive provided that the system was installed after the year 2007 or more specifically runs x86_64 with Linux 2.6.18+ or Windows Vista+.
Some environments require that security be provided using existing infrastructure like SSL frontends. In that case, the "redbean-unsecure" download link might be the right choice for you, since it's a special build of redbean that leaves out the security code. That way, you can bolt the security on separately using a tool like stunnel.
redbean also provides integrated SSL support based on MbedTLS. It's configured to offer 128 bits of security with modern clients, but will fall back to at minimum 112 bits of security depending on the preferences of the client. Both are secure based on public knowledge until 2030 according to NIST. If you'd rather restrict yourself to just 150+ bits of security but with the tradeoff of dropping support for old Internet Explorer and making embedded clients less happy, then pass the -B flag, which'll restrict redbean to a very short list of protocols, algorithms, and parameters that the NSA, NIST, and IANA all agree upon.
redbean's SSL implementation is tuned for performance. It uses hardware algorithms when available such as AES-NI, SHA-NI, and RDRAND. redbean does not use costly hardnening measures specific only to legacy clients like Internet Explorer if they increase denial of service risk for the server as a whole.
redbean is tuned for ease of use. Your redbean uses a protocol polyglot for serving HTTP and HTTPS on the same port numbers. Both the TLS hello and the SSLv2 hello are accepted, even though only TLS is supported. For example, both of these are valid:
http://127.0.0.1:8080/ https://127.0.0.1:8080/
By default, your redbean will automatically generate ephemeral self-signed ECDSA and RSA serving certificates. This causes browser warnings. The simplest option for making the warning go away is to give redbean a key signing key (KSK).
openssl req -x509 -newkey rsa:2048 \ -keyout .ca.key -out .ca.crt -days 6570 -nodes \ -subj '/C=US/ST=CA/O=Jane Doe/CN=My Root CA 1' \ -addext 'keyUsage = critical,cRLSign,keyCertSign' sudo ./redbean.com -C ca.crt -K .ca.key -p 80 -p 443
Your SSL root can then be installed on client machines as follows:
# linux sudo cp ca.crt /usr/local/share/ca-certificates sudo update-ca-certificates # macos sudo security add-trusted-cert -d -r trustRoot \ -k /Library/Keychains/System.keychain ca.crt # windows certutil -addstore -f "ROOT" ca.crt # notes # firefox is special you have to use its settings
If your goal is to make SSL deploys easy, then it's possible to put the
KSK inside the redbean.com file using the InfoZIP program. Be sure the
key is a hidden file. It can be loaded using your .init.lua
script with the LoadAsset
,
ProgramCertificate
, and
ProgramPrivateKey
APIs.
Please note, this is just an example of what you could do; we don't
claim it's what you should do.
For a public-facing online service, the simplest way to use SSL is with Let's Encrypt. Let's say you're migrating from NGINX. In that case you'll likely want something like the following:
# commands subject to public monitoring
certbot certonly --nginx --key-type ecdsa \
--cert-name redbean-ecdsa -d redbean.dev -d www.redbean.dev
certbot certonly --nginx --key-type rsa \
--cert-name redbean-rsa -d redbean.dev -d www.redbean.dev
You can then program /var/www/html/.init.lua
as such:
ProgramPrivateKey(Slurp('/etc/letsencrypt/live/redbean-ecdsa/privkey.pem')) ProgramCertificate(Slurp('/etc/letsencrypt/live/redbean-ecdsa/fullchain.pem')) ProgramPrivateKey(Slurp('/etc/letsencrypt/live/redbean-rsa/privkey.pem')) ProgramCertificate(Slurp('/etc/letsencrypt/live/redbean-rsa/fullchain.pem')) if IsDaemon() then ProgramUid(33) # see `vipw` to get appropriate number ProgramGid(33) # see `vigr` to get appropriate number ProgramPort(80) ProgramPort(443) ProgramLogPath('/var/log/redbean.log') ProgramPidPath('/var/run/redbean.pid') end function OnHttpRequest() path = GetPath() if path == '/favicon.ico' or path == '/site.webmanifest' or path == '/favicon-16x16.png' or path == '/favicon-32x32.png' or path == '/apple-touch-icon' then SetLogLevel(kLogWarn) end Route() SetHeader('Content-Language', 'en-US') end
You'd then run redbean as follows:
redbean.com -dD /var/www/html
You can load as many public and private keys as you want. They can be specified as pem, der, concatenated ascii, bundles, or chains. If you don't specify specific chains then redbean will automatically infer it based on SUBJECT → ISSUER relationships. Your redbean won't serve the self-signed root certificate at the end of the chain where self-signed is defined as SUBJECT == ISSUER. Otherwise you can control when chains terminate by setting the max length constraint to zero.
Your redbean supports SSL virtual hosting. 99.76% of TLS clients send a Server Name Indicator (SNI), which is matched against DNS or IPs in Subject Alternative Names (SAN) or the Common Name (CN) of subject if SAN isn't used. This means you don't need to reveal your whole domain portfolio to each client just to have ssl. You can just use different certificates for each domain if you choose to do so. If redbean can't find an appropriate match, then the first certificate will be chosen.
SSL layer client verification is unusual, but some options are:
-j
to enable verification of HTTPS clients.
Clients are verified based on the SSL roots you've provided. Those
can be installed via the Lua API or placed in the ZIP executable
folder usr/share/ssl/root.
SSL verbosity is controlled as follows for troubleshooting:
-V log ssl errors -VV log ssl state changes too -VVV log ssl informational messages too -VVVV log ssl verbose details too
That's in addition to existing flags like -vvvm.
No APIs are currently provided for use-cases like long-polling and websockets. That should change in the future.
# Note: Benchmarked on an Intel® Core™ i9-9900 CPU # Note: Use redbean-demo.com -s $ wrk -H 'Accept-Encoding: gzip' -t 12 -c 120 \ http://127.0.0.1:8080/tool/net/demo/index.html Running 10s test @ http://127.0.0.1:8080/tool/net/demo/index.html 12 threads and 120 connections Thread Stats Avg Stdev Max +/- Stdev Latency 18.27ms 131.81ms 1.71s 97.60% Req/Sec 85.17k 10.73k 144.05k 82.75% 10221627 requests in 10.10s, 7.53GB read Socket errors: connect 0, read 0, write 0, timeout 13 Requests/sec: 1012088.67 Transfer/sec: 763.48MB
Funding for redbean was crowdsourced from Justine Tunney's GitHub sponsors and Patreon subscribers. Your support is what makes projects like redbean possible. Thank you.
redbean hacker news thread (1,998 upvotes)
αcτµαlly pδrταblε εxεcµταblε (671 upvotes)
justine's web page