SimtinHTTP user manual

SimtinHTTP is a simple and tiny HTTP server written in Rust. It focuses on Windows, but being pure Rust, it should compile easily on Linux and other operating systems as well (with some limitations, see Rust platform support). Functionally speaking, you can view it very roughly as python3 -m http.server without Python — and within less than 1 MiB (or 400 KiB with UPX compression).

It started as a project to serve files from a local folder over Tor, as a replacement to Onionshare, which is great but is too heavy, does a bit too many things to be really simple to set up, and for some reason won’t provide a portable setup (yes, that ticket is from 2017 🤷). SimtinHTTP is also appropriate to serve files on a home network (for instance, I use it to read videos on my HY300Pro projector), and, provided that you know what you are doing, it can also be used to serve files publicly over the internet, with some additional configuration efforts (in a nutshell, configuring port forwarding or your firewall if applicable).

As a result, its focus is to be:

Since the primary purpose of SimtinHTTP is to serve files over Tor, it should also not require JavaScript on the client side, as Tor users generally prefer to keep JavaScript off.

Getting started

Quick start

1. Create a file named config.json with this minimal content:

{
  "serverBindings": [
    {
      "basePath": "folder to serve"
    }
  ]
}

2. Place config.json in the same folder as simtin-http.exe

3. Run simtin-http.exe

4. Open your browser and go to http://127.0.0.1:8080/

More detailed configuration file

Create a file named config.json and following this structure:

{
  "serverBindings": [
    {
      "bindAddress": "127.0.0.1:8080",
      "basePath": "C:/root/folder1/"
    },
    {
      "bindAddress": "127.0.0.1:8081",
      "basePath": "C:/root/folder2/"
    }
  ],
  "ipWhitelist" [],
  "cache": {
    "size": 1000,
    "ttl": 60
  },
  "debug": false,
  "directoryIndex": "just a placeholder",
  "enableDirectoryListing": true,
  "log": {
    "level": "info",
    "timestamp": "ms",
    "output": "stdout"
  },
  "shortSizeUnits": false,
  "showLastModified": true,
  "showServerSignature": 2
}

The parameters are detailed in the table below:

Parameter Type Default Description
serverBindings Array no default (mandatory) Array of server bindings. Each binding is an object with the properties basePath and bindAddress. See below for details about each of them.
Example: [{"basePath": "C:/root/folder1/", "bindAddress": "127.0.0.1:8080"}]
ipWhitelist Array [] Array of whitelisted IPs. If empty or missing, all IPs are allowed. Otherwise, only the listed IPs are allowed, and connections from other IPs are dropped without sending a response.
Example: ["127.0.0.1", "127.0.0.2"]
serverBindings[].basePath String no default (mandatory) Folder to serve. Example: C:/root/folder/
EVERYTHING in that folder (and, obviously, subfolders) will be made accessible via the server, so choose wisely. And yes, even “hidden” files, files with a name that starts with a dot, “.htaccess”, etc. Every. Thing.
Relative paths should work, but you’ll probably want to use an absolute path in order to avoid bad surprises.
serverBindings[].bindAddress String 127.0.0.1:8080 Address and port to listen on (format: IP:Port). The default will only serve requests from localhost, which is enough for a Tor onion.
Set it to 0.0.0.0:8080 if you want to serve from all interfaces, or something like 192.168.1.1:8080 (whatever your LAN IP is) to serve on your home network. Don’t forget to customize the port as needed.
While it is not mandatory, if you want to serve multiple base folders you will have to configure each of them with a unique bindAddress, so the default value will only take you so far.
cache.size usize 1000 Maximum number of entries in the cache. Note that the cache will only cache (fully HTML-rendered) directory listings. So, while not offering direct control over the size in bytes, each entry is expected to be reasonably small, and this will depend on your typical directory contents.
cache.ttl 64-bit integer 60 TTL (time to live) for cache entries, in seconds. If your directory contents barely ever change, you may want to increase it. If they change often, you may want to decrease it, or even get a build without the cache feature.
debug boolean false Set to true to enable some debugging features.
You’ll probably want to keep it false. In its current state, true won’t cause a big mess either, but you never know how it will change.
directoryIndex String[] None An ordered array of names of files to display when a directory is requested. SimtinHTTP will pick the first one that exists. If empty or not set (or invalid), or if none of the listed index files exists, SimtinHTTP will display a list of the files in the directory if enableDirectoryListing is set to true, or a not found error if false.
Example: ["index.html", "index.htm"]
enableDirectoryListing boolean false If set to true, SimtinHTTP will display a list of the files in the directory when a directory is requested.
The default it false, for the sake of consistency with the rest of the other default settings, which were chosen with a focus on security and minimizing information leaks.
This is, however, a breaking change compared to the previous behavior, as well as a bit of a departure from the original design. It also adds a little extra step to the first-time setup.
log.level String info Verbosity level of the logger. Corresponds to the log::Level enum from the log crate.
Possible values, from most to least verbose: trace, debug, info, warn, error, off. trace is currently not used.
log.timestamp String ms Formatting precision of timestamps.
Possible values: s, m (ms, milliseconds), µ (µs, microseconds), n (ns, nanoseconds).
log.ouput String stdout Where to output the logs.
Possible values: stdout, stderr, file some/file/name.txt (don’t forget the “file ” prefix).
shortSizeUnits boolean false If set to true, units will be abbreviated even more, like K instead of kiB, B instead of bytes, etc.
showLastModified boolean false Whether to show the last modified date of your files.
You’ll probably want to set it to true because it’s quite nicer this way. But as security and minimizing information leaks is a priority for the project, it’s set to false by default.
showServerSignature 8-bit integer 0 Whether to show the server signature: 0 shows nothing, 1 shows the name, 2 shows the name and version.
It’s typically a good practice to at least hide the version. However, since we’re not that mainstream (yet?), 2 should be safe enough.
Again, it’s set to 0 by default due to our security focus, but setting it to 1 would be kind to spread the word 👀
Note that 0 will attempt to make the server less recognizable, by not serving the user manual, nor the logo/favicon or the default styles. Which will have the side effect of making the directory listing look a bit ugly. Also note that this setting will probably evolve in the future, but 0 and 1 should remain roughly the same.

