Corsproxy is a small, simple, and efficient Linux HTTP proxy service which receives a HTTP request on a port and forwards that request to a pre-configured target HTTP or HTTPS server. The proxy service then receives the reply from that server, and returns it to the original client unaltered except that the HTTP header has the Access-Control-Allow-Origin field set to get around CORS restrictions. It works for both IPv4 and IPv6 source and target addresses. HTTP request methods GET, POST, PUT, PATCH, DELETE, or HEAD are supported.
Why another CORS proxy program? Existing CORS proxies I found require the originating client to specify the target server as an option/parameter within the incoming URL to the proxy. The proxy dynamically extracts the target server from the URL and then sends the "real" URL to the target. My application use case only allowed me to change the server name so I could not "embed" the real server in the target URL. This simple CORS proxy must instead be statically pre-configured with the target server so it knows where to forward incoming requests. E.g.
$ ./corsproxy 8000=http://192.168.1.1:9000
The above will run corsproxy
to receive requests on port 8000
and
forward them to HTTP server 192.168.1.1:9000
.
$ ./corsproxy 8000=http://192.168.1.1:9000 8001=https://192.168.1.2:9000
This runs 2 independent proxies. It will do the same as the previous
example but will also independently and asynchronously receive requests
on port 8001
and forward them to HTTPS server 192.168.1.2:9000
. You
can specify as many proxy mappings as you want.
Instead of specifying the target mappings on the command line as above,
you can instead choose to configure them in ~/.config/corsproxy.toml
a/s per the instructions in the example
corsproxy.toml
here. The file is convenient if you
are starting the program via systemd etc. Proxy
mappings are only read from the file if none are specified on the
command line.
The receiving (i.e. listening) port and server/IP address must at least be
specified in each proxy mapping. The target port is optional.
The format, as seen in the above examples,
is [host:]port=http://server[:targetport]
or [host:]port=https://server[:targetport]
.
The latest version and documentation is available at http://github.com/bulletmark/corsproxy.
Originally this program was written for IPv4 address proxying only but
now handles IPv6 address proxying as well. IPv6 listening and target
hosts are specified by enclosing them in square brackets, e.g.
[2409:d001:4c04:3a10:4d5a:3061:db17:835]
or [::]
.
The default host address to listen for a port is 0.0.0.0
to allow all
IPv4 connections. However, you can limit to local only (i.e. loopback)
connections by specifying the host as 127.0.0.1
. Likewise, you can
specify IPv6 hosts, e.g. [::]
for all, or [::1]
for loopback. Some
examples follow:
# Local/loopback IPv4 address proxy:
$ ./corsproxy 127.0.0.1:8000=http://192.168.1.1
# Local/loopback IPv6 address proxy:
$ ./corsproxy [::1]:8000=http://192.168.1.1
# All IPv4 address proxy:
$ ./corsproxy 8000=http://192.168.1.1
# which same as:
$ ./corsproxy 0.0.0.0:8000=http://192.168.1.1
# All IPv6 address proxy:
$ ./corsproxy [::]:8000=http://192.168.1.1
# Use 2 mappings for both IPv4 and IPv6 hosts:
# [Note that Python asyncio does not allow dual stack IPv4/IPv6 so
# must run 2 separate mappings]
$ ./corsproxy 8000=http://192.168.1.1 [::]:8000=http://192.168.1.1
# Forward IPv4 HTTP to IPv6 HTTPS server (on it's port 9000):
$ ./corsproxy 8000=https://[2409:d001:4c04:3a10:4d5a:3061:db17:835]:9000
Requires python
3.7 or later and any modern
systemd based Linux environment. E.g. I run it
on a Raspberry Pi using Arch Linux
ARM.
These instructions assume you are using systemd to start the application. A systemd service service file is provided.
-
Clone repository and create configuration:
$ git clone https://github.com/bulletmark/corsproxy $ cd corsproxy $ mkdir -p ~/.config $ cp corsproxy.toml ~/.config $ vim ~/.config/corsproxy.toml # Add your target servers
-
Create virtual environment (venv) and install service:
$ python3 -m venv .venv $ .venv/bin/pip install -r requirements.txt $ sudo cp corsproxy.service /etc/systemd/system $ sudoedit /etc/systemd/system/corsproxy.service # Edit #TEMPLATE# values.
Note: Alternatively, to create the venv, install the requirement
packages, insert the template values, and enable + start the service you
can use my pinstall tool. Just
install it and do the following in the corsproxy
directory.
$ pinstall venv
$ pinstall service
To enable starting at boot and also start immediately:
$ sudo systemctl enable corsproxy
$ sudo systemctl start corsproxy
To stop immediately and also disable starting at boot:
$ sudo systemctl stop corsproxy
$ sudo systemctl disable corsproxy
Show status:
$ systemctl status corsproxy
Show log:
$ journalctl -u corsproxy
cd
to source directory, as above. Then update the source:
$ git pull
Update ~/.config/corsproxy.toml
and
/etc/systemd/system/corsproxy.service
if necessary. Then restart the
service.
$ sudo systemctl restart corsproxy
Alternatively, for many users it may be easier to install and run this
application using Docker. Follow
your Linux distribution's instructions to ensure Docker is
installed and enabled to
automatically start at boot. Also ensure you add your
user to the
docker
group.
The Docker image is available on Docker Hub. Run the following command:
$ docker run --restart always -d -p 8000:8000 bulletmark/corsproxy 8000=http://192.168.1.98
Be sure to change the target server mapping to what you require. The image is available for amd64, arm64, and arm/v7 architectures. E.g. on a standard PC, or on a Raspberry Pi, just run the above single command and docker will download, install, and run the appropriate image. Docker will also restart the corsproxy container when your system starts.
Type corsproxy -h
to view the usage summary:
usage: corsproxy [-h] [-d] [-c CONFFILE] [targets ...]
A simple CORS proxy. Reads list of target server mappings from the command
line, or from your config file. Target server mappings are of the form
"[host:]port=http://server[:targetport]" or
"[host:]port=https://server[:targetport]" where "port" is the local listening
port and "server[:targetport]" is the server (and optional target port) to
proxy to. The default host address to listen on for a port is '0.0.0.0' to
allow all IPv4 connections but you can specify an alternate host address for
each server mapping, e.g. '127.0.0.1' to limit to local IPv4 connections, or
'[::]' for all IPv6 connections, or '[::1]' to limit to local IPv6
connections, or any specific IPv4 or IPv6 address to limit to that interface.
E.g. to listen all IPv4 and IPv6 addresses and forward to same IPv4 server
define 2 mappings: "0.0.0.0:8000=http://192.168.1.1"
"[::]:8000=http://192.168.1.1".
positional arguments:
targets 1 or more proxy target server mappings
options:
-h, --help show this help message and exit
-d, --debug enable debug output
-c CONFFILE, --conffile CONFFILE
alternative configuration file,
default="~/.config/corsproxy.toml"
-
Incompatible Change: HTTPS targets are now supported in addition to standard HTTP. This necessitates an incompatible change to how the target server mappings are defined. E.g. a previous mapping
8000:192.168.1.98
now must be defined as8000=http://192.168.1.98
because you are required to define whether the target server ishttp
orhttps
. Note the listening port is now separated from the target server with a=
, not a:
. -
Incompatible Change: The configuration file
~/.config/corsproxy
is renamed to~/.config/corsproxy.toml
and is now TOML format. -
Enhancement: IPv6 addresses can now also be specified for both source and target addresses, in addition to IPv4 addresses. Also, source addresses for IPv4 and IPv6 can be specified to limit to loopback interface only, or to a specific interface, etc.
-
Enhancement: HTTP methods PUT, PATCH, DELETE, and HEAD are now supported in addition to the normal GET and POST.
-
Enhancement: Previously I was using a home-grown implementation to intercept and insert CORS headers. This worked for my use but it may not work generally for all users so now I use the Starlette middleware CORS package which is likely to be much more standards based and robust for general use.
-
Enhancement: For concurrency, the code now uses native Python asyncio rather than 3rd party gevent/greenlet so it is slightly more performant and efficient.
-
Python 3.7+ is required at a minimum. Python 3.6 no longer supported.
Copyright (C) 2019 Mark Blakeney. This program is distributed under the terms of the GNU General Public License. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses/ for more details.