Skip to content

Releases: csd113/RustHost

v0.1.3.1 minor bugfix

13 Apr 21:14
a7887f0

Choose a tag to compare

[v0.1.3.1]

Changed

  • Simplified the generated data directory so fresh installs now create site/, settings.toml, and a single runtime/ tree for logs, TLS state, and Tor state instead of scattering runtime-owned folders at the top level.

What's Changed

  • v1.3.1 minor bug fix by @csd113 in #18
  • Normalize rooted path validation across platforms by @csd113 in #19
  • Fix ACME client config clippy violations by @csd113 in #20

Full Changelog: v0.1.3...v0.1.3.1

v0.1.3

31 Mar 23:13
64d0b96

Choose a tag to compare

[v0.1.3]

Simplified updates

  • Added stronger static-file delivery polish with Last-Modified revalidation, precompressed asset sidecar support (.br / .gz), and a lighter-weight identity streaming path for common uncompressed responses.
  • Moved the initial site scan off the startup critical path, skipping it in headless mode so the server can begin accepting traffic sooner.
  • Added a shared reload path that also responds to SIGHUP, making headless deployments easier to operate without relying on the interactive dashboard.
  • Improved headless runtime output so startup summarizes HTTP/HTTPS/site/Tor state, and Tor now logs the full onion address explicitly when it becomes ready.
  • Removed a small hot-path allocation from Accept-Encoding parsing by switching quality-value parsing to a fixed-width stack-only loop.
  • Reworked listener lifecycle management so HTTP, HTTPS, and redirect servers continuously reap completed connection tasks instead of retaining them until shutdown.
  • Moved access-log disk writes onto a bounded background worker, preventing request handling from blocking on synchronous access-log I/O and surfacing dropped-log backpressure when the queue overflows.
  • Hardened HTTPS redirect startup by validating redirect configs up front and requiring the redirect listener to bind successfully before startup continues.
  • Switched generated defaults to safer production behavior by disabling automatic port fallback and built-in Tor until an operator explicitly enables them.
  • Made graceful shutdown budgets configurable and applied them consistently to HTTP, HTTPS, redirect, and Tor drain behavior so normal restarts are less likely to cut off slow transfers.
  • Made HTTPS startup fail closed so TLS configuration or HTTPS bind failures now stop startup instead of silently falling back to insecure HTTP-only serving.
  • Fixed Tor's internal upstream address selection so onion traffic always connects back through loopback when the public listener is bound to 0.0.0.0 or ::.
  • Moved per-request filesystem path resolution onto Tokio's blocking pool to avoid starving the async runtime under slow-disk or hostile request load.
  • Tightened connection admission so HTTP, HTTPS, and redirect listeners reject overflow immediately instead of holding accepted sockets open while waiting for permits.
  • Completed the shared response hardening path so redirects, OPTIONS, 405, 304, and other non-file responses now receive the full security-header set consistently.
  • Added automatic Onion-Location headers on clearnet HTTPS responses when the built-in Tor onion service is ready, so supporting browsers can surface the .onion version of the current page.
  • Re-enabled built-in Tor by default for newly generated configs and shortened the default Tor shutdown drain window from 30 seconds to 5 seconds.
  • Wired site.error_503 into runtime serving and preload custom error pages at startup with size limits, removing per-request reloads and dead config.
  • Improved access-log accuracy by recording real Content-Length values when known and - when a streamed/compressed size is not known ahead of time.
  • Made compression more production-friendly by honoring Accept-Encoding quality values and skipping obviously poor candidates such as tiny or already-compressed assets.
  • Hardened private filesystem creation further by validating directory chains, rejecting symlink hops, and keeping restrictive permissions in place for Tor and TLS state.
  • Cleaned up startup and shutdown reliability by draining failed startup tasks, allowing structured access-log reinitialization after shutdown, and holding ACME lifecycle ownership in runtime state instead of a permanent one-shot global.
  • Fixed IPv6 listener binding and local URL rendering so HTTP, HTTPS, redirect, dashboard, and localhost flows all handle bracketed IPv6 addresses correctly.
  • Corrected the Arti relay timeout behavior so active long-lived transfers are limited by idle time instead of a mistaken full-session wall clock.
  • Bounded directory listings during traversal instead of collecting and sorting an entire hostile directory before truncation.
  • Expanded test coverage with HTTPS handshake tests, IPv6 HTTP tests, ACME restart lifecycle coverage, redirect handling, proxy IP resolution, custom 503 pages, and connection-limit rejection.
  • Added top-of-file file/location reference headers across the codebase, removed stale issue-fix annotations, and continued splitting logic into smaller focused modules.
  • Rewrote the README and setup guide to better document production scope, cross-platform behavior, HTTPS/Tor setup, headless operation, and static-hosting-only expectations.
  • Removed duplicate setup filename variants so the repository stays clean on case-insensitive macOS and Windows filesystems.

v0.1.2 HTTPS Support

28 Mar 17:23

Choose a tag to compare

[v0.1.2]

Added

  • HTTPS support — RustHost can now serve your site over a secure, encrypted connection (the padlock icon in your browser). Works out of the box with no extra software needed.
  • Automatic self-signed certificates — when you turn on HTTPS with no other setup, RustHost creates its own certificate for local development. Great for testing on your own machine.
  • Let's Encrypt integration — RustHost can automatically get and renew a free, trusted certificate from Let's Encrypt so browsers won't show any warnings for your real domain.
  • Bring-your-own certificate — if you already have certificate files from another provider, you can point RustHost at them directly.
  • HTTP-to-HTTPS redirect — optionally sends visitors who arrive on the plain HTTP address over to the secure HTTPS address automatically.
  • [tls] config section — new settings in settings.toml to control all of the above. If you don't add this section, everything works exactly as before — nothing breaks.
  • Security headers on HTTPS — secure connections automatically include headers that tell browsers to always use HTTPS for your site in the future.

Changed

  • Connection handler is now flexible — the part of RustHost that talks to browsers was updated so it can handle both regular and encrypted connections. Existing HTTP behavior is unchanged.

v0.1.1 Bug Fixes and Reliability Improvements

24 Mar 01:10

Choose a tag to compare

[v0.1.1]

Added

  • Depth-bounded scan_site BFS — the directory scanner now stops at 64 levels deep and emits a warning instead of running indefinitely on adversarially deep directory trees.
  • Multiple log rotation backupsLogFile::rotate now keeps up to five numbered backup files (.log.1.log.5) instead of one, matching what operators expect from tools like logrotate.

Changed

  • lib.rs visibility audit — items only used in integration tests (percent_decode, ByteRange, Encoding, onion_address_from_pubkey) are now re-exported under #[cfg(test)] rather than unconditionally, reducing the public API surface.
  • Comment hygiene — all internal fix X.Y tags have been replaced with descriptive prose so the rationale for each decision is clear to contributors.

Repository & CI (Phase 0)

  • rust-toolchain.toml — pins the nightly channel so every contributor and CI run uses the same compiler. No more "works on my machine" build failures.
  • GitHub Actions CI — runs build, test, clippy, rustfmt, cargo-audit, and cargo-deny on Ubuntu, macOS, and Windows on every push and PR.
  • Cargo.toml profile tuningopt-level = 1 for dev dependencies speeds up debug builds; the release profile uses lto = true, strip = true, and codegen-units = 1 for a smaller, faster binary.

HTTP Server

  • Keep-alive via hyper 1.x — migrated from a hand-rolled single-shot HTTP/1.1 parser to hyper. Eliminates the 30–45 second Tor page-load penalty that was caused by Connection: close on every response.
  • Brotli and Gzip compression — negotiated via Accept-Encoding. Brotli is preferred over Gzip for Tor users since they pay in latency for every byte.
  • ETag / conditional GET — weak ETags computed from file modification time and size. Returns 304 Not Modified when If-None-Match matches, saving a round-trip.
  • Range requests — supports bytes=N-M, bytes=N-, and bytes=-N suffix forms. Returns 206 Partial Content or 416 Range Not Satisfiable as appropriate. Enables audio and video seeking.
  • Per-IP rate limitingDashMap-backed lock-free CAS loop. Connections beyond max_connections_per_ip are dropped at accept time with a TCP RST.
  • Smart Cache-Control — HTML responses get no-store; content-hashed assets (8–16 hex characters in the filename stem) get max-age=31536000, immutable; everything else gets no-cache.
  • Security headers on every responseX-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN, Referrer-Policy: no-referrer, and Permissions-Policy: camera=(), microphone=(), geolocation=(). HTML responses additionally include a configurable Content-Security-Policy.
  • --serve <dir> one-shot mode — serve a directory directly without a settings.toml. Skips first-run setup entirely.
  • Extended MIME types — added .webmanifest, .opus, .flac, .glb, and .ndjson.
  • Combined Log Format access log — written to logs/access.log with owner-only 0600 permissions.

Tor / Onion Service

  • Idle timeout fix (copy_with_idle_timeout) — replaced the wall-clock cap (which disconnected active large downloads after 60 seconds) with a true per-side idle deadline that resets on every read or write.
  • reference_onion test — replaced the tautological self-referencing test with an external test vector computed independently using Python's standard library.

Configuration

  • URL redirect and rewrite rules[[redirects]] table in settings.toml, checked before filesystem resolution. Supports 301 and 302.
  • Custom error pagessite.error_404 and site.error_503 config keys resolve to HTML files served with the correct status codes.
  • --config and --data-dir CLI flags — override the default config and data directory paths. Enables multi-instance deployments and systemd unit files with explicit paths.
  • --version and --help CLI flags.
  • #[serde(deny_unknown_fields)] on all config structs — a misspelled key like bund = "127.0.0.1" causes a clear startup error instead of silently using the default.
  • Typed config fieldsbind is std::net::IpAddr; log level is a LogLevel enum. Invalid values are caught at deserialisation time, not after the server starts.

Features

  • SPA fallback routing — unknown paths fall back to index.html when site.spa_routing = true, enabling React, Vue, and Svelte client-side routing.
  • canonical_root hot reload — the [R] keypress pushes a new canonicalised root to the accept loop over a watch channel without restarting the server.
  • Dependency log filtering — Arti and Tokio internals at Info and below are suppressed by default, keeping the log focused on application events. Configurable via filter_dependencies.

Reliability

  • Exponential backoff for Tor retries — re-bootstrap retries now use exponential backoff (30 s, 60 s, 120 s, …, capped at 300 s) instead of a fixed linear delay.
  • Shutdown drain per subsystem — HTTP and Tor drains each have their own independently-bounded timeout (5 s for HTTP, 10 s for Tor) so a slow HTTP drain doesn't steal time from Tor circuit teardown.
  • percent-encoding crate — replaced the hand-rolled percent_decode function with the audited upstream crate. Added a null-byte guard specific to filesystem path use.
  • scan_site partial failure — unreadable subdirectories are skipped with a warning instead of aborting the entire scan.
  • fstat batchingLogFile::write_line calls fstat every 100 writes (instead of on every record) to reduce syscall overhead on active servers.

Testing & CI

  • Unit tests for all security-critical functionspercent_decode, resolve_path, validate, strip_timestamp, and hsid_to_onion_address all have #[cfg(test)] coverage.
  • Integration tests (tests/http_integration.rs) — covers all HTTP core flows using raw TcpStream: 200, HEAD, 304, 403, 404, 400, range requests, and oversized headers.

Fixed

Critical (Phase 1)

  • Config path traversalvalidate() now rejects any site.directory or logging.file value that is an absolute path, contains .., or contains a platform path separator. Previously, directory = "../../etc" would cause the server to serve the entire /etc tree.
  • Tor port race condition — replaced the 50 ms sleep used to synchronise the HTTP server's bound port with the Tor subsystem with a tokio::sync::oneshot channel. The server sends the actual bound port through the channel before entering the accept loop. Previously, on a loaded system, the race could be lost silently, causing every inbound Tor connection to fail with ECONNREFUSED to port 0 while the dashboard showed a healthy green status.
  • XSS in directory listingsbuild_directory_listing() now HTML-entity-escapes all filenames before interpolating them into link text, and percent-encodes filenames in href attributes. Previously, a file named "><script>alert(1)</script> produced an executable XSS payload in any directory listing page.
  • HEAD requests sent a response bodyHEAD requests now send the correct headers (including Content-Length reflecting the full body size) but no body, as required by RFC 7231 §4.3.2. Previously, the full file was sent.
  • Slow-loris DoSread_request() is now wrapped in a 30-second timeout. Connections that don't deliver a complete request header in time receive a 408 Request Timeout. Configurable via request_timeout_secs.
  • Unbounded connection spawning — both the HTTP accept loop and the Tor stream loop now use a tokio::sync::Semaphore to cap concurrent connections (default: 256). Previously, unlimited concurrent connections could exhaust file descriptors and task stack memory.
  • Files loaded entirely into memory — replaced tokio::fs::read (which loaded the entire file into a Vec<u8>) with tokio::fs::File::open + tokio::io::copy. Memory per connection is now bounded by the kernel socket buffer (~128–256 KB) regardless of file size.
  • strip_timestamp panic on non-ASCII log lines — the old implementation used a byte index derived from .bytes() to slice a &str, which panicked when the index fell inside a multi-byte UTF-8 character. Now uses splitn(3, ']'), which is both panic-safe and handles Unicode correctly.
  • TorStatus not updated when onion service terminates — when the onion service stream ends unexpectedly, the status is now set to TorStatus::Failed("stream ended") and the .onion address is cleared. Previously, the dashboard permanently showed a healthy green badge after the service had silently stopped.
  • Terminal not restored on panic or crash — a std::panic::set_hook is registered at startup to call console::cleanup() (which issues LeaveAlternateScreen, cursor::Show, and disable_raw_mode) on all exit paths. The cleanup function is idempotent, so calling it from multiple paths is safe.

High — Reliability (Phase 2)

  • HTTP request reading done byte-by-byteread_request() previously issued up to 8,192 individual read syscalls per request. The stream is now wrapped in tokio::io::BufReader and headers are read line-by-line. Also correctly handles \r\n\r\n split across multiple TCP segments.
  • scan_site only scanned the top-level directory — now performs a full breadth-first traversal using a work queue, counting files and sizes in all subdirectories. Unreadable directories are skipped with a warning instead of propagating an error.
  • canonicalize() called on every request — the site root is now canonicalised once at startup and passed into each connection handler. Eliminates a realpath() syscall on every single request.
  • open_browser duplicated — the function existed in two separate source fil...
Read more

v0.1.0

22 Mar 08:04
be9a8e2

Choose a tag to compare

Changelog

All notable changes to RustHost are documented here.


[0.1.0] — Initial Release

HTTP Server

  • Custom HTTP/1.1 static file server built directly on tokio::net::TcpListener — no third-party HTTP framework dependency.
  • Serves GET and HEAD requests; all other methods return 400 Bad Request.
  • Percent-decoding of URL paths (e.g. %20 → space) before file resolution.
  • Query string and fragment stripping before path resolution.
  • Path traversal protection: every resolved path is verified to be a descendant of the site root via std::fs::canonicalize; any attempt to escape (e.g. /../secret) is rejected with HTTP 403 Forbidden.
  • Request header size cap of 8 KiB; oversized requests are rejected immediately.
  • Content-Type, Content-Length, and Connection: close headers on every response.
  • Configurable index file (default: index.html) served for directory requests.
  • Optional HTML directory listing for directory requests when no index file is found, with alphabetically sorted entries.
  • Built-in "No site found" fallback page (HTTP 200) when the site directory is empty and directory listing is disabled, so the browser always shows a helpful message rather than a connection error.
  • Placeholder index.html written on first run so the server is immediately functional out of the box.
  • Automatic port fallback: if the configured port is in use, the server silently tries the next free port up to 10 times before giving up (configurable via auto_port_fallback).
  • Configurable bind address; defaults to 127.0.0.1 (loopback only) with a logged warning when set to 0.0.0.0.
  • Per-connection Tokio tasks so concurrent requests never block each other.

MIME Types

  • Built-in extension-to-MIME mapping with no external dependency, covering:
    • Text: html, htm, css, js, mjs, txt, csv, xml, md
    • Data: json, jsonld, pdf, wasm, zip
    • Images: png, jpg/jpeg, gif, webp, svg, ico, bmp, avif
    • Fonts: woff, woff2, ttf, otf
    • Audio: mp3, ogg, wav
    • Video: mp4, webm
    • Unknown extensions fall back to application/octet-stream.

Tor Onion Service (Arti — in-process)

  • Embedded Tor support via Arti, the official Rust Tor implementation — no external tor binary or torrc file required.
  • Bootstraps to the Tor network in a background Tokio task; never blocks the HTTP server or console.
  • First run downloads approximately 2 MB of directory consensus data (approximately 30 seconds); subsequent runs reuse the cache and start in seconds.
  • Stable .onion address across restarts: the service keypair is persisted to rusthost-data/arti_state/; deleting this directory rotates to a new address.
  • Consensus cache stored in rusthost-data/arti_cache/ for fast startup.
  • Onion address encoded in-process using the v3 .onion spec (SHA3-256 checksum + base32) — no dependency on Arti's DisplayRedacted formatting.
  • Each inbound Tor connection is bridged to the local HTTP server via tokio::io::copy_bidirectional in its own Tokio task.
  • Tor subsystem can be disabled entirely with [tor] enabled = false; the dashboard onion section reflects this immediately.
  • Graceful shutdown: the TorClient is dropped naturally when the Tokio runtime exits, closing all circuits cleanly — no explicit kill step needed.
  • .onion address displayed in the dashboard and logged in a prominent banner once the service is active.

Interactive Terminal Dashboard

  • Full-screen raw-mode terminal UI built with crossterm; no external TUI framework.
  • Three screens navigable with single-key bindings:
    • Dashboard (default) — live status overview.
    • Log view — last 40 log lines, toggled with [L].
    • Help overlay — key binding reference, toggled with [H]; any other key dismisses it.
  • Dashboard sections:
    • Status — local server state (RUNNING with bind address and port, or STARTING) and Tor state (DISABLED / STARTING / READY / FAILED with exit code).
    • Endpoints — local http://localhost:<port> URL and Tor .onion URL (or a dim status hint if Tor is not yet ready).
    • Site — directory path, file count, and total size (auto-scaled to B / KB / MB / GB).
    • Activity — total request count and error count (errors highlighted in red when non-zero).
    • Key bar — persistent one-line reminder of available key bindings.
  • Dashboard redraws at a configurable interval (default: 500 ms).
  • Log view supports optional HH:MM:SS timestamp display, toggled via show_timestamps in config.
  • Customisable instance name shown in the dashboard header (max 32 characters).
  • Headless / non-interactive mode: set [console] interactive = false for systemd or piped deployments; the server prints a plain http://… line to stdout instead.
  • Graceful terminal restore on fatal crash: raw mode is disabled and the cursor is shown even if the process exits unexpectedly.

Configuration

  • TOML configuration file (rusthost-data/settings.toml) with six sections: [server], [site], [tor], [logging], [console], [identity].
  • Configuration validated at startup with clear, multi-error messages before any subsystem is started.
  • Validated fields include port range, bind IP address format, index file name (no path separators), log level, console refresh rate minimum (100 ms), instance name length (1–32 chars), and absence of control characters in the name.
  • Full default config written automatically on first run with inline comments explaining every option.
  • Reloading site stats (file count and total size) without restart via [R] in the dashboard.

Logging

  • Custom log::Log implementation; all modules use the standard log facade macros (log::info!, log::warn!, etc.).
  • Dual output: log file on disk (append mode, parent directories created automatically) and an in-memory ring buffer.
  • Ring buffer holds the most recent 1 000 lines and feeds the console log view without any file I/O on each render tick.
  • Log file path configurable relative to rusthost-data/; defaults to logs/rusthost.log.
  • Configurable log level: trace, debug, info, warn, error.
  • Timestamped entries in [LEVEL] [HH:MM:SS] message format.
  • Logging can be disabled entirely ([logging] enabled = false) for minimal-overhead deployments.

