Releases: csd113/RustHost
Releases · csd113/RustHost
v0.1.3.1 minor bugfix
[v0.1.3.1]
Changed
- Simplified the generated data directory so fresh installs now create
site/,settings.toml, and a singleruntime/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
[v0.1.3]
Simplified updates
- Added stronger static-file delivery polish with
Last-Modifiedrevalidation, 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-Encodingparsing 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.0or::. - 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-Locationheaders on clearnet HTTPS responses when the built-in Tor onion service is ready, so supporting browsers can surface the.onionversion 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_503into 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-Lengthvalues when known and-when a streamed/compressed size is not known ahead of time. - Made compression more production-friendly by honoring
Accept-Encodingquality 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
503pages, 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
[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 insettings.tomlto 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
[v0.1.1]
Added
- Depth-bounded
scan_siteBFS — 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 backups —
LogFile::rotatenow keeps up to five numbered backup files (.log.1–.log.5) instead of one, matching what operators expect from tools likelogrotate.
Changed
lib.rsvisibility 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.Ytags 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, andcargo-denyon Ubuntu, macOS, and Windows on every push and PR. Cargo.tomlprofile tuning —opt-level = 1for dev dependencies speeds up debug builds; the release profile useslto = true,strip = true, andcodegen-units = 1for a smaller, faster binary.
HTTP Server
- Keep-alive via
hyper1.x — migrated from a hand-rolled single-shot HTTP/1.1 parser tohyper. Eliminates the 30–45 second Tor page-load penalty that was caused byConnection: closeon 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. Returns304 Not ModifiedwhenIf-None-Matchmatches, saving a round-trip.- Range requests — supports
bytes=N-M,bytes=N-, andbytes=-Nsuffix forms. Returns206 Partial Contentor416 Range Not Satisfiableas appropriate. Enables audio and video seeking. - Per-IP rate limiting —
DashMap-backed lock-free CAS loop. Connections beyondmax_connections_per_ipare dropped at accept time with a TCP RST. - Smart
Cache-Control— HTML responses getno-store; content-hashed assets (8–16 hex characters in the filename stem) getmax-age=31536000, immutable; everything else getsno-cache. - Security headers on every response —
X-Content-Type-Options: nosniff,X-Frame-Options: SAMEORIGIN,Referrer-Policy: no-referrer, andPermissions-Policy: camera=(), microphone=(), geolocation=(). HTML responses additionally include a configurableContent-Security-Policy. --serve <dir>one-shot mode — serve a directory directly without asettings.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.logwith owner-only0600permissions.
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_oniontest — 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 insettings.toml, checked before filesystem resolution. Supports 301 and 302. - Custom error pages —
site.error_404andsite.error_503config keys resolve to HTML files served with the correct status codes. --configand--data-dirCLI flags — override the default config and data directory paths. Enables multi-instance deployments and systemd unit files with explicit paths.--versionand--helpCLI flags.#[serde(deny_unknown_fields)]on all config structs — a misspelled key likebund = "127.0.0.1"causes a clear startup error instead of silently using the default.- Typed config fields —
bindisstd::net::IpAddr;log levelis aLogLevelenum. Invalid values are caught at deserialisation time, not after the server starts.
Features
- SPA fallback routing — unknown paths fall back to
index.htmlwhensite.spa_routing = true, enabling React, Vue, and Svelte client-side routing. canonical_roothot reload — the[R]keypress pushes a new canonicalised root to the accept loop over awatchchannel without restarting the server.- Dependency log filtering — Arti and Tokio internals at
Infoand below are suppressed by default, keeping the log focused on application events. Configurable viafilter_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-encodingcrate — replaced the hand-rolledpercent_decodefunction with the audited upstream crate. Added a null-byte guard specific to filesystem path use.scan_sitepartial failure — unreadable subdirectories are skipped with a warning instead of aborting the entire scan.fstatbatching —LogFile::write_linecallsfstatevery 100 writes (instead of on every record) to reduce syscall overhead on active servers.
Testing & CI
- Unit tests for all security-critical functions —
percent_decode,resolve_path,validate,strip_timestamp, andhsid_to_onion_addressall have#[cfg(test)]coverage. - Integration tests (
tests/http_integration.rs) — covers all HTTP core flows using rawTcpStream: 200, HEAD, 304, 403, 404, 400, range requests, and oversized headers.
Fixed
Critical (Phase 1)
- Config path traversal —
validate()now rejects anysite.directoryorlogging.filevalue that is an absolute path, contains.., or contains a platform path separator. Previously,directory = "../../etc"would cause the server to serve the entire/etctree. - 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::oneshotchannel. 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 withECONNREFUSEDto port 0 while the dashboard showed a healthy green status. - XSS in directory listings —
build_directory_listing()now HTML-entity-escapes all filenames before interpolating them into link text, and percent-encodes filenames inhrefattributes. Previously, a file named"><script>alert(1)</script>produced an executable XSS payload in any directory listing page. - HEAD requests sent a response body —
HEADrequests now send the correct headers (includingContent-Lengthreflecting the full body size) but no body, as required by RFC 7231 §4.3.2. Previously, the full file was sent. - Slow-loris DoS —
read_request()is now wrapped in a 30-second timeout. Connections that don't deliver a complete request header in time receive a408 Request Timeout. Configurable viarequest_timeout_secs. - Unbounded connection spawning — both the HTTP accept loop and the Tor stream loop now use a
tokio::sync::Semaphoreto 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 aVec<u8>) withtokio::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_timestamppanic 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 usessplitn(3, ']'), which is both panic-safe and handles Unicode correctly.TorStatusnot updated when onion service terminates — when the onion service stream ends unexpectedly, the status is now set toTorStatus::Failed("stream ended")and the.onionaddress 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_hookis registered at startup to callconsole::cleanup()(which issuesLeaveAlternateScreen,cursor::Show, anddisable_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-byte —
read_request()previously issued up to 8,192 individualreadsyscalls per request. The stream is now wrapped intokio::io::BufReaderand headers are read line-by-line. Also correctly handles\r\n\r\nsplit across multiple TCP segments. scan_siteonly 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 arealpath()syscall on every single request.open_browserduplicated — the function existed in two separate source fil...
v0.1.0
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
GETandHEADrequests; all other methods return400 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 withHTTP 403 Forbidden. - Request header size cap of 8 KiB; oversized requests are rejected immediately.
Content-Type,Content-Length, andConnection: closeheaders 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.htmlwritten 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 to0.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.
- Text:
Tor Onion Service (Arti — in-process)
- Embedded Tor support via Arti, the official Rust Tor implementation — no external
torbinary ortorrcfile 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
.onionaddress across restarts: the service keypair is persisted torusthost-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
.onionspec (SHA3-256 checksum + base32) — no dependency on Arti'sDisplayRedactedformatting. - Each inbound Tor connection is bridged to the local HTTP server via
tokio::io::copy_bidirectionalin its own Tokio task. - Tor subsystem can be disabled entirely with
[tor] enabled = false; the dashboard onion section reflects this immediately. - Graceful shutdown: the
TorClientis dropped naturally when the Tokio runtime exits, closing all circuits cleanly — no explicit kill step needed. .onionaddress 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.onionURL (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:SStimestamp display, toggled viashow_timestampsin config. - Customisable instance name shown in the dashboard header (max 32 characters).
- Headless / non-interactive mode: set
[console] interactive = falsefor systemd or piped deployments; the server prints a plainhttp://…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::Logimplementation; all modules use the standardlogfacade 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 tologs/rusthost.log. - Configurable log level:
trace,debug,info,warn,error. - Timestamped entries in
[LEVEL] [HH:MM:SS] messageformat. - Logging can be disabled entirely (
[logging] enabled = false) for minimal-overhead deployments.
Lifecycle and Startup
- First-run detection: if
rusthost-data/settings.tomldoes not exist, RustHost initialises the data directory (site/,logs/), writes defaults, drops a placeholderindex.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 orSIGINT/SIGTERM(viactrlc); 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); usesopen(macOS),explorer(Windows), orxdg-open(Linux/other). - All subsystems share state through an
Arc<RwLock<AppState>>; hot-path request and error counters use separateArc<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-denyconfiguration (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: thersacrate is a transitive dependency ofarti-clientused exclusively for RSA signature verification on Tor directory consensus documents, not decryption; the attack's threat model does not apply.
First functional Release
HTTP Server
- Custom HTTP/1.1 static file server built directly on
tokio::net::TcpListener— no third-party HTTP framework dependency. - Serves
GETandHEADrequests; all other methods return400 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 withHTTP 403 Forbidden. - Request header size cap of 8 KiB; oversized requests are rejected immediately.
Content-Type,Content-Length, andConnection: closeheaders 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.htmlwritten 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 to0.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.
- Text:
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.onionURL (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:SStimestamp display, toggled viashow_timestampsin config. - Customisable instance name shown in the dashboard header (max 32 characters).
- Headless / non-interactive mode: set
[console] interactive = falsefor systemd or piped deployments; the server prints a plainhttp://…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::Logimplementation; all modules use the standardlogfacade 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 tologs/rusthost.log. - Configurable log level:
trace,debug,info,warn,error. - Timestamped entries in
[LEVEL] [HH:MM:SS] messageformat. - Logging can be disabled entirely (
[logging] enabled = false) for minimal-overhead deployments.
Lifecycle and Startup
- First-run detection: if
rusthost-data/settings.tomldoes not exist, RustHost initialises the data directory (site/,logs/), writes defaults, drops a placeholderindex.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 orSIGINT/SIGTERM(viactrlc); 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); usesopen(macOS),explorer(Windows), orxdg-open(Linux/other). - All subsystems share state through an
Arc<RwLock<AppState>>; hot-path request and error counters use separateArc<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-denyconfiguration (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: thersacrate is a transitive dependency ofarti-clientused exclusively for RSA signature verification on Tor directory consensus documents, not decryption; the attack's threat model does not apply.