-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
346 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
1.0.1 | ||
- some minor bugs corrections | ||
|
||
2.0.0 | ||
- code rewritten | ||
- https server added |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,95 @@ | ||
reverseproxy | ||
==== | ||
[![version](https://img.shields.io/badge/version-1.0.1-blue.svg)](https://github.com/geosoft1/reverseproxy/archive/master.zip) | ||
[![version](https://img.shields.io/badge/version-2.0.0-blue.svg)](https://github.com/geosoft1/reverseproxy/archive/master.zip) | ||
[![license](https://img.shields.io/badge/license-gpl-blue.svg)](https://github.com/geosoft1/reverseproxy/blob/master/LICENSE) | ||
|
||
Simple [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) server. Useful for accessing web applications on various servers (or VMs) through a single domain. | ||
|
||
### How it works? | ||
## How it works? | ||
|
||
![reverseproxy](https://user-images.githubusercontent.com/6298396/36028867-5e549ea4-0da9-11e8-8ecf-62546e95ca5c.png) | ||
|
||
Just complete the `conf.json` file and run the server. Example: | ||
|
||
{ | ||
"ip":"", | ||
"port":"8080", | ||
"routes":{ | ||
"/upload":"192.168.88.160:8080", | ||
"/Downloads/":"192.168.88.164:8000", | ||
"#":"the pattern / matches all paths not matched by other registered patterns", | ||
"/":"192.168.88.161" | ||
} | ||
} | ||
{ | ||
"routes": { | ||
"#": "the pattern / matches all paths not matched by other registered patterns", | ||
"/": "http://192.168.88.250", | ||
"/wrong": "192.168.88.250:8080", | ||
"/upload": "http://192.168.88.250:8080", | ||
"/hello": "https://192.168.88.250:8090", | ||
"/static/": "http://192.168.88.250:8080", | ||
"#/disabled": "192.168.88.250:8080" | ||
} | ||
} | ||
|
||
## Configuration details | ||
## Getting started | ||
|
||
"ip":"", | ||
To compile the reverse proxy server use | ||
|
||
No ip mean `localhost` on hosting server. Is no need to change this. | ||
go build | ||
|
||
"port":"8080", | ||
If you still want just an HTTP reverse proxy, compile with | ||
|
||
The server listening on this port. Remeber to forward the port `80` to this port if your connection pass through a router. No root right are required if you run on big ports (eg. `8080`). | ||
go build http.go | ||
|
||
or for HTTPS | ||
|
||
go build https.go | ||
|
||
Parameters | ||
|
||
### `-conf` | ||
|
||
Start program with a certain configuration file. Default `conf.json`. | ||
|
||
### `-http` | ||
|
||
Listening address and port for HTTP server. Default `:8080`. | ||
|
||
### `-https` | ||
|
||
Listening address and port for HTTPS server. Default `:8090`. | ||
|
||
### `-https-enabled` | ||
|
||
Enable HTTPS server. Default `false`. | ||
|
||
### `-verbose` | ||
|
||
Enable verbose mode for middleware. | ||
|
||
## Routes | ||
|
||
Routes has the folowing structure | ||
|
||
"path":"target" | ||
"path":"host" | ||
|
||
The path is what you request and the host is what you get. The reverse proxy always add the path to the host (eg. if your host address is `example.com` then the path `/` mean `example.com/` and `/upload` mean `example.com/upload`). | ||
|
||
Paths starting with `#` are comments and are not added to routes. | ||
|
||
A path like `/name/` match any request starting with `name` (eg. `/api/` match also `/api/bla` and so on). | ||
|
||
Hosts must be a complete url address and port. | ||
|
||
Do not repeat the routes because the server will take always the last route to a host. | ||
|
||
## Testing the server | ||
|
||
The path is what you request and the target is what you get (eg. if your domain is `example.com` then `/` mean `example.com/` and `/upload` mean `example.com/upload`). | ||
curl --verbose http://localhost:8080/hello | ||
|
||
`#` path mean a comment and is not added to routes. Put the text in target. `#something` don't mean a comment. | ||
For HTTPS use | ||
|
||
The reverse proxy add your path to the target, so be prepared to handle this path. For example the folowing will get an error page. | ||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt | ||
curl --insecure --verbose https://localhost:8090/hello | ||
|
||
"/upload":"google.com" | ||
## Faq | ||
|
||
Use `/` path for main site which have index page on `/`. Use sufixes for other web services which have the sufix as main page. | ||
### Why the HTTPS is not enabled by default? | ||
|
||
Remeber that a route like `/name/` mean match any starting with `name` (eg. `/api/` match also `/api/bla` and so on). | ||
HTTPS server need some valid certificates which you may not have. If you need only a HTTP server is no reason to generate cerificates just to run the program. | ||
|
||
Do not repeat the routes because the server will take always the last route to a target. | ||
### Should I use http or https in the host address? | ||
|
||
Yes, prefixes are mandatory to tell the server in which chain to put the route. Omitting that will skip the route. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,11 @@ | ||
{ | ||
"ip":"", | ||
"port":"8080", | ||
"routes":{ | ||
"/upload":"192.168.88.160:8080", | ||
"#/files/":"192.168.88.160:8080", | ||
"/Downloads/":"192.168.88.164:8000", | ||
"/img":"192.168.88.161:8081", | ||
"#":"the pattern / matches all paths not matched by other registered patterns", | ||
"/":"192.168.88.161" | ||
} | ||
} | ||
"routes": { | ||
"#": "the pattern / matches all paths not matched by other registered patterns", | ||
"/": "http://192.168.88.250", | ||
"/wrong": "192.168.88.250:8080", | ||
"/upload": "http://192.168.88.250:8080", | ||
"/hello": "https://192.168.88.250:8090", | ||
"/static/": "http://192.168.88.250:8080", | ||
"#/disabled": "192.168.88.250:8080" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// simple http reverse proxy | ||
// Copyright (C) 2017-2019 geosoft1 geosoft1@gmail.com | ||
// | ||
// 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 | ||
// (at your option) 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 for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
// +build http | ||
|
||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"net/http/httputil" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
var configFile = flag.String("conf", "conf.json", "configuration file") | ||
var httpAddress = flag.String("http", ":8080", "http address") | ||
var verbose = flag.Bool("verbose", false, "explain what is being done") | ||
|
||
var config map[string]interface{} | ||
|
||
func NewReverseProxy(scheme, host string) *httputil.ReverseProxy { | ||
return httputil.NewSingleHostReverseProxy(&url.URL{ | ||
Scheme: scheme, | ||
Host: host, | ||
}) | ||
} | ||
|
||
func Register(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
if *verbose { | ||
log.Printf("request %s%s", r.RemoteAddr, r.RequestURI) | ||
} | ||
w.Header().Set("Access-Control-Allow-Origin", "*") | ||
w.Header().Set("Access-Control-Allow-Headers", "X-Requested-With") | ||
p.ServeHTTP(w, r) | ||
} | ||
} | ||
|
||
func main() { | ||
flag.Usage = func() { | ||
fmt.Printf("usage: %s [options]\n", filepath.Base(os.Args[0])) | ||
flag.PrintDefaults() | ||
} | ||
flag.Parse() | ||
log.SetFlags(log.LstdFlags | log.Lshortfile) | ||
|
||
folder, err := filepath.Abs(filepath.Dir(os.Args[0])) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
file, err := os.Open(filepath.Join(folder, *configFile)) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
if err := json.NewDecoder(file).Decode(&config); err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
for path, host := range config["routes"].(map[string]interface{}) { | ||
log.Printf("%s -> %s", path, host) | ||
if strings.HasPrefix(path, "#") { | ||
// skip comments | ||
continue | ||
} | ||
u, err := url.Parse(host.(string)) | ||
if err != nil { | ||
// skip invalid hosts | ||
log.Println(err) | ||
continue | ||
} | ||
http.HandleFunc(path, Register(NewReverseProxy(u.Scheme, u.Host))) | ||
} | ||
|
||
log.Printf("start http server on %s", *httpAddress) | ||
if err := http.ListenAndServe(*httpAddress, nil); err != nil { | ||
log.Fatalln(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// simple https reverse proxy | ||
// Copyright (C) 2017-2019 geosoft1 geosoft1@gmail.com | ||
// | ||
// 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 | ||
// (at your option) 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 for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
// +build https | ||
|
||
package main | ||
|
||
import ( | ||
"crypto/tls" | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"net/http/httputil" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
var configFile = flag.String("conf", "conf.json", "configuration file") | ||
var httpsAddress = flag.String("https", ":8090", "https address") | ||
var verbose = flag.Bool("verbose", false, "explain what is being done") | ||
|
||
var config map[string]interface{} | ||
|
||
func NewReverseProxy(scheme, host string) *httputil.ReverseProxy { | ||
return httputil.NewSingleHostReverseProxy(&url.URL{ | ||
Scheme: scheme, | ||
Host: host, | ||
}) | ||
} | ||
|
||
func Register(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
if *verbose { | ||
log.Printf("request %s%s", r.RemoteAddr, r.RequestURI) | ||
} | ||
w.Header().Set("Access-Control-Allow-Origin", "*") | ||
w.Header().Set("Access-Control-Allow-Headers", "X-Requested-With") | ||
p.ServeHTTP(w, r) | ||
} | ||
} | ||
|
||
func main() { | ||
flag.Usage = func() { | ||
fmt.Printf("usage: %s [options]\n", filepath.Base(os.Args[0])) | ||
flag.PrintDefaults() | ||
} | ||
flag.Parse() | ||
log.SetFlags(log.LstdFlags | log.Lshortfile) | ||
|
||
folder, err := filepath.Abs(filepath.Dir(os.Args[0])) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
file, err := os.Open(filepath.Join(folder, *configFile)) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
if err := json.NewDecoder(file).Decode(&config); err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
for path, host := range config["routes"].(map[string]interface{}) { | ||
log.Printf("%s -> %s", path, host) | ||
if strings.HasPrefix(path, "#") { | ||
// skip comments | ||
continue | ||
} | ||
u, err := url.Parse(host.(string)) | ||
if err != nil { | ||
// skip invalid hosts | ||
log.Println(err) | ||
continue | ||
} | ||
http.HandleFunc(path, Register(NewReverseProxy(u.Scheme, u.Host))) | ||
} | ||
|
||
// allow you to use self signed certificates | ||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} | ||
// openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt | ||
log.Printf("start https server on %s", *httpsAddress) | ||
if err := http.ListenAndServeTLS(*httpsAddress, filepath.Join(folder, "server.crt"), filepath.Join(folder, "server.key"), nil); err != nil { | ||
log.Fatalln(err) | ||
} | ||
} |
Oops, something went wrong.