HTTP(1)
πΈ NAME πΈ
http β from HTTP(1) in the General Commands Manual β is a basic HTTP server for hosting a folder fast and simply. Thatβs the whole vibe: folder in, HTTP out, no drama. π
β¨ SYNOPSIS β¨
http [OPTIONS] [DIRECTORY]
π DESCRIPTION π
Okay so real talk: this is Host These Things Please β a basic HTTP server for hosting a folder fast and simply. The name is literally doing the most and I love it. π«Ά
The idea is to make a program that can compile down to a simple binary that can be used via Linux CLI to quickly take the current directory and serve it over HTTP. Everything should have sensible defaults such that you do not have to pass parameters like what port to use. Lowkey the dream: you type the command, it serves, you move on with your life. β¨
π OPTIONS π
[DIR]β directory to host. It must exist. Default: current working directory. If you donβt pass one, she just serves where youβre standing. π-p,--port [PORT]β port to host the server on. Must be between1and65'535. A value of0will assign a random port, chosen by the OS. Default: first free port from8000up. So like, sheβll find a spot if you donβt pick one. π-a,--address [ADDRESS]β IP to bind the server to. Default:0.0.0.0. Classic βlisten everywhereβ energy. π-t,--temp-dir [TEMP]β temporary directory to use to store data to write. Only matters if--allow-writeis also specified or--no-encodeis not. Default:$TEMP. Basically the scratch space for when writing or encoding is in the mix. ποΈ--ssl [TLS_IDENTITY_FILE]β TLS identity file to use to encrypt as. The password is taken from theHTTP_SSL_PASSenvironment variable, or empty if that variable doesnβt exist. Default:None. Secure-channel era, but only if you hand her the identity file. π--gen-sslβ generate a single-use self-signed TLS certificate withopenssland use it for this session. The password for the certificate is the empty string, except on MacOS, where itβs"password", since the platform libssl refuses to import passwordless certificates. Exclusive with--ssl. Default:false. One-session wonder cert, no cap. π§--auth [USERNAME[:PASSWORD]]β data for global authentication. Equivalent to--path-authwith a root path and the same credentials. This argument is deprecated, and will be replaced with the current version of--path-authon the next breaking release. Use--path-authin new designs to avoid surprises. Default:None. Old reliable, but sheβs got a βdeprecatedβ sticker on her forehead. π·οΈ--gen-authβ generate a one-offusername:passwordset for global authentication. Functions as if--authwas specified with the generated credentials. This argument is deprecated, and will be replaced with the current version of--gen-path-authon the next breaking release. Use--gen-path-authin new designs to avoid surprises. Exclusive with--auth. Default:false. Cute one-time login moment, but again: deprecated. π--path-auth [PATH=[USERNAME[:PASSWORD]]]β data for per-path authentication. The specifiedPATHwill require the specified credentials to access. If credentials are unspecified, the path will have authentication disabled, even if global or parent paths have authentication specified. These can be arbitrarily nested.PATHis slash-normalised stripped of leading and trailing slashes. Specifying more than one of the samePATHis erroneous. Default: empty. This is the βlocked door but only for this hallwayβ option. π--gen-path-auth [PATH]β generate a one-offusername:passwordset for authentication underPATH. The username consists of6-12random alphanumeric characters, whereas the password consists of10-25random characters from most of the ASCII printable set. Functions as if--path-authwas specified withPATHand the generated credentials. Exclusive with--path-authwith the equivalentPATH. Default: empty. Random creds, generated fresh, very βnew phone who dis.β π²--proxy [HEADER-NAME:CIDR]β treatHEADER-NAMEas a proxy forwarded-for header when the request originates from an address inside the network specified by theCIDR. If the header is set but the request isnβt in the network, itβs ignored. Can be specified any amount of times. Default: none. Trust the header only when the request comes from the right neighborhood. ποΈ--proxy-redir [HEADER-NAME:CIDR]β treatHEADER-NAMEas a proxyX-Original-URLheader when the request originates from an address inside the network specified by theCIDR: this used only for303 See OtherLocation:headers when redirecting due to an index file. Can be specified any amount of times. Default: none. Redirect-flavored proxy trust, specifically for that index-file redirect moment. π-m,--mime-type [EXTENSION:MIME-TYPE]β returnMIME-TYPEfor files withEXTENSION. IfEXTENSIONis the empty string, return thatMIME-TYPEfor files with no extension. The default MIME type is as returned by themime_guesscrate, if any, otherwise"application/octet-stream"for binary files or"text/plain". Can be specified any amount of times. Default: none. Custom MIME mapping, iykyk. π--request-bandwidth [BYTES]β limit the band for each request toBYTES/second wide. Can be suffixed with[KMGTPE]binary prefixes or[kmgtpe]SI prefixes. Zero disables capping. Default:0. Throttle era, if you need it. π’-H,--header [NAME: VALUE]...β add the specified headers to all responses.VALUEis left-trimmed. Header glow-up for every response. β¨-s,--no-follow-symlinksβ donβt follow symlinks when requesting file access. If a symlink is requested and this flag is on it will be treated as if it didnβt exist. No sneaky link-following. π«-r,--sandbox-symlinksβ restrict/sandbox where symlinks lead to only the direct descendants of the hosted directory. If a file outside the direct descendancy of the hosted directory requested and this flag is on it will be treated as if it didnβt exist. Symlinks stay in their lane, periodt. π§±-w,--allow-writeβ allow for write operations. Currently supported write operations:PUTandDELETE. With PUTs, theX-Last-Modified/X-OC-MTimeheaders can be specified to milliseconds/seconds since epoch, and this will be set on the fileβsst_mtim. This isfalseby default because itβs most likely not something you want to do. Write access is giving βhandle with care,β bestie. β οΈ-D,--convenient-webdavβ allowMKCOL(create directory) andMOVE(rename) WebDAV requests. These are accessible from the web UI. These are write requests so this is a no-op unless-w.Falseby default. Convenient little WebDAV shortcuts. ποΈ-d,--webdavβ handle WebDAV requests:MKCOL(create directory)MOVE(rename)PROPFIND(open in WebDAV client)COPY(copy files, directories)PROPPATCH(set file properties after PUT-uploading)
MKCOL and MOVE are accessible from the web UI, the rest enable mounting and file management via a WebDAV client. False by default. Supersedes -D. Full WebDAV mode activated. π«Ά
-A,--archivesβ allow requesting tar and ZIP archives with
curl -H 'Accept: application/tar' ...
and by including a form in the generated indices.
This defines two APIs:
GET+Acceptcontaining any of the following:application/tarapplication/x-tar=> tarapplication/zipapplication/x-zip-compressed=> ZIP
POST+ sentinel values embedded into the generated index (POSTis otherwise unsupported)
The results should be logically equivalent to "cd -L"ing to the requested path (subject to -s and -r), then "tar -c * .*" (so symbolic links are never followed, for example).
If a file or directory fails to open, it is skipped and does not abort archiving.
Files with st_nlink > 1 are detected and accrued for tar archives.
ZIPs only include regular files, directories, and symbolic links. Files that would be encoded if requesting them directly will be DEFLATEd (subject to -e).
If the requested path is a file, then a single-file archive is produced.
False by default. Archive girl summer. ποΈ
-l,--no-listingsβ do not generate directory listings. Hereβs the behavior matrix of--no-listingswith--no-indices:- Path
/has-index: Neither= index;-i= listing;-l= index;-l -i= 404 - Path
/no-index: Neither= listing;-i= listing;-l= 404;-l -i= 404
- Path
This is false by default because itβs most likely for debugging purposes. Debug gremlin mode, but make it configurable. π
-i,--no-indicesβ do not automatically serve the index file for directories containing one. This isfalseby default because itβs most likely for debugging purposes. When generating an index file, look for fileREADMEin the directory being indexed; if it exists, read it, and inject it at the given position (default bottom), in the given format (plainwill be<pre>-wrapped). The last option in a group takes effect. Any amount of READMEs can be added, and are reproduced in the order given. The entire index, with all the files embedded, is stored in memory. README injection is lowkey iconic. π-e,--no-encodeβ do not encode filesystem files. Encoded files are stored in the temp directory rather than being kept in memory. This isfalseby default because itβs useful for reducing bandwidth usage. No encoding, no extra temp storage, simple as. πΈ--encoded-filesystem FS_LIMIT,--encoded-generated GEN_LIMITβ consume at mostFS_LIMITspace for encoded filesystem files (inTEMP) and at mostGEN_LIMITmemory for encoded generated responses. The arguments are an integer, optionally followed by case-insensitivek(kilobyte),m(megabyte),g(gigabyte),t(terabyte), orp(petabyte), optionally followed by case-insensitiveb. This quota may be exceeded temporarily while servicing a request. Limits are limits-ish, but not always instant. π--encoded-prune MAX_AGEβ prune cached encoded data older thanMAX_AGE. The argument is given in seconds, optionally followed by case-insensitives(seconds),m(minutes),h(hours), ord(days). Cleanup era for old encoded cache. π§Ή-x,--strip-extensionsβ allow stripping index extensions from served paths: a request to/filemight get served by/file.[s]htm[l]. This isfalseby default. Fancy path matching, only if you opt in. β¨--404 FALLBACK-FILEβ when returning a404response to aGET, sendFALLBACK-FILE, instead of a generated error page, as the body.FALLBACK-FILEis a filesystem path and is not subject to-s/-rrestrictions. Custom 404 body, because sometimes the error page needs a personality. π«Ά-q,--quiet...β suppress increasing amounts of output. Specifying this flagNtimes will, for:N == 0β show all outputN >= 1β suppress serving status lines ("IP was served something")N >= 2β suppress startup except for auth data, if presentN >= 3β suppress all startup messages
Quiet mode has layers, bestie. π€«
-Q,--quiet-timeβ donβt prepend log lines with the timestamp. Clean logs, no clock. β°-c,--no-colourβ donβt colourise log output. Monochrome log vibe, if thatβs your thing. π€
π NOTES π
Okay bestie, real talk about ETags. When this thing returns files from the filesystem, the ETag it sends back is based on the filesystem, the i-node, and the precise modification time.
So obviously, if you're serving files from filesystems with coarse timestamps (like FAT with its 1s-resolution), changes can be hidden from ETag-using user agents. The manual's example is: if a file was modified at 2023-02-12T01:00:00.100000000, a UA requested and cached a response for 2023-02-12T01:00:00.000000000, then the file was modified again at 2023-02-12T01:00:00.900000000, subsequent requests with If-None-Match: 2023-02-12T01:00:00.000000000 will all return 304 Not Modified.
This isn't really much of an issue, don't use FAT as a High-Performance File System (or reload w/o cache), and If-Modified-Since is affected with this by design, on all back-ends.
β¨ EXAMPLES β¨
These are the reference examples, bestie. The first one is the baseline, and the rest are like "same vibe, but with a twist."
πΈ http
Host the current directory on the first free port upwards of 8000, don't follow symlinks, don't allow writes.
Example output:
p:\Rust\http> http
Hosting "." on port 8000 without TLS and no authentication...
Ctrl-C to stop.
127.0.0.1:47880 was served directory listing for \\?\P:\Rust\http
127.0.0.1:47902 was served file \\?\P:\Rust\http\http.1.html as text/html
127.0.0.1:47916 was served file S:\Rust-target\doc\main.css as text/css
127.0.0.1:48049 asked for OPTIONS
127.0.0.1:47936 used disabled request method DELETE
127.0.0.1:48222 used disabled request method PUT
^C
Assuming that P:\Rust\http\target is a symlink to S:\Rust-target, the following requests have been made, in order:
GET /
GET /http.1.html
GET /target/doc/main.css
OPTIONS
DELETE <path doesn't matter>
PUT <path doesn't matter>
The above output snippet is used as a reference for other examples.
π
http -s
As in the first example, but don't follow symlinks.
Example output change:
127.0.0.1:47916 requested to GET nonexistent entity S:\Rust-target\doc\main.css
π₯ http -w
As in the first example, but allow writes.
Example output change:
127.0.0.1:47936 deleted file \\?\P:\Rust\http\http.1.html
127.0.0.1:48222 created \\?\P:\Rust\http\index.html, size: 1033554B
Corresponding request:
DELETE /http.1.html
PUT /index.html with request body containing roughly 1MB of data
Another behavioral change is that, in this case, the folder (and file) named T:/-=- TEMP -=-/http-P-Rust-http/writes/ and T:/-=- TEMP -=-/http-P-Rust-http/writes/index.html were created while the file P:\Rust\http\http.1.html was deleted (also works on directories).
π http -w -t "../TEMP"
As in the previous example, but use a different temp dir.
Behavioral changes: the created folder and file are named P:/Rust/TEMP/http-P-Rust-http/writes/ and P:/Rust/TEMP/http-P-Rust-http/writes/index.html.
π http -p 6969
As in the first example, but host on port 6969.
Assuming the port is free, example output change:
Hosting "." on port 6969 without TLS and no authentication...
If the port is taken, example output change:
Starting server failed: port taken.
<EOF>
π¦ http -a 192.168.65.1
As in the first example, but listen on address 192.168.65.1.
Assuming the address can be used, example output change:
Hosting "." on port 8000 under address 192.168.65.1 without TLS and no authentication...
If the address is inaccessible or doesn't exist, example output change:
Starting server failed: The requested address is not valid in its context.
(os error 10049).
<EOF>
π HTTP_SSL_PASS=pwd http --ssl cert/http8k.p12
As in the first example, but encrypt with the identity file cert/http8k.p12 unlocked with password "pwd".
Assuming password is correct, example output change:
Hosting "." on port 8000 TLS certificate from "cert/http8k.p12"
and no authentication...
π§ http --gen-ssl
As in the first example, but encrypt with a newly created self-signed identity file.
Example output change:
Hosting "." on port 8000 with TLS certificate from
"$TEMP/http-P-Rust-http/tls/tls.p12" and no authentication...
π http --path-auth /=Pirate
As in the first example, but require all clients to log in with the username "Pirate".
Example output change:
Hosting "." on port 8000 without TLS and basic authentication...
Basic authentication credentials:
Path Username Password
/ Pirate
On unauthed request:
127.0.0.1:15141 requested to GET http://127.0.0.1:8005/ without authorisation
Invalid credentials supplied:
127.0.0.1:15142 requested to GET http://127.0.0.1:8005/ with invalid credentials
"Pirate:memelord11"
Valid credentials supplied:
127.0.0.1:15142 correctly authorised to GET http://127.0.0.1:8005/
127.0.0.1:15142 was served directory listing for \\?\P:\Rust\http
π http --path-auth /=Pirate:memelord42
As in the first example, but require all clients to log in with the username "Pirate" and password "memelord42".
Example output change:
Hosting "." on port 8000 without TLS and basic authentication...
Basic authentication credentials:
Path Username Password
/ Pirate memelord42
See above for log messages when performing requests.
π«Ά http --gen-path-auth /
As in the first example, but generate a username:password pair and require all clients to log in therewith.
Example output change:
Hosting "." on port 8000 without TLS and basic authentication...
Basic authentication credentials:
Path Username Password
/ jOvm8yCp &gK=h&$-$HElLPb9HO%
See above for log messages when performing requests.
π‘οΈ multi-path auth (the long one)
This is the big one:
http --path-auth /=admin:admin --gen-path-auth /target/debug --path-auth
target/doc= --path-auth target/.rustc_info.json= --path-auth
target/release/=releases
As in the first example, but allow unauthenticated access to /target/doc and /target/.rustc_info.json, require username "releases" and no password to access /target/release, require a randomly-generated username:password pair to access /target/debug, and lock all other paths behind "admin:admin".
Example output change:
Hosting "." on port 8000 without TLS and basic authentication...
Basic authentication credentials:
Path Username Password
/ admin admin
/target/.rustc_info.json
/target/debug PYld448 l=Z~vdp,zAt^<uvRyU.T<F
/target/doc
/target/release releases
See above for log messages when performing requests.
β http -r
As in the first example, but restrict accessible paths to direct descendants of the hosted directory.
Example output change:
127.0.0.1:47916 requested to GET nonexistent entity S:\Rust-target\doc\main.css
π http --proxy ... and http --proxy-redir ...
The full command is:
http --proxy X-Forwarded-For:127.0.0.1 --proxy
X-Proxied-For:192.168.1.0/24 --proxy-redir X-Original-URL:127.0.0.1
As in the first example, but treat the X-Forwarded-For and X-Proxied-For as proxy headers for requests from localhost and the 192.168.1.0/24 network, respectively.
When redirecting, trust 127.0.0.1 to know how to redirect.
Given, that requests from 127.0.0.1, 192.168.1.109, and 93.184.216.34 have the following headers set:
X-Forwarded-For: OwO
X-Proxied-For: UwU
X-Original-URL: https://reversely.proxied/jpegs
Then the output will be as follows:
Hosting "." on port 8000 without TLS and no authentication...
Trusted proxies:
Header Network
X-Forwarded-For 127.0.0.1
X-Proxied-For 192.168.1.0/24
Ctrl-C to stop.
[2020-02-17 17:48:41] 127.0.0.1:1392 for OwO was served directory listing for \\?\P:\Rust\http
[2020-02-17 17:49:12] 192.168.1.109:1403 for UwU was served directory listing for \\?\P:\Rust\http
[2020-02-17 17:49:29] 93.184.216.34:1397 was served directory listing for \\?\P:\Rust\http
[2020-02-17 17:48:41] Redirecting 127.0.0.1:1393 for OwO to https://reversely.proxied/jpegs/ - found index file index.html
π¨ http --mime-type ...
The command:
http --mime-type css:text/css;charset=utf-8 --mime-type :image/jpeg
As in the first example, but send .css with the charset=utf8 attribute and treat files with no extension as JPEGs.
Then the output will be as follows:
Hosting "." on port 8000 without TLS and no authentication...
Serving files with no extension as image/jpeg.
Serving files with .css extension as text/css; charset=utf-8.
Ctrl-C to stop.
[2020-07-20 12:32:24] 127.0.0.1:47916 was served file \\?\S:\Rust-target\doc\main.css as text/css; charset=utf-8
[2020-07-20 12:32:25] 127.0.0.1:2803 was served file \\?\P:\121D800E\http\DSC_6505 as image/jpeg
π http --request-bandwidth 4K
As in the first example, but limit each request to 4096 bytes per second.
Example output change:
Hosting "." on port 8000 without TLS and no authentication...
Requests limited to 4096B/s.
Ctrl-C to stop.
π AUTHOR π
Written by thecoshman <rust@thecoshman.com>, nabijaczleweli <nabijaczleweli@nabijaczleweli.xyz>, pheki, Adrian Herath <adrianisuru@gmail.com>, cyqsimon, jim4067, Orhun ParmaksΔ±z <orhunparmaksiz@gmail.com>, Kian-Meng Ang <kianmeng@cpan.org>, Theodore Ni, and ThorbjΓΈrn Lindeijer <bjorn@lindeijer.nl>.
π REPORTING BUGS π
Bugs go here: <https://github.com/thecoshman/http/issues>.
π¦ SEE ALSO π¦
Peep the project at <https://github.com/thecoshman/http>.
This iconic page is the HTTP(1) manpage from the http developers, dated July 2026. Byeee bestie π
β¨
π¦ where this page comes from
- arch rolling: httplz 2.6.0-1 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms