From fe7fd3613b2dfd6022156a8dd4d2b0af3fad0d3a Mon Sep 17 00:00:00 2001
From: LiOn <lion.lg82@gmail.com>
Date: Sun, 4 Aug 2024 14:07:24 +0300
Subject: [PATCH 1/2] Added ENV options with refactor Config load

---
 cmd/proxy/main.go | 86 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 72 insertions(+), 14 deletions(-)

diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go
index f6b5a80..e4cce67 100644
--- a/cmd/proxy/main.go
+++ b/cmd/proxy/main.go
@@ -7,6 +7,7 @@ import (
 	"encoding/base64"
 	"encoding/hex"
 	"encoding/json"
+	"errors"
 	"flag"
 	"fmt"
 	"github.com/mdp/qrterminal/v3"
@@ -27,6 +28,7 @@ import (
 	"net/http/httputil"
 	"net/url"
 	"os"
+	"strconv"
 	"time"
 )
 
@@ -177,31 +179,91 @@ func getPublicIP() (string, error) {
 	return ip.Query, nil
 }
 
+func getEnvValue(envName string) (string, error) {
+	var value = os.Getenv(envName)
+	if value != "" {
+		return value, nil
+	} else {
+		return "", errors.New("environment variable " + envName + " not found")
+	}
+}
+
 func loadConfig() (*Config, error) {
 	var cfg Config
+	var envValue string
+	var saveRequire = false
 
 	file := "./config.json"
 	data, err := os.ReadFile(file)
 	if err != nil {
-		var srvKey ed25519.PrivateKey
-		_, srvKey, err = ed25519.GenerateKey(nil)
+		saveRequire = true
+	} else {
+		err = json.Unmarshal(data, &cfg)
 		if err != nil {
 			return nil, err
 		}
-		cfg.PrivateKey = srvKey.Seed()
+	}
+
+	//defaults with env priority
+	envValue, err = getEnvValue("GLOBAL_CONFIG_URL")
+	if err == nil {
+		cfg.NetworkConfigURL = envValue
+	} else if cfg.NetworkConfigURL == "" {
 		cfg.NetworkConfigURL = "https://ton.org/global.config.json"
+	}
 
-		cfg.ExternalIP, err = getPublicIP()
+	envValue, err = getEnvValue("EXTERNAL_IP")
+	if err == nil {
+		cfg.ExternalIP = envValue
+	} else if cfg.ExternalIP == "" {
+		var publicIP, err = getPublicIP()
 		if err != nil {
 			return nil, err
 		}
+		cfg.ExternalIP = publicIP
+	}
+
+	envValue, err = getEnvValue("LISTEN_IP")
+	if err == nil {
+		cfg.ListenIP = envValue
+	} else if cfg.ListenIP == "" {
 		cfg.ListenIP = "0.0.0.0"
+	}
 
+	envValue, err = getEnvValue("LISTEN_PORT")
+	if err == nil {
+		value, err := strconv.ParseUint(envValue, 10, 16)
+		if err != nil {
+			return nil, err
+		}
+		cfg.Port = uint16(value)
+	} else if cfg.Port == 0 {
 		// generate consistent port
 		cfg.Port = 9000 + (crc16.Checksum([]byte(cfg.ExternalIP), crc16.MakeTable(crc16.CRC16_XMODEM)) % 5000)
+	}
 
+	envValue, err = getEnvValue("PROXY_PASS")
+	if err == nil {
+		cfg.ProxyPass = envValue
+	} else if cfg.ProxyPass == "" {
 		cfg.ProxyPass = "http://127.0.0.1:80/"
+	}
+
+	var envPrivateKey string
+	envPrivateKey, err = getEnvValue("PRIVATE_KEY")
+	if err != nil {
+		log.Println("Warning: Store PrivateKey in config.json is unsafe! Use PRIVATE_KEY env instead.")
+		if cfg.PrivateKey == nil {
+			var srvKey ed25519.PrivateKey
+			_, srvKey, err = ed25519.GenerateKey(nil)
+			if err != nil {
+				return nil, err
+			}
+			cfg.PrivateKey = srvKey.Seed()
+		}
+	}
 
+	if saveRequire {
 		data, err = json.MarshalIndent(cfg, "", "\t")
 		if err != nil {
 			return nil, err
@@ -211,18 +273,14 @@ func loadConfig() (*Config, error) {
 		if err != nil {
 			return nil, err
 		}
-
-		return &cfg, nil
 	}
 
-	err = json.Unmarshal(data, &cfg)
-	if err != nil {
-		return nil, err
-	}
-
-	// backwards compatibility with old configs
-	if cfg.NetworkConfigURL == "" {
-		cfg.NetworkConfigURL = "https://ton.org/global.config.json"
+	//envPrivateKey must stay secret
+	if envPrivateKey != "" {
+		cfg.PrivateKey, err = base64.StdEncoding.DecodeString(envPrivateKey)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	return &cfg, nil

From 7dae28524688cbb67e956cd889ad4027b26acadf Mon Sep 17 00:00:00 2001
From: LiOn <lion.lg82@gmail.com>
Date: Sun, 4 Aug 2024 15:07:02 +0300
Subject: [PATCH 2/2] Update README.md

---
 README.md | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 3c496fd..4f2a725 100644
--- a/README.md
+++ b/README.md
@@ -47,11 +47,24 @@ Alternatively, you can run in simple mode, with .adnl domain, if you don't have
 
 Now anyone can access your TON Site! Using ADNL address or domain. 
 
-If you want to change some settings, like proxy pass url - open `config.json` file, edit and restart proxy. Default proxy pass url is `http://127.0.0.1:80/`
+If you want to change some settings, like proxy pass url - open `config.json` file, edit and restart proxy.
 
 Proxy adds additional headers:
 `X-Adnl-Ip` - ip of client, and `X-Adnl-Id` - adnl id of client
 
+If you want to change some settings, like proxy pass url - open `config.json` file, edit and restart proxy.
+Or use ENV variables:
+- `GLOBAL_CONFIG_URL` (default: https://ton.org/global.config.json)
+- `EXTERNAL_IP` (default: detect via http://ip-api.com/json/)
+- `LISTEN_IP` (default: 0.0.0.0)
+- `LISTEN_PORT` (default: 9000 + rand)
+- `PROXY_PASS` (default: http://127.0.0.1:80)
+- `PRIVATE_KEY` (default: generate and write to `config.json`, is env not passed. It can be used on first start to generate Private Key )
+
+ENV's, has priority over `config.json` and can be useful to run reverse-proxy in Docker container.
+
+*Using `PRIVATE_KEY` is more safety then store key in file and recommended for production.
+
 ### FAQ
 
 #### Can I have multiple domains on single reverse-proxy?