A single-threaded reverse proxy written in C, based on the reactor pattern using Linux's Epoll mechanism. Full asynchronous state handling, supports HTTPS and canonical name redirection for one host.
So my last project was a web server, also made in C. After making it capable of hosting a real website I rented an AWS instance and tried to host my own website with it.
Long story short, just using running my server on port 80 and 443 was not enough.
Google was refusing to index the HTTPS version of my website, even after telling it explicitly with meta tags.
So I had to resort an Nginx proxy that redirected all traffic to the HTTPS version of the site.
This is where the idea for a reverse proxy originated, which was in some cases more complex and simpler than server-c.
- Uses a single
epoll()instance to monitor all the file descriptors in a true async manner. - Only supports a single upstream server.
- A single upstream removes the need for calling the blocking
getaddrinfo()function, after accepting. - Upstream info is loaded even before calling the first
accept(). - Canonical host for requests and upstream can be different.
- Redirects with 301 code, incase canonical host does not match with request header.
- Regex is used to validate the upstream host and host header of every request.
- TLS is used to support HTTPS, done using
openssl. - Timeouts are used for every individual I/O state.
- A full connection timeout is also used for every connection regardless which state they are in.
- Custom Error Page is served in case of any error, which changes dynamically based on the response status code.
- Clean Shutdown is done by handling interrupt and kill signals.
THIS PROXY SERVER ONLY SUPPORTS LINUX SYSTEMS.
Install Dependencies
The following dependencies are required to build and run the program on Linux:
gcc: C Compilermake: Project buildopenssl: TLS handling & HTTPS support
If using a package manager, please check to see the exact names of these programs for your distro.
Download the source
git clone https://github.com/navrajkalsi/proxy-c
cd proxy-cBuild the project
# Building
make
# Installing the binary
make install
# Cleaning build objects
make clean
# Uninstall
make uninstall| Variable | Default | Description |
|---|---|---|
| DEFAULT_PORT | "1419" | Listening port for client side connections. |
| DEFAULT_CANONCIAL_HOST | "https://example.com" | Canonical Host to match the value of Host header against. |
| DEFAULT_UPSTREAM | DEFAULT_CANONICAL_HOST | URL of the server to contact for response, if request is deemed valid. |
| DOMAIN_CERT | "/etc/ssl/domain/domain.cert" | Path to domain certificate for HTTPS. |
| PRIVATE_KEY | "/etc/ssl/domain/private.key" | Path to private key for HTTPS. |
DOMAIN_CERT & PRIVATE_KEY CAN ONLY BE CHANGED DURING COMPILATION, i.e., during make, and not during runtime with flags.
If proxy-c command is not found after installation, the directory in which the binary got installed is not on the PATH.
ADD THE MAKE INSTALLATION DIRECTORY TO THE PATH AND TRY AGAIN.
The following flags can be used to alter the behaviour of the program:
| Flag | Flag Description | Required Argument | Default |
|---|---|---|---|
| -a | Accept Incoming Connections from all IPs. | Localhost only | |
| -c | Canonical Host to redirect to. | Host origin string | DEFAULT_CANONICAL_HOST |
| -h | Print usage on command line. | ||
| -p | Port to listen on. | Port number | DEFAULT_PORT |
| -s | Use HTTPS for client side. | HTTP only | |
| -S | Use HTTPS for server side. | HTTP only | |
| -u | Server URL to contact for response. | Upstream origin string | DEFAULT_UPSTREAM |
| -v | Print version number. | ||
| -w | Print all warnings as errors. | Warnings are not printed |
proxy-cBy default:
- Loads address information for DEFAULT_UPSTREAM.
- Starts listening for clients on DEFAULT_PORT.
- Listens to only localhost requests.
- Uses HTTP only for client side operations.
- Matches the host header of each request against DEFAULT_CANONICAL_HOST.
- Uses HTTP only for server side operations.
proxy-c -a -c localhost:8080 -p 8080 -S -u https://example.com- Loads address information for https://example.com.
- Starts listening for clients on port 8080.
- Listens to request from all IPs.
- Uses HTTP only for client side operations.
- Matches the host header of each request against localhost:8080.
- Uses HTTPS only for server side operations.