Lifecycle and Startup

  • First-run detection: if rusthost-data/settings.toml does not exist, RustHost initialises the data directory (site/, logs/), writes defaults, drops a placeholder index.html, prints a short getting-started guide, and exits cleanly — no daemon started.
  • Normal run startup sequence: load and validate config → initialise logging → build shared state → scan site directory → bind HTTP server → start Tor (if enabled) → start console → open browser (if configured) → enter event loop.
  • Shutdown triggered by [Q] keypress or SIGINT/SIGTERM (via ctrlc); sends a watch-channel signal to the HTTP server and console, then waits 300 ms for in-flight connections before exiting.
  • Optional browser launch at startup (open_browser_on_start); uses open (macOS), explorer (Windows), or xdg-open (Linux/other).
  • All subsystems share state through an Arc<RwLock<AppState>>; hot-path request and error counters use separate Arc<Metrics> backed by atomics so the HTTP handler never acquires a lock per request.

Project and Build

  • Single binary; no installer, no runtime dependencies beyond the binary itself (Tor included via Arti).
  • Data directory co-located with the binary at ./rusthost-data/; entirely self-contained.
  • Minimum supported Rust version: 1.86 (required by arti-client 0.40).
  • Release profile: opt-level = 3, LTO enabled, debug symbols stripped.
  • cargo-deny configuration (deny.toml) enforcing allowed SPDX licenses (MIT, Apache-2.0, Apache-2.0 WITH LLVM-exception, Zlib, Unicode-3.0) and advisory database checks; known transitive duplicate crates (mio, windows-sys) skipped with comments.
  • Advisory RUSTSEC-2023-0071 (RSA Marvin timing attack) acknowledged and suppressed with a documented rationale: the rsa crate is a transitive dependency of arti-client used exclusively for RSA signature verification on Tor directory consensus documents, not decryption; the attack's threat model does not apply.

First functional Release

20 Mar 18:33
98717a8

Choose a tag to compare

Pre-release

HTTP Server

  • Custom HTTP/1.1 static file server built directly on tokio::net::TcpListener — no third-party HTTP framework dependency.
  • Serves GET and HEAD requests; all other methods return 400 Bad Request.
  • Percent-decoding of URL paths (e.g. %20 → space) before file resolution.
  • Query string and fragment stripping before path resolution.
  • Path traversal protection: every resolved path is verified to be a descendant of the site root via std::fs::canonicalize; any attempt to escape (e.g. /../secret) is rejected with HTTP 403 Forbidden.
  • Request header size cap of 8 KiB; oversized requests are rejected immediately.
  • Content-Type, Content-Length, and Connection: close headers on every response.
  • Configurable index file (default: index.html) served for directory requests.
  • Optional HTML directory listing for directory requests when no index file is found, with alphabetically sorted entries.
  • Built-in "No site found" fallback page (HTTP 200) when the site directory is empty and directory listing is disabled, so the browser always shows a helpful message rather than a connection error.
  • Placeholder index.html written on first run so the server is immediately functional out of the box.
  • Automatic port fallback: if the configured port is in use, the server silently tries the next free port up to 10 times before giving up (configurable via auto_port_fallback).
  • Configurable bind address; defaults to 127.0.0.1 (loopback only) with a logged warning when set to 0.0.0.0.
  • Per-connection Tokio tasks so concurrent requests never block each other.

MIME Types

  • Built-in extension-to-MIME mapping with no external dependency, covering:
    • Text: html, htm, css, js, mjs, txt, csv, xml, md
    • Data: json, jsonld, pdf, wasm, zip
    • Images: png, jpg/jpeg, gif, webp, svg, ico, bmp, avif
    • Fonts: woff, woff2, ttf, otf
    • Audio: mp3, ogg, wav
    • Video: mp4, webm
    • Unknown extensions fall back to application/octet-stream.

