A minimal, single-threaded HTTP server written from scratch in C for Linux.
Built with raw POSIX sockets — no external libraries, no frameworks. Just gcc and the standard library. It serves static files from the public/ directory over HTTP/1.1.
- Serves static files from
public/ - GET requests only (405 Method Not Allowed for anything else)
- MIME type detection (currently HTML and plain text)
- Custom 404 error page
- Query string stripping (
/page?foo=bar→/page) - Request logging with client IP, port, status code, and bytes sent
- Socket reuse via
SO_REUSEADDRfor quick restarts - 400 Bad Request handling for malformed request lines
- Linux
- GCC (or any C99 compiler)
- Make (optional)
gcc -o http-server src/server.cOr use make:
make./http-serverThe server starts on port 8000 and serves files from public/:
[*] Server running on http://localhost:8000
[*] Press Ctrl+C to stopcurl http://localhost:8000/ # serves public/index.html
curl http://localhost:8000/anything-else # serves public/anything-else or 404Or open http://localhost:8000 in your browser.
├── http-server # compiled binary
├── public/ # static files served by the server
│ └── index.html
└── src/
└── server.c # the entire server implementation
socket()creates a TCP socket,setsockopt()enables address reuse, andbind()+listen()start the server on port 8000.- The main loop accepts one connection at a time and reads the request line.
check_method()rejects anything that isn't GET with a405.serve_file()maps the URL path to a file underpublic/and reads it into memory.send_response()writes the HTTP/1.1 response headers followed by the body.log_request()prints an access log line like:
[12:34:56] 127.0.0.1:52734 "GET / HTTP/1.1" 200 223
- Single-threaded: handles one request at a time
- No persistent connections (
Connection: closealways) - Limited MIME type coverage
- No HTTP parsing beyond the request line (no headers, no bodies)
- No directory traversal protection
- No config for the port or document root
MIT