- Add hostname-based request routing for multiple capsules per server - Parse virtual host configs from TOML sections ([hostname]) - Implement per-host certificate and content isolation - Add comprehensive virtual host testing and validation - Update docs and examples for multi-host deployments This enables Pollux to serve multiple Gemini domains from one instance, providing the foundation for multi-tenant Gemini hosting.
5.4 KiB
Pollux - A Simple Gemini Server
Pollux is a lightweight Gemini server for serving static files securely. It supports virtual hosting, allowing multiple Gemini capsules on a single server instance. Features include TLS encryption, hostname validation, directory serving, and comprehensive security protections.
Requirements
Rust 1.70+ and Cargo.
Building
Clone or download the source, then run:
cargo build --release
This produces the target/release/pollux binary.
Virtual Hosting
Pollux supports virtual hosting, allowing you to serve multiple Gemini capsules from a single server. Each hostname can have its own root directory, certificates, and configuration.
Configuration
Create a config file at /etc/pollux/config.toml or use --config to specify a path:
# Global settings (optional)
bind_host = "0.0.0.0"
port = 1965
log_level = "info"
max_concurrent_requests = 1000
# Virtual host configurations
["example.com"]
root = "/var/gemini/example.com"
cert = "/etc/ssl/example.com.crt"
key = "/etc/ssl/example.com.key"
["blog.example.com"]
root = "/var/gemini/blog"
cert = "/etc/ssl/blog.crt"
key = "/etc/ssl/blog.key"
["another-site.net"]
root = "/var/gemini/another"
cert = "/etc/ssl/another.crt"
key = "/etc/ssl/another.key"
port = 1966 # Optional per-host port override
Features
- Multiple hostnames on a single server instance
- Per-host TLS certificates for proper security isolation
- Automatic content isolation - each host serves only its own files
- Path security - directory traversal attacks are blocked
- Index file serving -
index.gmifiles are served automatically - Hostname validation - DNS-compliant hostname checking
Request Routing
gemini://example.com/→ serves/var/gemini/example.com/index.gmigemini://blog.example.com/article.gmi→ serves/var/gemini/blog/article.gmigemini://unknown.com/→ returns status 53 "Proxy request refused"
Single Host Mode (Legacy)
For backward compatibility, you can still use the old single-host format:
root = "/path/to/static/files"
cert = "/path/to/cert.pem"
key = "/path/to/key.pem"
hostname = "gemini.example.com"
bind_host = "0.0.0.0"
port = 1965
log_level = "info"
max_concurrent_requests = 1000
Development Setup
Quick Start with Self-Signed Certs
mkdir -p tmp
openssl req -x509 -newkey rsa:2048 \
-keyout tmp/key.pem \
-out tmp/cert.pem \
-days 365 \
-nodes \
-subj "/CN=localhost"
Update config.toml:
cert = "tmp/cert.pem"
key = "tmp/key.pem"
Run the server:
./pollux --config /path/to/config.toml
Access with a Gemini client like Lagrange at gemini://yourdomain.com/.
Development Notes
- These certificates are for local testing only
- Browsers will show security warnings with self-signed certs
- Certificates in the
dev/directory are gitignored for security
Options
--config(-C): Path to config file (default/etc/pollux/config.toml)--no-tls: Disable TLS for testing (uses raw TCP connections)--test-processing-delay(debug builds only): Add delay before processing requests (seconds) - for testing rate limiting
Security
Pollux is designed with security as a priority:
- Path traversal protection - requests like
../../../etc/passwdare blocked - TLS encryption - all connections are encrypted with valid certificates
- Content isolation - virtual hosts cannot access each other's files
- Request validation - malformed requests are rejected
- Rate limiting - configurable concurrent request limits prevent abuse
Best Practices
Virtual Hosting Setup
- Use separate TLS certificates for each hostname when possible
- Keep host root directories separate and properly permissioned
- Use DNS-compliant hostnames (no underscores, proper formatting)
- Monitor logs for unknown hostname attempts
Certificate Management
- Never commit certificate files to version control
- Use development certificates only for local testing
- Production certificates should be obtained via Let's Encrypt or your CA
- Rotate certificates regularly and restart the server
File Organization
- Create
index.gmifiles in directories for automatic serving - Use
.gmiextension for Gemini text files - Store certificates outside web-accessible directories
- Use proper file permissions (readable by server user only)
Limitations
- No dynamic content - Pollux serves only static files
- Single certificate per server - All hosts currently share the same TLS certificate (can be enhanced)
- No CGI support - No server-side processing or scripting
- Memory usage - All host configurations are loaded into memory
- No HTTP support - Gemini protocol only
Examples
The examples/ directory contains sample configuration files:
virtual-hosting.toml- Multi-host setup with different certificatessingle-host.toml- Legacy single-host configurationdevelopment.toml- Local development with self-signed certificates
Testing
Run cargo test for the full test suite, which includes comprehensive integration tests covering:
- Virtual hosting with multiple hostnames
- TLS certificate validation
- Path security and isolation
- Concurrent request handling
- Performance validation
Note: Some integration tests use Python 3 for Gemini protocol validation. If Python 3 is not available, certain tests will be skipped automatically.