fix: use Go tool for cert upload, fix apps.yaml YAML format
This commit is contained in:
parent
6ea3164d72
commit
aa29d363ce
3 changed files with 185 additions and 33 deletions
84
deploy.sh
84
deploy.sh
|
|
@ -149,10 +149,6 @@ if [ "$GREENFIELD" = true ]; then
|
|||
echo "[INFO] Version: $(cat $TARGET_DIR/VERSION)"
|
||||
fi
|
||||
|
||||
# Generate stateless API token for Zoraxy
|
||||
DEPLOY_TOKEN=$(openssl rand -hex 32 2>/dev/null || date +%s | sha256sum | head -c 64)
|
||||
echo "[*] Stateless API token generated"
|
||||
|
||||
# Write ACME config + BoltDB (before Zoraxy starts, db not locked)
|
||||
mkdir -p "$TARGET_DIR/config/zoraxy/conf"
|
||||
cat > "$TARGET_DIR/config/zoraxy/conf/acme_conf.json" <<EOF
|
||||
|
|
@ -165,17 +161,15 @@ if [ "$GREENFIELD" = true ]; then
|
|||
}
|
||||
EOF
|
||||
|
||||
# Seed API token and admin into BoltDB
|
||||
# Seed admin into BoltDB
|
||||
if [ -f "$TOOL_BIN" ]; then
|
||||
mkdir -p "$TARGET_DIR/data/zoraxy"
|
||||
touch "$TARGET_DIR/data/zoraxy/sys.db"
|
||||
"$TOOL_BIN" db --db "$TARGET_DIR/data/zoraxy/sys.db" \
|
||||
--set "auth:api_key:${DEPLOY_TOKEN}:{\"username\":\"${ADMIN_USERNAME:-master}\",\"permission\":\"admin\"}" 2>&1 || true
|
||||
"$TOOL_BIN" db --db "$TARGET_DIR/data/zoraxy/sys.db" \
|
||||
--set "system:admin:{\"username\":\"${ADMIN_USERNAME:-master}\"}" 2>&1 || true
|
||||
"$TOOL_BIN" db --db "$TARGET_DIR/data/zoraxy/sys.db" \
|
||||
--set "zorxauth:options:{\"enable_auth_gateway\":true,\"sso_redirect_url\":\"https://${APP_SUB}.${DOMAIN}/\"}" 2>&1 || true
|
||||
echo " [OK] API token + admin seeded into BoltDB"
|
||||
echo " [OK] Admin seeded into BoltDB"
|
||||
fi
|
||||
|
||||
# Start Zoraxy
|
||||
|
|
@ -189,23 +183,19 @@ EOF
|
|||
sleep 2
|
||||
done
|
||||
|
||||
# Register certificates using stateless API token
|
||||
echo "[*] Registering certificates via API token..."
|
||||
CERTS_DIR="$TARGET_DIR/config/zoraxy/conf/certs"
|
||||
AUTH_HEADER="Authorization: Bearer ${DEPLOY_TOKEN}"
|
||||
for SUB in $APP_SUB $DNS_SUB $WWW_SUB; do
|
||||
FQDN="${SUB}.${DOMAIN}"
|
||||
CRT_FILE="$CERTS_DIR/${FQDN}.pem"
|
||||
if [ ! -f "$CRT_FILE" ]; then echo " SKIP $FQDN (no .pem file)"; continue; fi
|
||||
R=$(curl -s --max-time 10 -X POST "http://127.0.0.1:8000/api/cert/upload?ktype=pub&domain=${FQDN}" \
|
||||
-H "${AUTH_HEADER}" -H "Content-Type: application/json" \
|
||||
--data-binary "@${CRT_FILE}" 2>&1) || true
|
||||
if echo "$R" | grep -qi '"success"\|"ok"\|^{}$'; then
|
||||
echo " [OK] $FQDN registered"
|
||||
# Register certificates using Go tool (handles CSRF/session properly)
|
||||
echo "[*] Registering certificates via Go tool..."
|
||||
REG_TOOL="$REPO_DIR/tools/register-certs/register-certs"
|
||||
if [ -f "$REG_TOOL" ]; then
|
||||
cd "$REPO_DIR/tools/register-certs" && go build -o register-certs . 2>/dev/null && cd "$REPO_DIR"
|
||||
"$REG_TOOL" "${ADMIN_USERNAME:-master}" "${ADMIN_PASSWORD:-9Aku7MfklZU9ldnZ}" \
|
||||
${APP_SUB}.${DOMAIN} ${DNS_SUB}.${DOMAIN} ${WWW_SUB}.${DOMAIN} 2>&1 || true
|
||||
else
|
||||
echo " [WARN] $FQDN: $(echo $R | head -c 80)"
|
||||
echo " [WARN] Register tool not found, building..."
|
||||
cd "$REPO_DIR/tools/register-certs"
|
||||
go build -o register-certs . 2>&1 || true
|
||||
cd "$REPO_DIR"
|
||||
fi
|
||||
done
|
||||
|
||||
# Stop Zoraxy to write proxy configs
|
||||
|
||||
|
|
@ -255,14 +245,46 @@ ZORAXY_AUTH
|
|||
echo "[*] Generating apps.yaml..."
|
||||
cat > "$TARGET_DIR/config/nextworkspace/apps.yaml" <<EOF
|
||||
apps:
|
||||
- name: "OpenCloud" subtitle: "File Storage" path: "/cloud" upstream: "http://127.0.0.1:9100" icon: "cloud"
|
||||
- name: "Euro Office" subtitle: "Collaborative Suite" path: "/office" upstream: "http://127.0.0.1:9200" icon: "office"
|
||||
- name: "ERPNext" subtitle: "Enterprise ERP" path: "/erp" upstream: "http://127.0.0.1:9300" icon: "erp"
|
||||
- name: "Matrix Chat" subtitle: "Team Communication" path: "/chat" upstream: "http://127.0.0.1:9400" icon: "chat"
|
||||
- name: "Jitsi" subtitle: "Video Conferencing" path: "/meet" upstream: "http://127.0.0.1:9500" icon: "video"
|
||||
- name: "Webmail" subtitle: "Email Client" path: "/mail" upstream: "http://127.0.0.1:9600" icon: "mail"
|
||||
- name: "AI Chat" subtitle: "Open WebUI" path: "/ai" upstream: "http://127.0.0.1:9700" icon: "bot"
|
||||
- name: "Portainer" subtitle: "Container Management" path: "/admin" upstream: "http://127.0.0.1:9800" icon: "admin"
|
||||
- name: "OpenCloud"
|
||||
subtitle: "File Storage"
|
||||
path: "/cloud"
|
||||
upstream: "http://127.0.0.1:9100"
|
||||
icon: "cloud"
|
||||
- name: "Euro Office"
|
||||
subtitle: "Collaborative Suite"
|
||||
path: "/office"
|
||||
upstream: "http://127.0.0.1:9200"
|
||||
icon: "office"
|
||||
- name: "ERPNext"
|
||||
subtitle: "Enterprise ERP"
|
||||
path: "/erp"
|
||||
upstream: "http://127.0.0.1:9300"
|
||||
icon: "erp"
|
||||
- name: "Matrix Chat"
|
||||
subtitle: "Team Communication"
|
||||
path: "/chat"
|
||||
upstream: "http://127.0.0.1:9400"
|
||||
icon: "chat"
|
||||
- name: "Jitsi"
|
||||
subtitle: "Video Conferencing"
|
||||
path: "/meet"
|
||||
upstream: "http://127.0.0.1:9500"
|
||||
icon: "video"
|
||||
- name: "Webmail"
|
||||
subtitle: "Email Client"
|
||||
path: "/mail"
|
||||
upstream: "http://127.0.0.1:9600"
|
||||
icon: "mail"
|
||||
- name: "AI Chat"
|
||||
subtitle: "Open WebUI"
|
||||
path: "/ai"
|
||||
upstream: "http://127.0.0.1:9700"
|
||||
icon: "bot"
|
||||
- name: "Portainer"
|
||||
subtitle: "Container Management"
|
||||
path: "/admin"
|
||||
upstream: "http://127.0.0.1:9800"
|
||||
icon: "admin"
|
||||
EOF
|
||||
|
||||
# Remove stale proxy.old dirs created by Zoraxy
|
||||
|
|
|
|||
130
tools/register-certs/main.go
Normal file
130
tools/register-certs/main.go
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 4 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s <username> <password> <domain> [domain...]\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
username := os.Args[1]
|
||||
password := os.Args[2]
|
||||
domains := os.Args[3:]
|
||||
|
||||
jar, _ := cookiejar.New(nil)
|
||||
client := &http.Client{Jar: jar}
|
||||
|
||||
// Step 1: Fetch login page to get CSRF token
|
||||
resp, err := client.Get("http://127.0.0.1:8000/login.html")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "FAIL: fetching login page: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
re := regexp.MustCompile(`content="([^"]+)"`)
|
||||
match := re.FindStringSubmatch(string(body))
|
||||
var csrf string
|
||||
for _, m := range match {
|
||||
if len(m) > 20 {
|
||||
csrf = m
|
||||
break
|
||||
}
|
||||
}
|
||||
if csrf == "" {
|
||||
fmt.Fprintf(os.Stderr, "FAIL: could not extract CSRF token\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Step 2: Login
|
||||
form := url.Values{"username": {username}, "password": {password}}
|
||||
req, _ := http.NewRequest("POST", "http://127.0.0.1:8000/api/auth/login", strings.NewReader(form.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("X-CSRF-Token", csrf)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "FAIL: login request: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
body, _ = io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 || !strings.Contains(string(body), `"ok"`) {
|
||||
fmt.Fprintf(os.Stderr, "FAIL: login failed (status=%d): %s\n", resp.StatusCode, strings.TrimSpace(string(body)))
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("OK: Logged in as %s\n", username)
|
||||
|
||||
// Step 3: Upload cert for each domain
|
||||
certsDir := "/opt/nextworkspace/config/zoraxy/conf/certs"
|
||||
success := true
|
||||
for _, domain := range domains {
|
||||
// Try .pem first, then .crt for backward compatibility
|
||||
certFile := certsDir + "/" + domain + ".pem"
|
||||
if _, err := os.Stat(certFile); os.IsNotExist(err) {
|
||||
certFile = certsDir + "/" + domain + ".crt"
|
||||
}
|
||||
certData, err := os.ReadFile(certFile)
|
||||
if err != nil {
|
||||
fmt.Printf("SKIP: %s (no cert file)\n", domain)
|
||||
continue
|
||||
}
|
||||
|
||||
// Get fresh CSRF for each upload
|
||||
resp, err := client.Get("http://127.0.0.1:8000/login.html")
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: %s csrf fetch failed: %v\n", domain, err)
|
||||
continue
|
||||
}
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
match = re.FindStringSubmatch(string(body))
|
||||
csrf = ""
|
||||
for _, m := range match {
|
||||
if len(m) > 20 {
|
||||
csrf = m
|
||||
break
|
||||
}
|
||||
}
|
||||
if csrf == "" {
|
||||
fmt.Printf("WARN: %s no CSRF token\n", domain)
|
||||
continue
|
||||
}
|
||||
|
||||
uploadURL := fmt.Sprintf("http://127.0.0.1:8000/api/cert/upload?ktype=pub&domain=%s", domain)
|
||||
req, _ := http.NewRequest("POST", uploadURL, strings.NewReader(string(certData)))
|
||||
req.Header.Set("X-CSRF-Token", csrf)
|
||||
req.Header.Set("Content-Type", "application/x-pem-file")
|
||||
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("WARN: %s upload failed: %v\n", domain, err)
|
||||
success = false
|
||||
continue
|
||||
}
|
||||
body, _ = io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == 200 {
|
||||
fmt.Printf("OK: %s cert uploaded\n", domain)
|
||||
} else {
|
||||
fmt.Printf("FAIL: %s (status=%d): %s\n", domain, resp.StatusCode, strings.TrimSpace(string(body)))
|
||||
success = false
|
||||
}
|
||||
}
|
||||
|
||||
if !success {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
BIN
tools/register-certs/register-certs
Executable file
BIN
tools/register-certs/register-certs
Executable file
Binary file not shown.
Loading…
Reference in a new issue