# H2O HTTP Server Deployment & Usage Guide
## 1. Prerequisites
### System Requirements
- **OS**: Linux (kernel 3.10+), macOS (10.14+), or FreeBSD 10+
- **Architecture**: x86_64, ARM64, or ARMv7
- **Memory**: 512MB minimum (2GB+ recommended for production with HTTP/3)
### Build Dependencies
- **C Compiler**: GCC 4.9+ or Clang 3.4+
- **CMake**: 3.0 or higher
- **SSL Library** (one of):
- OpenSSL 1.0.2+ (1.1.1+ recommended for TLS 1.3)
- LibreSSL 2.4+
- BoringSSL (for QUIC/HTTP3 support)
- **zlib**: 1.2.3+ (for compression)
- **libuv**: 1.0+ (optional, for event loop integration)
- **pkg-config**: For dependency detection
### Optional Dependencies
- **Ruby**: 2.0+ (required for mruby scripting support)
- **Perl**: 5.10+ (required for running test suite)
- **libcap**: For binding privileged ports without root (Linux)
### Install Dependencies (Platform-Specific)
**Ubuntu/Debian:**
```bash
sudo apt-get update
sudo apt-get install build-essential cmake libssl-dev zlib1g-dev libuv1-dev pkg-config ruby perl
macOS:
xcode-select --install
brew install cmake openssl zlib libuv pkg-config ruby
CentOS/RHEL/Fedora:
sudo yum groupinstall "Development Tools"
sudo yum install cmake openssl-devel zlib-devel libuv-devel pkgconfig ruby perl
2. Installation
Clone Repository
git clone --depth 1 https://github.com/h2o/h2o.git
cd h2o
Configure Build
Create build directory and run CMake:
mkdir -p build
cd build
Standard Build (with OpenSSL):
cmake ..
Build with LibreSSL (bundled, recommended for HTTP/3):
cmake -DWITH_BUNDLED_SSL=on ..
Build with mruby support:
cmake -DWITH_MRUBY=on ..
Production Optimized Build:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
Compile and Install
make -j$(nproc)
sudo make install
Verify Installation
h2o --version
3. Configuration
H2O uses YAML configuration files. Create a configuration file at /etc/h2o/h2o.conf or ~/.h2o.conf.
Basic Configuration Example
Create /etc/h2o/h2o.conf:
# Listen on HTTP and HTTPS
listen:
port: 80
listen:
port: 443
ssl:
key-file: /etc/ssl/private/example.com.key
certificate-file: /etc/ssl/certs/example.com.crt
minimum-version: TLSv1.2
# HTTP/3 (QUIC) - requires OpenSSL 3.0+ or BoringSSL
listen:
port: 443
type: quic
ssl:
key-file: /etc/ssl/private/example.com.key
certificate-file: /etc/ssl/certs/example.com.crt
# Virtual Host Configuration
hosts:
"example.com:80":
paths:
/:
file.dir: /var/www/html
file.send-compressed: on
"example.com:443":
paths:
/:
file.dir: /var/www/html
file.send-compressed: on
file.mime.addtypes:
"application/javascript; charset=utf-8": .js
# Logging
access-log: /var/log/h2o/access.log
error-log: /var/log/h2o/error.log
pid-file: /var/run/h2o.pid
# Performance Tuning
http1-upgrade-to-http2: on
http2-reprioritize-blocking-assets: on # HTTP/2 push optimization
file.io_uring: on # Linux io_uring support (kernel 5.6+)
Environment Variables
H2O_ROOT: Installation prefix (default:/usr/local)H2O_CONF: Path to configuration file (default:/etc/h2o/h2o.conf)SSL_CERT_FILE/SSL_CERT_DIR: SSL certificate lookup paths
SSL Certificate Setup
For HTTP/3 (QUIC), certificates must include the TLS extension for QUIC:
# Generate with proper key usage for QUIC
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 \
-extensions v3_req -subj "/CN=example.com"
4. Build & Run
Development Mode
Build with debugging symbols and test suite:
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_MRUBY=on ..
make -j$(nproc)
make test
Running Locally
Start with custom configuration:
# Foreground mode (for testing)
sudo h2o -c /path/to/h2o.conf -m daemon
# Debug mode (verbose logging, foreground)
sudo h2o -c /path/to/h2o.conf --debug
Using as a Library
Link against libh2o in your C project:
#include <h2o.h>
// Initialize event loop
h2o_context_t ctx;
h2o_config_init(&conf);
h2o_context_init(&ctx, loop, &conf);
Compile with:
gcc -o myapp myapp.c `pkg-config --cflags --libs libh2o`
5. Deployment
Systemd Service Setup
Create /etc/systemd/system/h2o.service:
[Unit]
Description=H2O HTTP Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/h2o -c /etc/h2o/h2o.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/h2o /var/run
# Allow binding to privileged ports without root
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable h2o
sudo systemctl start h2o
Docker Deployment
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y build-essential cmake libssl-dev zlib1g-dev git
RUN git clone --depth 1 https://github.com/h2o/h2o.git /tmp/h2o && \
cd /tmp/h2o && mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DWITH_BUNDLED_SSL=on .. && \
make -j$(nproc) && make install
COPY h2o.conf /etc/h2o/h2o.conf
EXPOSE 80 443/udp 443/tcp
CMD ["h2o", "-c", "/etc/h2o/h2o.conf"]
Run with:
docker build -t h2o-server .
docker run -p 80:80 -p 443:443/tcp -p 443:443/udp h2o-server
HTTP/3 (QUIC) Production Setup
Ensure firewall allows UDP on port 443:
# iptables
sudo iptables -A INPUT -p udp --dport 443 -j ACCEPT
# nftables
sudo nft add rule inet filter input udp dport 443 accept
Reverse Proxy Configuration
H2O as reverse proxy to backend application:
hosts:
"api.example.com":
paths:
/:
proxy.reverse.url: http://127.0.0.1:8080/
proxy.websocket: on
proxy.preserve-x-forwarded-proto: on
proxy.timeout.io: 30000ms
6. Troubleshooting
Build Issues
CMake cannot find OpenSSL:
# Specify OpenSSL path explicitly
cmake -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl ..
Missing libuv (optional): If libuv is not found, H2O will use its internal event loop. To force libuv:
cmake -DWITH_LIBUV=on ..
Runtime Issues
Permission Denied on Ports < 1024:
H2O needs CAP_NET_BIND_SERVICE capability or run as root (not recommended for production):
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/h2o
HTTP/3 Connection Failures:
- Verify OpenSSL 3.0+ or BoringSSL is used (check
h2o --version) - Ensure UDP port 443 is open in firewall (not just TCP)
- Check SSL certificate includes proper ALPN for h3
High Memory Usage:
- Disable HTTP/2 push if not needed:
http2-push: off - Reduce
http2-max-concurrent-requests-per-connection(default: 100) - Enable
file.send-compressed: onto reduce memory pressure
Configuration Syntax Errors: Test configuration before reloading:
sudo h2o -c /etc/h2o/h2o.conf -t
Log Rotation: H2O supports USR1 signal for log reopening:
logrotate -f /etc/logrotate.d/h2o # Sends USR1 to h2o
Security Hardening
- Run with user
www-data:user: www-datain config - Enable strict transport security:
header.add: "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload" - Limit request body size:
limit-request-body: 102400000(100MB)
Performance Tuning
For high-throughput deployments:
# /etc/h2o/h2o.conf
max-connections: 10240
http2-max-concurrent-requests-per-connection: 200
file.io_uring: on # Linux 5.6+ only
file.send-compressed: gzip
gzip: on