At this point it should just work, and if it doesn't work on Linux it is a bug; however, little benchmarking has been done and only the most cursory security analysis.
The easyp pea says: My favourite type of pea is easyp easy HTT Ps
Note: This repository is a wrapper around the core easyp components. For easier access to binaries and source code bundle, visit the official website at www.easyp.net. Alternatively download this and the four other core components from GitHub:
- ACME Integration: Built-in Let's Encrypt certificate management (no certbot required!)
- Automatic Domain Discovery: Scans
/etc/letsencrypt/live/for domains or uses ACME - Dual Protocol Support: Serves both HTTP (port 80) and HTTPS (port 443)
- Static File Serving: Serves files from
/var/www/{domain}/for each domain- Falls back to /var/www/html
- Let's Encrypt Integration: Uses fullchain.pem and privkey.pem certificates
- HTTP-01 Challenge Support: Handles ACME domain validation challenges
- Automatic Certificate Renewal: Background task for certificate management
- Extension System: Modular architecture with multiple extension types
- Comment System: Example extensions implementing commenting with moderation capabilities
- Admin Panels: Secure admin interfaces for content management
- Privilege Dropping: Drops to
www-dataafter initialization for security - CGI-like Support: Executes statically compile and linked CGI-like scripts for dynamic content
- MIME Type Support: Proper content types for common file formats
- Comprehensive Logging: Detailed request and error logging
- Let's Encrypt certificates in
/etc/letsencrypt/live/(or use auto-ACME mode) - Document roots in
/var/www/{domain}/or common directory/var/www/html - Root privileges to bind to port 80 and 443 (you can use other ports but auto-ACME require port 80)
easyp features a powerful modular extension system with four types of extensions:
.expand.rs- Content expansion extensions that modify HTML content.bin.rs- CGI-bin like extensions for dynamic content generation.root.rs- Root-level extensions that run before privilege dropping.admin.rs- Admin panel extensions for content management
Drop these files into extensions/ at compile time to have you extensions linked into your single file webserver.
comment.expand.rs: Adds comment forms and displays live commentscomment.bin.rs: Handles comment submission via CGI-like APIcomment.root.rs: Sets up comment directories and permissionscomment.admin.rs: Provides comment moderation interface
- Converts
#EXTEND:math(op,i,j)blocks to rendered math, where op can be e.g. "add"
- Demonstrates basic extension functionality
- Adds example content to pages
Extensions are automatically discovered by the build system. To create a new extension:
- Add a
.rsfile to theextensions/directory with the appropriate suffix - Implement the required trait methods
- The build system will automatically compile and register your extension
// extensions/my_extension.expand.rs
use std::collections::HashMap;
pub fn extend(url: &str, args: &str) -> String {
// Your extension logic here
format!("<div>Custom content for {}</div>", url)
}- Clone or download this project
- Build the server:
cargo build --release
- Deploy using the included script:
./deploy.sh user@your-server.com
-
Create document roots for your domains:
sudo mkdir -p /var/www/example.com echo "<h1>Hello from example.com!</h1>" | sudo tee /var/www/example.com/index.html
-
Run the server with ACME certificate management:
# Email defaults to webmaster@$HOSTNAME (if hostname contains a dot) or webmaster@domain (shortest domain from reverse DNS) or webmaster@localhost # Staging defaults to false (production Let's Encrypt) # Run with domain list sudo ./target/release/easyp example.com another-domain.com
-
For testing, use the staging environment:
export ACME_STAGING="true" sudo ./target/release/easyp example.com another-domain.com
-
Customize the email address:
export ACME_EMAIL="admin@example.com" sudo ./target/release/easyp example.com another-domain.com
-
Ensure your Let's Encrypt certificates are in place:
/etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/example.com/privkey.pem -
Create document roots for your domains:
sudo mkdir -p /var/www/example.com echo "<h1>Hello from example.com!</h1>" | sudo tee /var/www/example.com/index.html
-
Run the server (requires root for port 443):
sudo ./target/release/easyp
Or use the systemd service (if deployed):
sudo systemctl start easyp sudo systemctl enable easyp # Start on boot
-
Visit your domains:
- http://example.com (HTTP on port 80)
- https://example.com (HTTPS on port 443)
- http://another-domain.com
- https://another-domain.com
easyp includes a complete commenting system with moderation capabilities:
- Comment Forms: Automatically replaces '#EXTEND:comment()' in served html files
- Live Comments: Accepted comments appear immediately on the page
- Moderation: Admin interface for approving/rejecting comments
- Security: Comments are sanitized and validated
- Storage: Comments stored in
/var/spool/easyp/comments/
- Access via secret URL:
https://your-domain.com/comment_{admin_key} - Admin key is generated automatically on first run and stored in /var/spool/easyp.admin
- Batch moderation with checkboxes
easyp provides secure admin panels for content management:
- Keys are generated dynamically on first run
- Stored in
/var/spool/easyp/admin - Keys are cached in memory for security
- Each extension gets its own unique admin key
- go to https://example.com/KEY to administer system.
- Admin keys are long, random alphanumeric strings
- Admin panels only accessible with correct keys
- Privilege dropping ensures admin operations run as
www-data
The server supports two modes of operation:
ACME Mode (Default when domains are specified):
- Automatically requests Let's Encrypt certificates for specified domains
- Handles HTTP-01 challenges for domain validation
- Stores certificates in
/var/lib/easyp/certs/ - Automatically renews certificates before expiration
- Uses staging environment by default (set
ACME_STAGING=falsefor production)
Legacy Mode (Fallback):
- Scans
/etc/letsencrypt/live/for existing domains - Uses pre-existing certificates from certbot or other tools
- No automatic certificate management
ACME_EMAIL: Email address for Let's Encrypt registration (defaults towebmaster@$HOSTNAMEif hostname contains a dot, otherwisewebmaster@domainwhere domain is the shortest domain found by reverse DNS, orwebmaster@localhostas final fallback)ACME_STAGING: Set to "true" for staging Let's Encrypt environment (defaults to "false" for production)ENABLE_DNS_DISCOVERY: Enable automatic hostname discovery via DNS (defaults to "true")
The server automatically:
- Serves files from
/var/www/{domain}/for each domain - Uses the first domain found as the default domain
- Maps file extensions to appropriate MIME types
- Handles ACME HTTP-01 challenges at
/.well-known/acme-challenge/
- HTML:
.html - CSS:
.css - JavaScript:
.js - JSON:
.json - WASM:
.wasm - Images:
.png,.jpg,.jpeg,.gif,.svg,.ico - Text:
.txt - Default:
application/octet-stream
- This is a basic implementation for development/testing
- In production, consider additional security measures
- Ensure proper file permissions on document roots
- Consider rate limiting and access controls
The project includes test scripts for different platforms:
setup_example.sh: Sets up example domains and content (Linux/macOS)test_server.sh: Creates test environment with self-signed certificates (Linux/macOS)test_server.bat: Windows batch script for test environment setuptest_server.ps1: PowerShell script for test environment setup (Not sure that this would work on Windows though)
# Run the bash test script
chmod +x test_server.sh
./test_server.sh
#Test on a remote server
./remote_tesh.sh example.com
# Build and run the server
cargo build --release
sudo ./target/release/easypUse the included deploy.sh script for easy deployment:
./deploy.sh user@your-server.comThis script will:
- Build the release binary
- Copy it to the target server
- Install it to
/usr/local/bin/easyp - Create and enable a systemd service
- Set up proper security configurations
-
Build the binary:
cargo build --release
-
Copy to target server:
scp target/release/easyp user@server:/usr/local/bin/
-
Set permissions:
ssh user@server "sudo chmod +x /usr/local/bin/easyp" -
Create systemd service (see
deploy.shfor the service file)
The easyp service includes:
- Automatic restart on failure
- Security hardening (NoNewPrivileges, PrivateTmp, etc.)
- Proper file system access controls
- Journal logging
Service management:
sudo systemctl start easyp # Start service
sudo systemctl stop easyp # Stop service
sudo systemctl restart easyp # Restart service
sudo systemctl status easyp # Check status
sudo journalctl -u easyp -f # View logsThe project includes optimized build profiles:
- Debug: Fast compilation with debug info
- "Release": Maximum optimization
- LTO: Maximum optimization with LTO, size optimization, and stripped symbols
- Debug build: ~62 MB
- "Release" build: ~4.9 MB
- LTO build: ~2.8MB (used for release)
The LTO profile uses:
lto = "fat": Full Link Time Optimizationcodegen-units = 1: Single codegen unit for better optimizationopt-level = "z": Optimize for sizestrip = true: Remove debug symbols
easyp/
├── src/ # Source code
│ ├── main.rs # Main server implementation
│ └── cgi_env.rs # CGI environment utilities
├── extensions/ # Extension modules
│ ├── comment.*.rs # Comment system extensions
│ ├── math.expand.rs # Math rendering extension
│ └── example.expand.rs # Example extension
├── target/ # Build output
│ └── release/easyp # Compiled binary
├── deploy.sh # Deployment script
├── Cargo.toml # Rust project configuration
└── README.md # This file
/var/www/{domain}/ # Document roots for each domain
/etc/letsencrypt/live/ # Let's Encrypt certificates
/var/spool/easyp/ # easyp data directory
├── admin # Admin keys file
└── comments/ # Comment system storage
├── in # Incoming comments
├── processing # Comments awaiting moderation
├── accept # Accepted comments
├── reject # Rejected comments
└── live/ # Live comments by URL hash
-
Permission Denied on Port 443
- Ensure running as root or with sudo
- Check if another service is using port 443
-
Certificate Not Found
- For ACME mode: Ensure domains are specified as command line arguments
- For legacy mode: Verify certificates exist in
/etc/letsencrypt/live/{domain}/ - Check file permissions (should be readable by root)
- Ensure ACME_EMAIL environment variable is set for ACME mode
-
Admin Panel Not Accessible
- Check admin key in
/var/spool/easyp/admin- or run
easyp --admin-urlsas root
- or run
- Verify URL format:
https://domain.com/extension_{key}
- Check admin key in
-
Comments Not Appearing
- Check comment moderation in admin panel (at
easyp --admin-urls) - Verify
/var/spool/easyp/comments/directory permissions - Ensure
www-datauser has write access
- Check comment moderation in admin panel (at
-
Extensions Not Loading
- Check build output for compilation errors
- Verify extension files are in
extensions/directory - Ensure proper trait implementations
-
ACME Certificate Issues
- Verify domain is accessible from the internet
- Check that port 80 is open for HTTP-01 challenges
- Ensure ACME_EMAIL is set correctly
- Use staging environment first (
ACME_STAGING=true) - Check certificate directory permissions:
/var/lib/easyp/certs/
- Check server logs:
sudo journalctl -u easyp -f - Verify file permissions:
ls -la /var/spool/easyp/comments/ - Test admin access:
curl -k https://domain.com/comment_{key} - Check certificate validity:
openssl x509 -in /etc/letsencrypt/live/domain/fullchain.pem -text -noout
The easyp webserver is distributed under the GPLv3.
The library this was forked from was licensed under
- Apache License version 2.0.
- MIT license.
- ISC license.
The GPLv3 is liberal enough for what most normal people would want to do with a webserver, including most commericial purposes. If you want to distribute under a license other than GPLv3 feel free to drop me a line. Alternatively just use the permissively licensed upstream library at https://github.com/rustls/rustls
- Security Audit
- Supply security updates via some secure channel.
- Investigate feasibility of automatic free subdomain instead of self-signed cert fallback.
- Fix warnings (Unused code: use or remove)
- Add more configuration options (e.g. aws-lc-ls without RSA)
- Sync with upstream.
- Use Async/Await properly, don't fallback on polling.
- Check that configuration options really work. I have mostly just tested auto-ACME mode without special configuration.
- Detect file encoding (UTF8 vs UTF16 etc.) support unknown file types?
