mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
simplify setup with script
This commit is contained in:
parent
05cbf99237
commit
b2a6a20f10
6 changed files with 254 additions and 184 deletions
22
README.md
22
README.md
|
@ -70,23 +70,17 @@ Setup DNS Records point to machine which runs `GoDoxy`, e.g.
|
|||
|
||||
**NOTE:** GoDoxy is designed to be (and only works when) running in `host` network mode, do not change it. To change listening ports, modify `.env`.
|
||||
|
||||
1. Pull the latest docker images
|
||||
1. Prepare a new directory for docker compose and config files.
|
||||
|
||||
2. Run setup script inside the directory, or [set up manually](#manual-setup)
|
||||
|
||||
```shell
|
||||
docker pull ghcr.io/yusing/go-proxy:latest
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/yusing/go-proxy/v0.9/scripts/setup.sh)"
|
||||
```
|
||||
|
||||
2. Create new directory, `cd` into it, then run setup, or [set up manually](#manual-setup)
|
||||
3. Start the container `docker compose up -d` and wait for it to be ready
|
||||
|
||||
```shell
|
||||
docker run --rm -v .:/setup ghcr.io/yusing/go-proxy /app/godoxy setup
|
||||
```
|
||||
|
||||
3. _(Optional)_ setup `docker-socket-proxy` other docker nodes (see [Multi docker nodes setup](https://github.com/yusing/go-proxy/wiki/Configurations#multi-docker-nodes-setup)) then add them inside `config.yml`
|
||||
|
||||
4. Start the container `docker compose up -d`
|
||||
|
||||
5. You may now do some extra configuration on WebUI `https://godoxy.domain.com`
|
||||
4. You may now do some extra configuration on WebUI `https://godoxy.yourdomain.com`
|
||||
|
||||
[🔼Back to top](#table-of-content)
|
||||
|
||||
|
@ -118,6 +112,10 @@ Setup DNS Records point to machine which runs `GoDoxy`, e.g.
|
|||
│ │ ├── middleware2.yml
|
||||
│ ├── provider1.yml
|
||||
│ └── provider2.yml
|
||||
├── data
|
||||
│ ├── metrics # metrics data
|
||||
│ │ ├── uptime.json
|
||||
│ │ └── system_info.json
|
||||
└── .env
|
||||
```
|
||||
|
||||
|
|
|
@ -66,23 +66,19 @@
|
|||
|
||||
## 安裝
|
||||
|
||||
1. 拉取最新的 Docker 映像
|
||||
**注意:** GoDoxy 設計為(且僅在)`host` 網路模式下運作,請勿更改。如需更改監聽埠,請修改 `.env`。
|
||||
|
||||
1. 準備一個新目錄用於 docker compose 和配置文件。
|
||||
|
||||
2. 在目錄內運行安裝腳本,或[手動安裝](#手動安裝)
|
||||
|
||||
```shell
|
||||
docker pull ghcr.io/yusing/go-proxy:latest
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/yusing/go-proxy/v0.9/scripts/setup.sh)"
|
||||
```
|
||||
|
||||
2. 建立新目錄,`cd` 進入後運行安裝,或[手動安裝](#手動安裝)
|
||||
3. 啟動容器 `docker compose up -d` 並等待就緒
|
||||
|
||||
```shell
|
||||
docker run --rm -v .:/setup ghcr.io/yusing/go-proxy /app/godoxy setup
|
||||
```
|
||||
|
||||
3. _(可選)_ 設置其他 Docker 節點的 `docker-socket-proxy`(參見 [多 Docker 節點設置](https://github.com/yusing/go-proxy/wiki/Configurations#multi-docker-nodes-setup)),然後在 `config.yml` 中添加它們
|
||||
|
||||
4. 啟動容器 `docker compose up -d`
|
||||
|
||||
5. 大功告成!可前往WebUI `https://gp.domain.com` 進行額外的配置
|
||||
4. 現在可以在 WebUI `https://godoxy.yourdomain.com` 進行額外配置
|
||||
|
||||
[🔼回到頂部](#目錄)
|
||||
|
||||
|
@ -114,6 +110,10 @@
|
|||
│ │ ├── middleware2.yml
|
||||
│ ├── provider1.yml
|
||||
│ └── provider2.yml
|
||||
├── data
|
||||
│ ├── metrics # metrics data
|
||||
│ │ ├── uptime.json
|
||||
│ │ └── system_info.json
|
||||
└── .env
|
||||
```
|
||||
|
||||
|
|
|
@ -42,9 +42,6 @@ func main() {
|
|||
args := common.GetArgs()
|
||||
|
||||
switch args.Command {
|
||||
case common.CommandSetup:
|
||||
internal.Setup()
|
||||
return
|
||||
case common.CommandReload:
|
||||
if err := query.ReloadServer(); err != nil {
|
||||
E.LogFatal("server reload error", err)
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Args struct {
|
||||
|
@ -12,7 +10,6 @@ type Args struct {
|
|||
|
||||
const (
|
||||
CommandStart = ""
|
||||
CommandSetup = "setup"
|
||||
CommandValidate = "validate"
|
||||
CommandListConfigs = "ls-config"
|
||||
CommandListRoutes = "ls-routes"
|
||||
|
@ -23,34 +20,20 @@ const (
|
|||
CommandDebugListMTrace = "debug-ls-mtrace"
|
||||
)
|
||||
|
||||
var ValidCommands = []string{
|
||||
CommandStart,
|
||||
CommandSetup,
|
||||
CommandValidate,
|
||||
CommandListConfigs,
|
||||
CommandListRoutes,
|
||||
CommandListIcons,
|
||||
CommandReload,
|
||||
CommandDebugListEntries,
|
||||
CommandDebugListProviders,
|
||||
CommandDebugListMTrace,
|
||||
}
|
||||
type MainServerCommandValidator struct{}
|
||||
|
||||
func GetArgs() Args {
|
||||
var args Args
|
||||
flag.Parse()
|
||||
args.Command = flag.Arg(0)
|
||||
if err := validateArg(args.Command); err != nil {
|
||||
log.Fatalf("invalid command: %s", err)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func validateArg(arg string) error {
|
||||
for _, v := range ValidCommands {
|
||||
if arg == v {
|
||||
return nil
|
||||
}
|
||||
func (v MainServerCommandValidator) IsCommandValid(cmd string) bool {
|
||||
switch cmd {
|
||||
case CommandStart,
|
||||
CommandValidate,
|
||||
CommandListConfigs,
|
||||
CommandListRoutes,
|
||||
CommandListIcons,
|
||||
CommandReload,
|
||||
CommandDebugListEntries,
|
||||
CommandDebugListProviders,
|
||||
CommandDebugListMTrace:
|
||||
return true
|
||||
}
|
||||
return fmt.Errorf("invalid command %q", arg)
|
||||
}
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
)
|
||||
|
||||
var (
|
||||
branch = common.GetEnvString("BRANCH", "v0.9")
|
||||
baseURL = "https://github.com/yusing/go-proxy/raw/" + branch
|
||||
requiredConfigs = []Config{
|
||||
{common.ConfigBasePath, true, false, ""},
|
||||
{common.DotEnvPath, false, true, common.DotEnvExamplePath},
|
||||
{common.ComposeFileName, false, true, common.ComposeExampleFileName},
|
||||
{path.Join(common.ConfigBasePath, common.ConfigFileName), false, true, common.ConfigExampleFileName},
|
||||
}
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Pathname string
|
||||
IsDir bool
|
||||
NeedDownload bool
|
||||
DownloadFileName string
|
||||
}
|
||||
|
||||
func Setup() {
|
||||
log.Println("setting up go-proxy")
|
||||
log.Println("branch:", branch)
|
||||
|
||||
if err := os.Chdir("/setup"); err != nil {
|
||||
log.Fatalf("failed: %s\n", err)
|
||||
}
|
||||
|
||||
for _, config := range requiredConfigs {
|
||||
config.setup()
|
||||
}
|
||||
|
||||
log.Println("setup finished")
|
||||
}
|
||||
|
||||
func (c *Config) setup() {
|
||||
if c.IsDir {
|
||||
mkdir(c.Pathname)
|
||||
return
|
||||
}
|
||||
if !c.NeedDownload {
|
||||
touch(c.Pathname)
|
||||
return
|
||||
}
|
||||
|
||||
fetch(c.DownloadFileName, c.Pathname)
|
||||
}
|
||||
|
||||
func hasFileOrDir(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func mkdir(pathname string) {
|
||||
_, err := os.Stat(pathname)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
log.Printf("creating directory %q\n", pathname)
|
||||
err := os.MkdirAll(pathname, 0o755)
|
||||
if err != nil {
|
||||
log.Fatalf("failed: %s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("failed: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func touch(pathname string) {
|
||||
if hasFileOrDir(pathname) {
|
||||
return
|
||||
}
|
||||
log.Printf("creating file %q\n", pathname)
|
||||
_, err := os.Create(pathname)
|
||||
if err != nil {
|
||||
log.Fatalf("failed: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func fetch(remoteFilename string, outFileName string) {
|
||||
if hasFileOrDir(outFileName) {
|
||||
if remoteFilename == outFileName {
|
||||
log.Printf("%q already exists, not overwriting\n", outFileName)
|
||||
return
|
||||
}
|
||||
log.Printf("%q already exists, downloading to %q\n", outFileName, remoteFilename)
|
||||
outFileName = remoteFilename
|
||||
}
|
||||
log.Printf("downloading %q to %q\n", remoteFilename, outFileName)
|
||||
|
||||
url, err := url.JoinPath(baseURL, remoteFilename)
|
||||
if err != nil {
|
||||
log.Fatalf("unexpected error: %s\n", err)
|
||||
}
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Fatalf("http request failed: %s\n", err)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
resp.Body.Close()
|
||||
log.Fatalf("error reading response body: %s\n", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(outFileName, body, 0o644)
|
||||
if err != nil {
|
||||
resp.Body.Close()
|
||||
log.Fatalf("failed to write to file: %s\n", err)
|
||||
}
|
||||
|
||||
log.Print("done")
|
||||
|
||||
resp.Body.Close()
|
||||
}
|
219
scripts/setup.sh
Executable file
219
scripts/setup.sh
Executable file
|
@ -0,0 +1,219 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Detect download tool
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
DOWNLOAD_TOOL="curl"
|
||||
DOWNLOAD_CMD="curl -fsSL -o"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
DOWNLOAD_TOOL="wget"
|
||||
DOWNLOAD_CMD="wget -qO"
|
||||
else
|
||||
read -p "Neither curl nor wget is installed, install curl? (y/n): " INSTALL
|
||||
if [ "$INSTALL" == "y" ]; then
|
||||
install_pkg "curl"
|
||||
else
|
||||
echo "Error: Neither curl nor wget is installed. Please install one of them and try again."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Using ${DOWNLOAD_TOOL} for downloads"
|
||||
|
||||
get_default_branch() {
|
||||
local repo="$1" # Format: owner/repo
|
||||
local branch
|
||||
|
||||
if [ "$DOWNLOAD_TOOL" = "curl" ]; then
|
||||
branch=$(curl -sL "https://api.github.com/repos/${repo}" | grep -o '"default_branch": *"[^"]*"' | cut -d'"' -f4)
|
||||
elif [ "$DOWNLOAD_TOOL" = "wget" ]; then
|
||||
branch=$(wget -qO- "https://api.github.com/repos/${repo}" | grep -o '"default_branch": *"[^"]*"' | cut -d'"' -f4)
|
||||
fi
|
||||
|
||||
if [ -z "$branch" ]; then
|
||||
echo "main" # Fallback to 'main' if detection fails
|
||||
else
|
||||
echo "$branch"
|
||||
fi
|
||||
}
|
||||
|
||||
# Environment variables with defaults
|
||||
REPO="yusing/go-proxy"
|
||||
BRANCH=${BRANCH:-$(get_default_branch "$REPO")}
|
||||
REPO_URL="https://github.com/$REPO"
|
||||
WIKI_URL="${REPO_URL}/wiki"
|
||||
BASE_URL="${REPO_URL}/raw/${BRANCH}"
|
||||
|
||||
# Config paths
|
||||
CONFIG_BASE_PATH="config"
|
||||
DOT_ENV_PATH=".env"
|
||||
DOT_ENV_EXAMPLE_PATH=".env.example"
|
||||
COMPOSE_FILE_NAME="compose.yml"
|
||||
COMPOSE_EXAMPLE_FILE_NAME="compose.example.yml"
|
||||
CONFIG_FILE_NAME="config.yml"
|
||||
CONFIG_EXAMPLE_FILE_NAME="config.example.yml"
|
||||
|
||||
echo "Setting up GoDoxy"
|
||||
echo "Branch: ${BRANCH}"
|
||||
|
||||
install_pkg() {
|
||||
# detect package manager
|
||||
if command -v apt >/dev/null 2>&1; then
|
||||
apt install -y "$1"
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
yum install -y "$1"
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
pacman -S --noconfirm "$1"
|
||||
else
|
||||
echo "Error: No supported package manager found"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_pkg() {
|
||||
local cmd="$1"
|
||||
local pkg="$2"
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
# check if user is root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Error: $pkg is not installed and you are not running as root. Please install it and try again."
|
||||
exit 1
|
||||
fi
|
||||
read -p "$pkg is not installed, install it? (y/n): " INSTALL
|
||||
if [ "$INSTALL" == "y" ]; then
|
||||
install_pkg "$pkg"
|
||||
else
|
||||
echo "Error: $pkg is not installed. Please install it and try again."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if file/directory exists
|
||||
has_file_or_dir() {
|
||||
[ -e "$1" ]
|
||||
}
|
||||
|
||||
# Function to create directory
|
||||
mkdir_if_not_exists() {
|
||||
if [ ! -d "$1" ]; then
|
||||
echo "Creating directory \"$1\""
|
||||
mkdir -p "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create empty file
|
||||
touch_if_not_exists() {
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "Creating file \"$1\""
|
||||
touch "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to download file
|
||||
fetch_file() {
|
||||
local remote_file="$1"
|
||||
local out_file="$2"
|
||||
|
||||
if has_file_or_dir "$out_file"; then
|
||||
if [ "$remote_file" = "$out_file" ]; then
|
||||
echo "\"$out_file\" already exists, not overwriting"
|
||||
return
|
||||
fi
|
||||
read -p "Do you want to overwrite \"$out_file\"? (y/n): " OVERWRITE
|
||||
if [ "$OVERWRITE" != "y" ]; then
|
||||
echo "Skipping \"$remote_file\""
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Downloading \"$remote_file\" to \"$out_file\""
|
||||
if ! $DOWNLOAD_CMD "$out_file" "${BASE_URL}/${remote_file}"; then
|
||||
echo "Error: Failed to download ${remote_file}"
|
||||
rm -f "$out_file" # Clean up partial download
|
||||
exit 1
|
||||
fi
|
||||
echo "Done"
|
||||
}
|
||||
|
||||
ask_while_empty() {
|
||||
local prompt="$1"
|
||||
local var_name="$2"
|
||||
local value=""
|
||||
while [ -z "$value" ]; do
|
||||
read -p "$prompt" value
|
||||
if [ -z "$value" ]; then
|
||||
echo "Error: $var_name cannot be empty, please try again"
|
||||
fi
|
||||
done
|
||||
eval "$var_name=\"$value\""
|
||||
}
|
||||
|
||||
check_pkg "openssl" "openssl"
|
||||
check_pkg "docker" "docker-ce"
|
||||
|
||||
# Setup required configurations
|
||||
# 1. Config base directory
|
||||
mkdir_if_not_exists "$CONFIG_BASE_PATH"
|
||||
|
||||
# 2. .env file
|
||||
fetch_file "$DOT_ENV_EXAMPLE_PATH" "$DOT_ENV_PATH"
|
||||
# set random JWT secret
|
||||
JWT_SECRET=$(openssl rand -base64 32)
|
||||
sed -i "s/GODOXY_API_JWT_SECRET=.*/GODOXY_API_JWT_SECRET=${JWT_SECRET}/" "$DOT_ENV_PATH"
|
||||
|
||||
# 3. docker-compose.yml
|
||||
fetch_file "$COMPOSE_EXAMPLE_FILE_NAME" "$COMPOSE_FILE_NAME"
|
||||
|
||||
# 4. config.yml
|
||||
fetch_file "$CONFIG_EXAMPLE_FILE_NAME" "${CONFIG_BASE_PATH}/${CONFIG_FILE_NAME}"
|
||||
|
||||
# 5. setup authentication
|
||||
|
||||
# ask for user and password
|
||||
echo "Setting up login user"
|
||||
ask_while_empty "Enter login username: " LOGIN_USERNAME
|
||||
ask_while_empty "Enter login password: " LOGIN_PASSWORD
|
||||
echo "Setting up login user \"$LOGIN_USERNAME\" with password \"$LOGIN_PASSWORD\""
|
||||
sed -i "s/GODOXY_API_USERNAME=.*/GODOXY_API_USERNAME=${LOGIN_USERNAME}/" "$DOT_ENV_PATH"
|
||||
sed -i "s/GODOXY_API_PASSWORD=.*/GODOXY_API_PASSWORD=${LOGIN_PASSWORD}/" "$DOT_ENV_PATH"
|
||||
|
||||
# 6. setup autocert
|
||||
|
||||
# ask if want to enable autocert
|
||||
echo "Setting up autocert for SSL certificate"
|
||||
ask_while_empty "Do you want to enable autocert? (y/n): " ENABLE_AUTOCERT
|
||||
|
||||
# quit if not using autocert
|
||||
if [ "$ENABLE_AUTOCERT" == "y" ]; then
|
||||
# ask for domain
|
||||
echo "Setting up autocert"
|
||||
ask_while_empty "Enter domain (e.g. example.com): " DOMAIN
|
||||
|
||||
# ask for email
|
||||
ask_while_empty "Enter email for Let's Encrypt: " EMAIL
|
||||
|
||||
# ask if using cloudflare
|
||||
ask_while_empty "Are you using cloudflare? (y/n): " USE_CLOUDFLARE
|
||||
|
||||
# ask for cloudflare api key
|
||||
if [ "$USE_CLOUDFLARE" = "y" ]; then
|
||||
ask_while_empty "Enter cloudflare api key: " CLOUDFLARE_API_KEY
|
||||
cat <<EOF >>"$CONFIG_BASE_PATH/$CONFIG_FILE_NAME"
|
||||
autocert:
|
||||
provider: cloudflare
|
||||
email: $EMAIL
|
||||
domains:
|
||||
- "*.${DOMAIN}"
|
||||
- "${DOMAIN}"
|
||||
options:
|
||||
auth_token: "$CLOUDFLARE_API_KEY"
|
||||
EOF
|
||||
else
|
||||
echo "Not using cloudflare, skipping autocert setup"
|
||||
echo "Please refer to ${WIKI_URL}/Supported-DNS-01-Providers for more information"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Setup finished"
|
Loading…
Add table
Reference in a new issue