Running the server

Place the config.json file in the same directory as the simtin-http.exe file, and run the server with:

simtin-http.exe

You should then be able to access the server at http://127.0.0.1:8080/ (obviously, change the port as needed, and the path to something that exists). If you set bindAddress to 0.0.0.0:8080 and you’re not behind some kind of firewall or router, you might well be already able to access the server at http://[your-external-ip]:8080/ from anywhere. Which you might want to ask yourself if this is what you really want.

As of version 0.7.2, you can also name the configuration file as you want, and pass its name as an argument: simtin-http.exe "my/cfg.file"

Going further…

Configuring Tor

This section is written with Windows in mind. However, the mentioned Tor Expert Bundle is available for Linux and macOS, and the instructions for those platforms should be roughly the same.

Downloading Tor

Start by downloading the latest version of Tor from https://www.torproject.org/download/tor/. Note that you need Tor (the “Tor Expert Bundle”), not the usual “Tor Browser”. But you should also get Tor Browser as well, if you don’t already have it, in order to later test your setup.

From this bundle, extract tor.exe, geoip and geoip6. Place them wherever you want, but I recommend placing them all together in a dedicated folder. Let’s call it tordir.

Creating the torrc configuration file

In tordir, create a file named torrc and following this structure:

DataDirectory [tordir]\data
DisableNetwork 0
GeoIPFile [tordir]\geoip
GeoIPv6File [tordir]\geoip6
Log notice stdout

ExitRelay 0

HiddenServiceDir [tordir]\hsdir
HiddenServicePort 80 127.0.0.1:8080

SocksPolicy reject *
SocksPort 0
    

Obviously, replace [tordir] with the actual, full path to where you placed geoip and geoip6. The data and hsdir folders may need to be created manually. You may also choose to place them elsewhere, or name them something else.

You can find what appears to be a fairly complete list of parameters at https://manpages.debian.org/testing/tor/torrc.5.en.html. Briefly, notably because finding documentation isn’t as easy as I wished it was:

See also https://community.torproject.org/onion-services/setup/ for some additional information on configuring a Tor Onion service.

Running Tor

Assuming you did place torrc in the same folder as tor.exe, you can start tor with:

tor.exe -f torrc

After a short moment, you should be able to access your hidden service, in Tor Browser, at http://[random stuff].onion, where [random stuff].onion is the name found in the hostname file that was automatically created in HiddenServiceDir.

Note that tor seems to not be very happy when you restart it “too often”, so you’ll want to double-check your config file before running it the first time, as well as before restarting it to update the config file. Many times, my onion would become unreachable for a long time after a restart. A quick fix is to delete the HiddenServiceDir in order to generate a brand new onion address, but obviously it can be a bit of a problem if you don’t want the address to change.
There are ways to configure Tor to accept commands such as reloading the config on the fly (without restarting), but that’s beyond the scope of this manual. Long story short, look into ControlPort and related settings.

Configuring port forwarding

This section is under construction / a very brief draft, but it can only do so much, as this is something that depends on your router, your local network setup, and you ability to configure those.

Using UPnP

A tool that worked for me is Portmapper. It uses Java, so it’s annoying because it uses Java, but it’s also convenient because it should work no matter your OS. The most important trick about it is that it includes 4 different UPnP libraries (actually I think there are just 3 plus a fake one), so if the default one doesn’t work for you, you should definitely try the others until one works: for me, the good one was the third.

In your router settings

Todo: add some pointers. But generally speaking, that will be in your router settings.

Feature flags

Concise change log

Version 0.8.1

Version 0.8.0

Version 0.7.2

Version 0.7.0

Version 0.6.0

Credits

SimtinHTTP uses the following libraries:

Library Description License
bytes Types and traits for working with bytes MIT
chrono Date and time library for Rust MIT or Apache-2.0
env_logger A logging implementation for `log` which is configured via an environment variable. MIT or Apache-2.0
fifo-cache A minimalist FIFO cache with TTL (Time To Live) support MIT
futures An implementation of futures and streams featuring zero allocations, composability, and iterator-like interfaces. MIT or Apache-2.0
futures-util Common utilities and extension traits for the futures-rs library. MIT or Apache-2.0
http-body-util Combinators and adapters for HTTP request or response bodies. MIT
hyper A protective and efficient HTTP library for all MIT
hyper-util A collection of utilities to do common things with hyper MIT
Iconoir An open-source library with 1500+ unique SVG icons, designed on a 24x24 pixels grid MIT
jiff A date-time library that encourages you to jump into the pit of success. This library is heavily inspired by the Temporal project. Unlicense or MIT
log A lightweight logging facade for Rust MIT or Apache-2.0
serde A generic serialization/deserialization framework MIT or Apache-2.0
serde_json A JSON serialization file format MIT or Apache-2.0
tokio An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications MIT
tokio-util Additional utilities for working with Tokio MIT
urlencoding A Rust library for doing URL percentage encoding. MIT

And, only for building:

Library Description License
list-features Extracts the list of enabled feature flags during compilation. MIT

* SimtinHTTP isn’t a statin, but it is a-static 😏