Interactive Terminal Dashboard

  • Full-screen raw-mode terminal UI built with crossterm; no external TUI framework.
  • Three screens navigable with single-key bindings:
    • Dashboard (default) — live status overview.
    • Log view — last 40 log lines, toggled with [L].
    • Help overlay — key binding reference, toggled with [H]; any other key dismisses it.
  • Dashboard sections:
    • Status — local server state (RUNNING with bind address and port, or STARTING) and Tor state (DISABLED / STARTING / READY / FAILED with exit code).
    • Endpoints — local http://localhost:<port> URL and Tor .onion URL (or a dim status hint if Tor is not yet ready).
    • Site — directory path, file count, and total size (auto-scaled to B / KB / MB / GB).
    • Activity — total request count and error count (errors highlighted in red when non-zero).
    • Key bar — persistent one-line reminder of available key bindings.
  • Dashboard redraws at a configurable interval (default: 500 ms).
  • Log view supports optional HH:MM:SS timestamp display, toggled via show_timestamps in config.
  • Customisable instance name shown in the dashboard header (max 32 characters).
  • Headless / non-interactive mode: set [console] interactive = false for systemd or piped deployments; the server prints a plain http://… line to stdout instead.
  • Graceful terminal restore on fatal crash: raw mode is disabled and the cursor is shown even if the process exits unexpectedly.

Configuration

  • TOML configuration file (rusthost-data/settings.toml) with six sections: [server], [site], [tor], [logging], [console], [identity].
  • Configuration validated at startup with clear, multi-error messages before any subsystem is started.
  • Validated fields include port range, bind IP address format, index file name (no path separators), log level, console refresh rate minimum (100 ms), instance name length (1–32 chars), and absence of control characters in the name.
  • Full default config written automatically on first run with inline comments explaining every option.
  • Reloading site stats (file count and total size) without restart via [R] in the dashboard.

Logging

  • Custom log::Log implementation; all modules use the standard log facade macros (log::info!, log::warn!, etc.).
  • Dual output: log file on disk (append mode, parent directories created automatically) and an in-memory ring buffer.
  • Ring buffer holds the most recent 1 000 lines and feeds the console log view without any file I/O on each render tick.
  • Log file path configurable relative to rusthost-data/; defaults to logs/rusthost.log.
  • Configurable log level: trace, debug, info, warn, error.
  • Timestamped entries in [LEVEL] [HH:MM:SS] message format.
  • Logging can be disabled entirely ([logging] enabled = false) for minimal-overhead deployments.

Lifecycle and Startup

  • First-run detection: if rusthost-data/settings.toml does not exist, RustHost initialises the data directory (site/, logs/), writes defaults, drops a placeholder index.html, prints a short getting-started guide, and exits cleanly — no daemon started.
  • Normal run startup sequence: load and validate config → initialise logging → build shared state → scan site directory → bind HTTP server → start Tor (if enabled) → start console → open browser (if configured) → enter event loop.
  • Shutdown triggered by [Q] keypress or SIGINT/SIGTERM (via ctrlc); sends a watch-channel signal to the HTTP server and console, then waits 300 ms for in-flight connections before exiting.
  • Optional browser launch at startup (open_browser_on_start); uses open (macOS), explorer (Windows), or xdg-open (Linux/other).
  • All subsystems share state through an Arc<RwLock<AppState>>; hot-path request and error counters use separate Arc<Metrics> backed by atomics so the HTTP handler never acquires a lock per request.

Project and Build

  • Single binary; no installer, no runtime dependencies beyond the binary itself (Tor included via Arti).
  • Data directory co-located with the binary at ./rusthost-data/; entirely self-contained.
  • Minimum supported Rust version: 1.86 (required by arti-client 0.40).
  • Release profile: opt-level = 3, LTO enabled, debug symbols stripped.
  • cargo-deny configuration (deny.toml) enforcing allowed SPDX licenses (MIT, Apache-2.0, Apache-2.0 WITH LLVM-exception, Zlib, Unicode-3.0) and advisory database checks; known transitive duplicate crates (mio, windows-sys) skipped with comments.
  • Advisory RUSTSEC-2023-0071 (RSA Marvin timing attack) acknowledged and suppressed with a documented rationale: the rsa crate is a transitive dependency of arti-client used exclusively for RSA signature verification on Tor directory consensus documents, not decryption; the attack's threat model does not apply.