smolserve
A lightweight, multi-protocol server serving Gemini, Gopher, and Finger protocols for local testing, development, and documentation.
Features
- Gemini Server: Serves Gemtext documents (
.gmi,.gemini) and static files over TLS. Auto-generates Gemtext directory listings when index files are absent and auto-generates self-signed TLS certificates for local development if none are provided. - Gopher Server: Serves
gophermapmenus, directory listings, text files (with dot-stuffing), and binary files. - Finger Server: Responds to Finger queries (RFC 1288) with the contents of a plan file.
- Exec Process Wrapper: Run
smolservein the background for the duration of an arbitrary command (such asmkdocs build,pytest, ormkdocs serve). - Flexible Configuration: Fully configurable via command-line arguments or a TOML configuration file.
- AsyncIO Powered: Lightweight, single-process asynchronous server implementation.
Installing
smolserve is a Python application and is distributed via PyPI. It can be installed using tools such as pipx:
pipx install smolserve
or uv:
uv tool install smolserve
If you have uv installed, you can also run smolserve directly using uvx:
uvx smolserve
Development Installation
If you are developing or contributing to smolserve, clone the repository and sync dependencies using uv:
git clone https://github.com/davep/smolserve.git
cd smolserve
uv sync
Quick Start
Run smolserve with defaults (binds to 127.0.0.1, Gemini on port 1965, Gopher on port 7070, Finger on port 7979):
smolserve
or with uv:
uv run smolserve
If target directories or plan files do not exist, smolserve automatically creates sample content directories (public_gemini/, public_gopher/, plan.txt) and self-signed TLS development certificates.
Exec / Command Wrapper Mode
smolserve includes a built-in process wrapper mode (exec), allowing you to temporarily run the Gemini, Gopher, and Finger servers for the lifespan of an arbitrary command (such as static documentation site generation, live dev servers, or automated test runs).
How It Works
- Server Initialization:
smolservestarts and binds all configured protocol servers. - Process Execution: Once servers are running,
smolservelaunches the specified child command. - Signal Forwarding: Signals such as
SIGINT(Ctrl+C) andSIGTERMare trapped and forwarded directly to the child process. - Automatic Cleanup & Exit Propagation: When the child process completes,
smolservegracefully stops all background servers and exits with the exact exit code returned by the child process (or exit code130on cancellation).
Command Syntax
You can specify the subcommand using exec --, exec, or --exec:
# Recommended POSIX standard syntax (using '--' separator)
smolserve exec -- <command> [args...]
# Direct syntax without '--'
smolserve exec <command> [args...]
# Flag syntax
smolserve --exec <command> [args...]
Passing Server Options
smolserve flags and configuration options should be placed before the exec subcommand:
# Custom configuration file with exec
smolserve -c smolserve.toml exec -- mkdocs build
# Custom host and port flags with exec
smolserve --host 0.0.0.0 --gemini-port 1966 exec -- pytest
Use Cases & Examples
-
Build Pipelines: Ensure background protocol servers are available while building documentation or static sites.
smolserve exec -- mkdocs build -
Live Development Servers: Run interactive documentation servers with live reload while
smolserveserves required content.smolserve exec -- mkdocs serve --livereload -
Integration Testing: Automatically spin up servers, run integration test suites or test clients, and shut down cleanly.
smolserve exec -- pytest tests/ -
Makefile Integration:
.PHONY: docs docs: smolserve exec -- $(mkdocs) build .PHONY: rtfm rtfm: smolserve exec -- $(mkdocs) serve --livereload
Command Line Options
Run smolserve --help to display all available options:
smolserve --help
Available flags:
-c,--config: Path to TOML configuration file.--generate-config: Print sample TOML configuration to stdout and exit.-v,--verbose: Enable verbose logging output.-q,--quiet: Silence informational output (errors only).--host: Host address to bind servers to (e.g.127.0.0.1or0.0.0.0).--gemini-port: Gemini server port.--gemini-root: Directory containing Gemtext/static content.--gemini-cert: Path to custom TLS PEM certificate.--gemini-key: Path to custom TLS PEM private key.--no-gemini: Disable Gemini server.--gopher-port: Gopher server port.--gopher-root: Directory containing Gopher content / gophermaps.--no-gopher: Disable Gopher server.--finger-port: Finger server port.--finger-plan: Path to Finger plan file.--no-finger: Disable Finger server.
TOML Configuration
You can pass a TOML configuration file via -c / --config:
[general]
host = "127.0.0.1"
[gemini]
enabled = true
port = 1965
root = "./public_gemini"
# cert_file = "./cert.pem"
# key_file = "./key.pem"
[gopher]
enabled = true
port = 7070
root = "./public_gopher"
[finger]
enabled = true
port = 7979
plan_file = "./plan.txt"
To generate a sample configuration file:
smolserve --generate-config > smolserve.toml
Development and Testing
Run the test suite using pytest or make:
uv run pytest
or run the full suite of linting, type checks, and tests:
make checkall