Skip to content

Latest commit

 

History

History
196 lines (144 loc) · 7.17 KB

File metadata and controls

196 lines (144 loc) · 7.17 KB

Operations

The daemon defaults to the foreground. On Unix you can pass -d / daemonize = true for a double-fork, or prefer systemd/launchd/Docker as the supervisor. After bind, user / group drop privileges (Unix). A pid_file is written after a successful bind.

Start and stop

./build/simple-httpd --config /etc/simple-httpd/simple-httpd.conf
# optional: --daemonize --user httpd --group httpd --pid-file /run/simple-httpd.pid

SIGINT and SIGTERM stop the accept loop and wait briefly for in-flight connections. SIGPIPE is ignored on Unix.

Exit codes: 0 clean stop after a successful listen, 1 listen/runtime failure, 2 usage or config/validation error.

Health

curl -sS http://127.0.0.1:8080/healthz
# ok

Default path is /healthz (health_path). Response is 200 and text/plain body ok\n. Empty health_path disables it. The endpoint skips HTTP Basic and rate limits.

A process that can accept TCP and return ok is up. It does not check disk, TLS expiry, or upstreams.

Metrics

curl -sS http://127.0.0.1:8080/metrics

Prometheus text (metrics_path, default /metrics). Counters and gauges:

Metric Meaning
simple_httpd_requests_total{status="…"} Responses by HTTP status
simple_httpd_requests_sum All recorded requests
simple_httpd_bytes_sent_total Response body bytes (not headers)
simple_httpd_request_duration_milliseconds_sum / _count Handling time
simple_httpd_connections_accepted_total Accepted clients
simple_httpd_connections_rejected_total Rejected at max_connections
simple_httpd_connections_active In-flight connections (gauge)
simple_httpd_queue_depth Accepted fds waiting for a worker (gauge)
simple_httpd_cache_hits_total / cache_misses_total File-body cache

Also skipped by auth and the rate limiter. Scrape from a private network.

Example Prometheus scrape:

scrape_configs:
  - job_name: simple-httpd
    static_configs:
      - targets: ["127.0.0.1:8080"]
    metrics_path: /metrics

SNMP is not implemented. Use Prometheus (or scrape /status).

Status (remote inspection)

curl -sS http://127.0.0.1:8080/status

JSON snapshot (status_path, default /status): version, uptime start, request/connection/cache counters, worker and max connection settings. Read-only. Skips auth and rate limits like health/metrics. Empty status_path disables it.

Admin API

When admin_path is set (and auth_basic_file is configured):

curl -u alice:secret http://127.0.0.1:8080/admin/config
curl -u alice:secret -X POST http://127.0.0.1:8080/admin/reload

/admin/reload requests the same soft reload as SIGHUP. Bind to a private interface or put the admin path behind a network ACL; Basic auth is not enough alone on the public internet.

Logs

Stream Default Content
error_log stderr (-) Start/stop, bind errors, TLS handshake failures, reload
access_log stdout (-) Combined-style lines, GMT date
security_log stderr (with errors) ip_denied, auth_failed, rate/connection limits, admin actions
127.0.0.1 - - [Sun, 30 Aug 2026 12:00:00 GMT] "GET / HTTP/1.1" 200 1234 "-" "curl/8.0"

log_level is debug | info | warn | error. Put files under /var/log/simple-httpd/ in production and rotate them (see deployment/logrotate.d/).

Reloading

SIGHUP reloads the config file that was used at start (--config or the discovered path). Soft keys apply live: document roots / vhosts, headers, rate limits, IP allow/deny, connection limits, rewrites, proxy/CGI/SSI/mime, compression, file-cache knobs, log paths/level (including security_log), health/metrics/status/admin paths, tcp_nodelay / sendfile, auth file.

These still need a restart: listen_address, listen_port, ssl_cert / ssl_key / tls_min_version, worker_threads, user / group / daemonize / pid_file.

kill -HUP $(pidof simple-httpd)
# or: systemctl reload simple-httpd   # if the unit sends SIGHUP

If no config file was loaded (CLI-only defaults), SIGHUP is ignored with a warning.

Capacity and I/O

Accept hands sockets to a worker_threads pool, gated by max_connections. At capacity, new clients are rejected (and counted) instead of blocking accept. tcp_nodelay (default on) reduces latency for small responses. sendfile (default on) uses kernel sendfile for cleartext static bodies on Linux/macOS; TLS and Windows fall back to a thread-local userspace buffer.

High availability

The process is stateless. HA is multi-instance + an external load balancer:

  1. Run N copies of simple-httpd (same or synced document root).
  2. Put a load balancer / reverse proxy in front for TLS termination or distribution.
  3. Point health checks at /healthz.
  4. Proxy backend failover inside one process is round-robin + connect retry (proxy key from 0.6.0).

There is no clustering protocol, shared memory, or data replication inside the daemon. Replicate files with rsync/nfs/object storage as you prefer.

Kubernetes sketch

apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple-httpd
spec:
  replicas: 3
  selector:
    matchLabels: { app: simple-httpd }
  template:
    metadata:
      labels: { app: simple-httpd }
    spec:
      containers:
        - name: httpd
          image: your.registry/simple-httpd:0.8.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet: { path: /healthz, port: 8080 }
          livenessProbe:
            httpGet: { path: /healthz, port: 8080 }
          volumeMounts:
            - name: www
              mountPath: /var/www/html
            - name: conf
              mountPath: /etc/simple-httpd
      volumes:
        - name: www
          persistentVolumeClaim: { claimName: www }
        - name: conf
          configMap: { name: simple-httpd-conf }
---
apiVersion: v1
kind: Service
metadata:
  name: simple-httpd
spec:
  selector: { app: simple-httpd }
  ports:
    - port: 80
      targetPort: 8080

Scale with the Deployment replica count. Terminate TLS at the Ingress or keep PEM mounts and ssl_cert / ssl_key in the pod.

Backup and disaster recovery

Back up:

  • The config file and htpasswd
  • TLS material
  • The document root (the daemon does not mutate it)

Restore: install the binary, restore those three trees, start the process. Logs are expendable if you ship them elsewhere. There is no built-in backup command.

systemd / launchd / Windows / Docker

Templates live in deployment/. They are examples: edit User, ExecStart, and config paths.

Linux sketch:

[Service]
ExecStart=/usr/local/bin/simple-httpd --config /etc/simple-httpd/simple-httpd.conf
Restart=on-failure
KillSignal=SIGTERM
# Optional: ExecReload=/bin/kill -HUP $MAINPID

The process does not notify systemd (Type=notify) and does not drop to a dedicated user by itself — set User= in the unit after the document root and logs are writable by that user. Binding port 80/443 as non-root needs CAP_NET_BIND_SERVICE or a proxy in front.

Docker: deployment/examples/docker/README.md.