diff --git a/.gitignore b/.gitignore index 727d3f1..74b03fb 100755 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ compose.yml -config/** - -bin/go-proxy.bak - +config/ +certs/ +bin/ templates/codemirror/ logs/ diff --git a/Makefile b/Makefile index f669eba..69036f5 100755 --- a/Makefile +++ b/Makefile @@ -6,7 +6,6 @@ setup: mkdir -p config certs [ -f config/config.yml ] || cp config.example.yml config/config.yml [ -f config/providers.yml ] || touch config/providers.yml - [ -f compose.yml ] || cp compose.example.yml compose.yml setup-codemirror: wget https://codemirror.net/5/codemirror.zip diff --git a/README.md b/README.md index 8d0d296..36c1a77 100755 --- a/README.md +++ b/README.md @@ -10,8 +10,6 @@ In the examples domain `x.y.z` is used, replace them with your domain - [Table of content](#table-of-content) - [Key Points](#key-points) - [How to use](#how-to-use) - - [Binary](#binary) - - [Docker](#docker) - [Command-line args](#command-line-args) - [Commands](#commands) - [Use JSON Schema in VSCode](#use-json-schema-in-vscode) @@ -44,83 +42,30 @@ In the examples domain `x.y.z` is used, replace them with your domain - Subdomain matching + Path matching **(domain name doesn't matter)** - HTTP(s) proxy + TCP/UDP Proxy (UDP is _experimental_) - HTTP(s) round robin load balance support (same subdomain and path across different hosts) -- Simple panel to see all reverse proxies and health available on port 8080 (http) and port 8443 (https) +- Web UI on port 8080 (http) and port 8443 (https) - ![panel screenshot](screenshots/panel.png) + - a simple panel to see all reverse proxies and health -- Config editor to edit config and provider files with validation + ![panel screenshot](screenshots/panel.png) - **Validate and save file with Ctrl+S** + - a config editor to edit config and provider files with validation - ![config editor screenshot](screenshots/config_editor.png) + **Validate and save file with Ctrl+S** + + ![config editor screenshot](screenshots/config_editor.png) ## How to use -1. Clone the repository `git clone https://github.com/yusing/go-proxy && cd go-proxy` - -2. Call `make setup` to init config file, provider file, and docker compose file - -3. Point your domain (i.e `y.z`) to your machine's IP address +1. Setup DNS Records to your machine's IP address - A Record: `*.y.z` -> `10.0.10.1` - AAAA Record: `*.y.z` -> `::ffff:a00:a01` -4. Start `go-proxy` (see [Binary](#binary) or [docker](#docker)) +2. Start `go-proxy` (see [Binary](docs/binary.md) or [docker](docs/docker.md)) -5. (Optional) `make setup-codemirror` in case you use the web config editor - -6. Start editing config files - - with text editor (i.e. Visual Studio Code) - - with web config editor by navigate to `ip:8080` - -### Binary - -1. (Optional) enabled HTTPS - - - Use autocert feature by completing `autocert` in `config.yml` - - - Use existing certificate - - Prepare your wildcard (`*.y.z`) SSL cert in `certs/` - - - cert / chain / fullchain: `certs/cert.crt` - - private key: `certs/priv.key` - -2. run the binary `bin/go-proxy` - -3. enjoy - -### Docker - -1. Copy content from [compose.example.yml](compose.example.yml) and create your own `compose.yml` - -2. Add networks to make sure it is in the same network with other containers, or make sure `proxy..host` is reachable - -3. (Optional) enable HTTPS - - - Use autocert feature by completing `autocert` section in `config/config.yml` and mount `certs/` to `/app/certs` in order to store obtained certs - - - Use existing certificate by mount your wildcard (`*.y.z`) SSL cert - - - cert / chain / fullchain -> `/app/certs/cert.crt` - - private key -> `/app/certs/priv.key` - -4. Start `go-proxy` with `docker compose up -d` or `make up`. - -5. (Optional) If you are using ufw with vpn that drop all inbound traffic except vpn, run below to allow docker containers to connect to `go-proxy` - - In case the network of your container is in subnet `172.16.0.0/16` (bridge), - and vpn network is under `100.64.0.0/10` (i.e. tailscale) - - `sudo ufw allow from 172.16.0.0/16 to 100.64.0.0/10` - - You can also list CIDRs of all docker bridge networks by: - - `docker network inspect $(docker network ls | awk '$3 == "bridge" { print $1}') | jq -r '.[] | .Name + " " + .IPAM.Config[0].Subnet' -` - -6. start your docker app, and visit .y.z - -7. check the logs with `docker compose logs` or `make logs` to see if there is any error, check panel at [panel port] for active proxies +3. Start editing config files + - with text editor (i.e. Visual Studio Code) + - or with web config editor by navigate to `ip:8080` ## Command-line args @@ -130,7 +75,12 @@ In the examples domain `x.y.z` is used, replace them with your domain - empty: start proxy server - validate: validate config and exit -- reload: force reload config and exit +- reload: trigger a force reload of config + +Examples: + +- Binary: `go-proxy reload` +- Docker: `docker exec -it go-proxy /app/go-proxy reload` ## Use JSON Schema in VSCode @@ -165,7 +115,7 @@ See [compose.example.yml](compose.example.yml) for more - `proxy.*.`: wildcard label for all aliases -Below labels has a **`proxy.`** prefix (i.e. `proxy.nginx.scheme: http`) +Below labels has a **`proxy..`** prefix (i.e. `proxy.nginx.scheme: http`) - `scheme`: proxy protocol - default: `http` @@ -201,7 +151,6 @@ Below labels has a **`proxy.`** prefix (i.e. `proxy.nginx.scheme: http`) ### Environment variables - `GOPROXY_DEBUG`: set to `1` or `true` to enable debug behaviors (i.e. output, etc.) -- `GOPROXY_REDIRECT_HTTP`: set to `0` or `false` to disable http to https redirect (only when certs are located) ### Config File @@ -226,7 +175,7 @@ See [config.example.yml](config.example.yml) for more values: - - `FROM_ENV`: value from environment + - `FROM_ENV`: value from environment (`DOCKER_HOST`) - full url to docker host (i.e. `tcp://host:2375`) - `file`: load reverse proxies from provider file @@ -247,45 +196,7 @@ See [providers.example.yml](providers.example.yml) for examples Follow [this guide](https://cloudkul.com/blog/automcatic-renew-and-generate-ssl-on-your-website-using-lego-client/) to create a new token with `Zone.DNS` read and edit permissions -To add more provider support (**CloudDNS** as an example): - -1. Fork this repo, modify [autocert.go](src/go-proxy/autocert.go#L305) - - ```go - var providersGenMap = map[string]ProviderGenerator{ - "cloudflare": providerGenerator(cloudflare.NewDefaultConfig, cloudflare.NewDNSProviderConfig), - // add here, i.e. - "clouddns": providerGenerator(clouddns.NewDefaultConfig, clouddns.NewDNSProviderConfig), - } - ``` - -2. Go to [https://go-acme.github.io/lego/dns/clouddns](https://go-acme.github.io/lego/dns/clouddns/) and check for required config - -3. Build `go-proxy` with `make build` - -4. Set required config in `config.yml` `autocert` -> `options` section - - ```shell - # From https://go-acme.github.io/lego/dns/clouddns/ - CLOUDDNS_CLIENT_ID=bLsdFAks23429841238feb177a572aX \ - CLOUDDNS_EMAIL=you@example.com \ - CLOUDDNS_PASSWORD=b9841238feb177a84330f \ - lego --email you@example.com --dns clouddns --domains my.example.org run - ``` - - Should turn into: - - ```yaml - autocert: - ... - options: - client_id: bLsdFAks23429841238feb177a572aX - email: you@example.com - password: b9841238feb177a84330f - ``` - -5. Run and test if it works -6. Commit and create pull request +To add more provider support, see [this](docs/add_dns_provider.md) ## Examples @@ -345,7 +256,7 @@ go-proxy: ports: - 80:80 ... - - 20000:20000/tcp + - :20000/tcp # or 20000-20010:20000-20010/tcp to declare large range at once # access app-db via <*>.y.z:20000 diff --git a/bin/go-proxy b/bin/go-proxy deleted file mode 100755 index f934eab..0000000 Binary files a/bin/go-proxy and /dev/null differ diff --git a/compose.example.yml b/compose.example.yml index 636c42a..8be7f43 100755 --- a/compose.example.yml +++ b/compose.example.yml @@ -1,18 +1,15 @@ version: '3' services: app: - build: . + image: ghcr.io/yusing/go-proxy:latest container_name: go-proxy restart: always networks: # ^also add here - default - # environment: - # - GOPROXY_DEBUG=1 # (optional, enable only for debug) - # - GOPROXY_REDIRECT_HTTP=0 # (optional, uncomment to disable http redirect (http -> https)) ports: - - 80:80 # http - # - 443:443 # optional, https + - 80:80 # http proxy - 8080:8080 # http panel + # - 443:443 # optional, https proxy # - 8443:8443 # optional, https panel # optional, if you declared any tcp/udp proxy, set a range you want to use diff --git a/docs/add_dns_provider.md b/docs/add_dns_provider.md new file mode 100644 index 0000000..16b07b2 --- /dev/null +++ b/docs/add_dns_provider.md @@ -0,0 +1,41 @@ +# Adding provider support + +## **CloudDNS** as an example + +1. Fork this repo, modify [autocert.go](../src/go-proxy/autocert.go#L305) + + ```go + var providersGenMap = map[string]ProviderGenerator{ + "cloudflare": providerGenerator(cloudflare.NewDefaultConfig, cloudflare.NewDNSProviderConfig), + // add here, i.e. + "clouddns": providerGenerator(clouddns.NewDefaultConfig, clouddns.NewDNSProviderConfig), + } + ``` + +2. Go to [https://go-acme.github.io/lego/dns/clouddns](https://go-acme.github.io/lego/dns/clouddns/) and check for required config + +3. Build `go-proxy` with `make build` + +4. Set required config in `config.yml` `autocert` -> `options` section + + ```shell + # From https://go-acme.github.io/lego/dns/clouddns/ + CLOUDDNS_CLIENT_ID=bLsdFAks23429841238feb177a572aX \ + CLOUDDNS_EMAIL=you@example.com \ + CLOUDDNS_PASSWORD=b9841238feb177a84330f \ + lego --email you@example.com --dns clouddns --domains my.example.org run + ``` + + Should turn into: + + ```yaml + autocert: + ... + options: + client_id: bLsdFAks23429841238feb177a572aX + email: you@example.com + password: b9841238feb177a84330f + ``` + +5. Run and test if it works +6. Commit and create pull request diff --git a/docs/binary.md b/docs/binary.md new file mode 100644 index 0000000..5f4cdbc --- /dev/null +++ b/docs/binary.md @@ -0,0 +1,46 @@ +# Getting started with `go-proxy` (binary) + +## Setup + +1. Install `make` and `wget` if not already + +2. Run setup script + + ```shell + export VERSION=latest + export SETUP_CODEMIRROR=1 # set to 0 if you don't need web config editor + wget -qO- https://6uo.me/go-proxy-setup-binary | sudo bash + ``` + + What it does: + + - Download source file and binary into /opt/go-proxy/$VERSION + - Setup `config.yml` and `providers.yml` + - Setup `template/codemirror` which is a dependency for web config editor + - Create a systemd service (if available) in `/etc/systemd/system/go-proxy.service` + - Enable and start `go-proxy` service + +3. Start editing config files in `http://:8080` + +4. Check logs / status with `systemctl status go-proxy` + +## Setup (alternative method) + +1. Download the latest release and extract somewhere + +2. Run `make setup` and _(optional) `make setup-codemirror`_ + +3. Enable HTTPS _(optional)_ + + - To use autocert feature + + complete `autocert` in `config/config.yml` + + - To use existing certificate + + Prepare your wildcard (`*.y.z`) SSL cert in `certs/` + + - cert / chain / fullchain: `certs/cert.crt` + - private key: `certs/priv.key` + +4. Run the binary `bin/go-proxy` diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..077421b --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,63 @@ +# Getting started with `go-proxy` docker container + +## Setup + +1. Install `wget` if not already + +2. Run setup script + + `bash <(wget -qO- https://6uo.me/go-proxy-setup-docker)` + + What it does: + + - Create required directories + - Setup `config.yml` and `compose.yml` + +3. Verify folder structure and then `cd go-proxy` + + ```plain + go-proxy + ├── certs + ├── compose.yml + └── config + ├── config.yml + └── providers.yml + ``` + +4. Enable HTTPs _(optional)_ + - To use autocert feature + - completing `autocert` section in `config/config.yml` + - mount `certs/` to `/app/certs` to store obtained certs + + - To use existing certificate + + mount your wildcard (`*.y.z`) SSL cert + + - cert / chain / fullchain -> `/app/certs/cert.crt` + - private key -> `/app/certs/priv.key` + +5. Modify `compose.yml` fit your needs + + Add networks to make sure it is in the same network with other containers, or make sure `proxy..host` is reachable + +6. Run `docker compose up -d` to start the container + +7. Start editing config files in `http://:8080` + +## Troubleshooting + +- Firewall issues + + If you are using `ufw` with vpn that drop all inbound traffic except vpn, run below: + + `sudo ufw allow from 172.16.0.0/16 to 100.64.0.0/10` + + Explaination: + + Docker network is usually `172.16.0.0/16` + + Tailscale is used as an example, `100.64.0.0/10` will be the CIDR + + You can also list CIDRs of all docker bridge networks by: + + `docker network inspect $(docker network ls | awk '$3 == "bridge" { print $1}') | jq -r '.[] | .Name + " " + .IPAM.Config[0].Subnet' -` diff --git a/setup-binary.sh b/setup-binary.sh new file mode 100644 index 0000000..ffd32b3 --- /dev/null +++ b/setup-binary.sh @@ -0,0 +1,108 @@ +#!/bin/sh +set -e +REPO_URL=https://github.com/yusing/go-proxy +BIN_URL="${REPO_URL}/releases/download/${VERSION}/go-proxy" +SRC_URL="${REPO_URL}/archive/refs/tags/${VERSION}.tar.gz" +APP_ROOT="/opt/go-proxy/${VERSION}" + +if [ -z "$VERSION" ]; then + echo "You must specify a version" + exit 1 +fi + +if [ -d "$APP_ROOT" ]; then + echo "$APP_ROOT already exists" + exit 1 +fi + +# check if wget exists +if ! [ -x "$(command -v wget)" ]; then + echo "wget is not installed" + exit 1 +fi + +# check if make exists +if ! [ -x "$(command -v make)" ]; then + echo "make is not installed" + exit 1 +fi + +dl_source() { + cd /tmp + echo "Downloading go-proxy source ${VERSION}" + wget -c "${SRC_URL}" -O go-proxy.tar.gz 2>&1 + echo "Done" + if [ $? -gt 0 ]; then + echo "Source download failed, check your internet connection and version number" + exit 1 + fi + echo "Extracting go-proxy source ${VERSION}" + tar xzf go-proxy.tar.gz 2>&1 + if [ $? -gt 0 ]; then + echo "failed to untar go-proxy.tar.gz" + exit 1 + fi + rm go-proxy.tar.gz + mkdir -p $(dirname $APP_ROOT) + mv "go-proxy-${VERSION}" $APP_ROOT + cd $APP_ROOT + echo "Done" +} +dl_binary() { + mkdir -p bin + echo "Downloading go-proxy binary ${VERSION}" + wget -c "${BIN_URL}" -O bin/go-proxy 2>&1 + if [ $? -gt 0 ]; then + echo "Binary download failed, check your internet connection and version number" + exit 1 + fi + chmod +x bin/go-proxy + echo "Done" +} +setup() { + make setup + if [ $? -gt 0 ]; then + echo "make setup failed" + exit 1 + fi + # SETUP_CODEMIRROR = 1 + if [ "$SETUP_CODEMIRROR" = "1" ]; then + make setup-codemirror || echo "make setup-codemirror failed, ignored" + fi +} + +dl_source +dl_binary +setup + +# setup systemd + +# check if systemctl exists +if ! command -v systemctl is-system-running > /dev/null 2>&1; then + echo "systemctl not found, skipping systemd setup" + exit 0 +fi +systemctl-failed() { + echo "Failed to enable and start go-proxy" + systemctl status go-proxy + exit 1 +} +mkdir -p /etc/systemd/system +cat < /etc/systemd/system/go-proxy.service +[Unit] +Description=go-proxy reverse proxy +After=network-online.target +Wants=network-online.target systemd-networkd-wait-online.service +[Service] +Type=simple +ExecStart=${APP_ROOT}/bin/go-proxy +WorkingDirectory=${APP_ROOT} +Environment="IS_SYSTEMD=1" +Restart=on-failure +RestartSec=1s +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload || systemctl-failed +systemctl enable --now go-proxy || systemctl-failed +echo "Setup complete" \ No newline at end of file diff --git a/setup-docker.sh b/setup-docker.sh new file mode 100644 index 0000000..3be91c6 --- /dev/null +++ b/setup-docker.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e +if [ -z "$BRANCH" ]; then + BRANCH="main" +fi +BASE_URL="https://github.com/yusing/go-proxy/raw/${BRANCH}" +mkdir -p go-proxy +cd go-proxy +mkdir -p config +mkdir -p certs +[ -f compose.yml ] || wget -cO - ${BASE_URL}/compose.example.yml > compose.yml +[ -f config/config.yml ] || wget -cO - ${BASE_URL}/config.example.yml > config/config.yml +[ -f config/providers.yml ] || touch config/providers.yml \ No newline at end of file diff --git a/src/go-proxy/constants.go b/src/go-proxy/constants.go index 7ca4f29..4e194f0 100644 --- a/src/go-proxy/constants.go +++ b/src/go-proxy/constants.go @@ -175,3 +175,8 @@ var logLevel = func() logrus.Level { } return logrus.GetLevel() }() + +var isRunningAsService = func() bool { + v := os.Getenv("IS_SYSTEMD") + return v == "1" +}() \ No newline at end of file diff --git a/src/go-proxy/main.go b/src/go-proxy/main.go index 96e5383..d4eb58d 100755 --- a/src/go-proxy/main.go +++ b/src/go-proxy/main.go @@ -19,12 +19,21 @@ func main() { args := getArgs() - logrus.SetFormatter(&logrus.TextFormatter{ - ForceColors: true, - DisableColors: false, - FullTimestamp: true, - TimestampFormat: "01-02 15:04:05", - }) + if isRunningAsService { + logrus.SetFormatter(&logrus.TextFormatter{ + DisableColors: true, + DisableTimestamp: true, + DisableSorting: true, + }) + } else { + logrus.SetFormatter(&logrus.TextFormatter{ + ForceColors: true, + DisableColors: false, + DisableSorting: true, + FullTimestamp: true, + TimestampFormat: "01-02 15:04:05", + }) + } if args.Command == CommandReload { err := utils.reloadServer()