fix: финализация fix6 для production runtime и reconfigure
This commit is contained in:
@@ -71,8 +71,8 @@ https://git.ext.flamy.studio/flamy_dev/HY2XS_flamy.git
|
|||||||
После установки применяются команды оркестратора:
|
После установки применяются команды оркестратора:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
hy2xs-orchestrator reconfigure --package-dir /opt/hy2xs-package --config /etc/hy2xs/hy2xs.env --dry-run
|
hy2xs-orchestrator reconfigure --package-dir /usr/local/lib/hy2xs/package --config /etc/hy2xs/hy2xs.env --dry-run
|
||||||
hy2xs-orchestrator reconfigure --package-dir /opt/hy2xs-package --config /etc/hy2xs/hy2xs.env --apply
|
hy2xs-orchestrator reconfigure --package-dir /usr/local/lib/hy2xs/package --config /etc/hy2xs/hy2xs.env --apply
|
||||||
```
|
```
|
||||||
|
|
||||||
Ключевые инварианты:
|
Ключевые инварианты:
|
||||||
|
|||||||
@@ -54,23 +54,11 @@ func InitSql(port string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if port != "" {
|
if port != "" {
|
||||||
var result string
|
|
||||||
db, err := sqliteDB.DB()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.QueryRow("SELECT value from config where key = 'H_UI_WEB_PORT' limit 1").Scan(&result); err != nil {
|
|
||||||
logrus.Errorf("sqlite exec err: %v", err)
|
|
||||||
return errors.New("sqlite exec err")
|
|
||||||
}
|
|
||||||
|
|
||||||
if result == "8081" {
|
|
||||||
if tx := sqliteDB.Exec("UPDATE config set value = ? where key = 'H_UI_WEB_PORT'", port); tx.Error != nil {
|
if tx := sqliteDB.Exec("UPDATE config set value = ? where key = 'H_UI_WEB_PORT'", port); tx.Error != nil {
|
||||||
logrus.Errorf("sqlite exec err: %v", tx.Error)
|
logrus.Errorf("sqlite exec err: %v", tx.Error)
|
||||||
return errors.New("sqlite exec err")
|
return errors.New("sqlite exec err")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := ensureAccountSchema(); err != nil {
|
if err := ensureAccountSchema(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"hy2xs-admin/model/constant"
|
|
||||||
"hy2xs-admin/util"
|
|
||||||
"os/exec"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Hysteria2Process struct {
|
|
||||||
process
|
|
||||||
binPath string
|
|
||||||
configPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
var mutexHysteria2 sync.Mutex
|
|
||||||
var cmdHysteria2 exec.Cmd
|
|
||||||
var hysteria2Instance *Hysteria2Process
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
hysteria2Instance = &Hysteria2Process{process{mutex: &mutexHysteria2, cmd: &cmdHysteria2}, util.GetHysteria2BinPath(), constant.Hysteria2ConfigPath}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHysteria2Instance() *Hysteria2Process {
|
|
||||||
return hysteria2Instance
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hysteria2Process) IsRunning() bool {
|
|
||||||
return h.isRunning()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hysteria2Process) StartHysteria2() error {
|
|
||||||
if err := h.start(h.binPath, "-c", h.configPath, "server"); err != nil {
|
|
||||||
_ = util.RemoveFile(h.configPath)
|
|
||||||
logrus.Errorf("start hysteria2 err: %v", err)
|
|
||||||
return errors.New("start hysteria2 err")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hysteria2Process) StopHysteria2() error {
|
|
||||||
if err := h.stop(); err != nil {
|
|
||||||
logrus.Errorf("stop hysteria2 err: %v", err)
|
|
||||||
return errors.New("stop hysteria2 err")
|
|
||||||
}
|
|
||||||
_ = util.RemoveFile(h.configPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hysteria2Process) Release() error {
|
|
||||||
if err := h.release(); err != nil {
|
|
||||||
logrus.Errorf("release hysteria2 err: %v", err)
|
|
||||||
return errors.New("release hysteria2 err")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -108,6 +108,7 @@
|
|||||||
- `HY2XS_ADMIN_INITIAL_PASSWORD` используется только для первичного bootstrap seed;
|
- `HY2XS_ADMIN_INITIAL_PASSWORD` используется только для первичного bootstrap seed;
|
||||||
- `HY2XS_ADMIN_CON_PASS` — отдельная runtime-сущность для Hysteria auth/smoke;
|
- `HY2XS_ADMIN_CON_PASS` — отдельная runtime-сущность для Hysteria auth/smoke;
|
||||||
- bootstrap secret хранится в явном формате `KEY=VALUE` (`ADMIN_USER`, `ADMIN_INITIAL_PASSWORD`, `ADMIN_CON_PASS`), права `0600`;
|
- bootstrap secret хранится в явном формате `KEY=VALUE` (`ADMIN_USER`, `ADMIN_INITIAL_PASSWORD`, `ADMIN_CON_PASS`), права `0600`;
|
||||||
|
- `HY2XS_FORCE_PASSWORD_CHANGE` в production baseline установлен в `false` (forced UX-flow пока не реализован);
|
||||||
- после первичного seed перезапуски `hy2xs-admin` не должны переопределять пароль admin и `con_pass`.
|
- после первичного seed перезапуски `hy2xs-admin` не должны переопределять пароль admin и `con_pass`.
|
||||||
|
|
||||||
## Что нельзя делать
|
## Что нельзя делать
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ export function parseRuntimeEnv(content: string): RuntimeConfig {
|
|||||||
hysteriaBindHost: normalizeIpv4Host("HY2XS_HYSTERIA_BIND_HOST", env.HY2XS_HYSTERIA_BIND_HOST || "0.0.0.0"),
|
hysteriaBindHost: normalizeIpv4Host("HY2XS_HYSTERIA_BIND_HOST", env.HY2XS_HYSTERIA_BIND_HOST || "0.0.0.0"),
|
||||||
hysteriaPort,
|
hysteriaPort,
|
||||||
hysteriaAuthMode: "http",
|
hysteriaAuthMode: "http",
|
||||||
hysteriaAuthUrl: env.HY2XS_HYSTERIA_AUTH_URL || `http://127.0.0.1:${uiPort}/hui/hysteria2/auth`,
|
|
||||||
hysteriaTrafficStatsHost: normalizeIpv4Host(
|
hysteriaTrafficStatsHost: normalizeIpv4Host(
|
||||||
"HY2XS_HYSTERIA_TRAFFIC_STATS_HOST",
|
"HY2XS_HYSTERIA_TRAFFIC_STATS_HOST",
|
||||||
env.HY2XS_HYSTERIA_TRAFFIC_STATS_HOST || "127.0.0.1"
|
env.HY2XS_HYSTERIA_TRAFFIC_STATS_HOST || "127.0.0.1"
|
||||||
@@ -221,7 +220,6 @@ export function renderRuntimeEnv(config: RuntimeConfig): string {
|
|||||||
`HY2XS_HYSTERIA_BIND_HOST=${config.hysteriaBindHost}`,
|
`HY2XS_HYSTERIA_BIND_HOST=${config.hysteriaBindHost}`,
|
||||||
`HY2XS_HYSTERIA_PORT=${config.hysteriaPort}`,
|
`HY2XS_HYSTERIA_PORT=${config.hysteriaPort}`,
|
||||||
"HY2XS_HYSTERIA_AUTH_MODE=http",
|
"HY2XS_HYSTERIA_AUTH_MODE=http",
|
||||||
`HY2XS_HYSTERIA_AUTH_URL=${config.hysteriaAuthUrl}`,
|
|
||||||
`HY2XS_HYSTERIA_TRAFFIC_STATS_HOST=${config.hysteriaTrafficStatsHost}`,
|
`HY2XS_HYSTERIA_TRAFFIC_STATS_HOST=${config.hysteriaTrafficStatsHost}`,
|
||||||
`HY2XS_HYSTERIA_TRAFFIC_STATS_PORT=${config.hysteriaTrafficStatsPort}`,
|
`HY2XS_HYSTERIA_TRAFFIC_STATS_PORT=${config.hysteriaTrafficStatsPort}`,
|
||||||
`HY2XS_HYSTERIA_TRAFFIC_STATS_SECRET=${config.hysteriaTrafficStatsSecret}`,
|
`HY2XS_HYSTERIA_TRAFFIC_STATS_SECRET=${config.hysteriaTrafficStatsSecret}`,
|
||||||
|
|||||||
@@ -22,12 +22,15 @@ export async function applyFirewall(context: InstallContext): Promise<void> {
|
|||||||
ACME_RULE: acmeRule
|
ACME_RULE: acmeRule
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await runVisible`cp -a /etc/nftables.conf /etc/nftables.conf.hy2xs.bak 2>/dev/null || true`;
|
||||||
await runVisible`cp -a /etc/nftables.d/hy2xs.nft /etc/nftables.d/hy2xs.nft.bak 2>/dev/null || true`;
|
await runVisible`cp -a /etc/nftables.d/hy2xs.nft /etc/nftables.d/hy2xs.nft.bak 2>/dev/null || true`;
|
||||||
|
await runVisible`test -f /etc/nftables.d/hy2xs.nft && echo 1 > /etc/nftables.d/hy2xs.nft.existed || rm -f /etc/nftables.d/hy2xs.nft.existed`;
|
||||||
|
await runVisible`grep -q 'include "/etc/nftables.d/hy2xs.nft"' /etc/nftables.conf && echo 1 > /etc/nftables.d/hy2xs.nft.include.existed || rm -f /etc/nftables.d/hy2xs.nft.include.existed`;
|
||||||
await writeText("/etc/nftables.d/hy2xs.nft.candidate", rendered, 0o600);
|
await writeText("/etc/nftables.d/hy2xs.nft.candidate", rendered, 0o600);
|
||||||
await runVisible`nft -c -f /etc/nftables.d/hy2xs.nft.candidate`;
|
await runVisible`nft -c -f /etc/nftables.d/hy2xs.nft.candidate`;
|
||||||
|
|
||||||
if (context.config.firewallStagedApply) {
|
if (context.config.firewallStagedApply) {
|
||||||
await runVisible`systemd-run --unit hy2xs-fw-rollback --on-active=45s /bin/sh -c 'cp -a /etc/nftables.d/hy2xs.nft.bak /etc/nftables.d/hy2xs.nft 2>/dev/null || true; nft -f /etc/nftables.conf >/dev/null 2>&1 || true'`;
|
await runVisible`systemd-run --unit hy2xs-fw-rollback --on-active=45s /bin/sh -c 'cp -a /etc/nftables.conf.hy2xs.bak /etc/nftables.conf 2>/dev/null || true; if [ -f /etc/nftables.d/hy2xs.nft.existed ]; then cp -a /etc/nftables.d/hy2xs.nft.bak /etc/nftables.d/hy2xs.nft 2>/dev/null || true; else rm -f /etc/nftables.d/hy2xs.nft; fi; nft -f /etc/nftables.conf >/dev/null 2>&1 || true'`;
|
||||||
}
|
}
|
||||||
|
|
||||||
await runVisible`mv /etc/nftables.d/hy2xs.nft.candidate /etc/nftables.d/hy2xs.nft`;
|
await runVisible`mv /etc/nftables.d/hy2xs.nft.candidate /etc/nftables.d/hy2xs.nft`;
|
||||||
@@ -41,4 +44,6 @@ export async function applyFirewall(context: InstallContext): Promise<void> {
|
|||||||
await runVisible`systemctl stop hy2xs-fw-rollback || true`;
|
await runVisible`systemctl stop hy2xs-fw-rollback || true`;
|
||||||
await runVisible`systemctl reset-failed hy2xs-fw-rollback || true`;
|
await runVisible`systemctl reset-failed hy2xs-fw-rollback || true`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await runVisible`rm -f /etc/nftables.conf.hy2xs.bak /etc/nftables.d/hy2xs.nft.bak /etc/nftables.d/hy2xs.nft.existed /etc/nftables.d/hy2xs.nft.include.existed`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ export async function smoke(context: InstallContext): Promise<void> {
|
|||||||
await runVisible`! ss -H -ltn | grep -q '0.0.0.0:${context.config.uiPort} '`;
|
await runVisible`! ss -H -ltn | grep -q '0.0.0.0:${context.config.uiPort} '`;
|
||||||
}
|
}
|
||||||
await runVisible`ss -H -lun | grep -q '0.0.0.0:${context.config.hysteriaPort} '`;
|
await runVisible`ss -H -lun | grep -q '0.0.0.0:${context.config.hysteriaPort} '`;
|
||||||
await runVisible`! ss -H -ltnu | grep -q '\[::\]'`;
|
await runVisible`! ss -H -ltn | grep -q '\[::\]:${context.config.uiPort} '`;
|
||||||
|
await runVisible`! ss -H -lun | grep -q '\[::\]:${context.config.hysteriaPort} '`;
|
||||||
const invalidAuthResponse = await runSecret`curl -sS --max-time 5 -X POST -H 'Content-Type: application/json' --data '{"addr":"127.0.0.1:12345","auth":"invalid","tx":"0"}' http://127.0.0.1:${context.config.uiPort}/hui/hysteria2/auth`;
|
const invalidAuthResponse = await runSecret`curl -sS --max-time 5 -X POST -H 'Content-Type: application/json' --data '{"addr":"127.0.0.1:12345","auth":"invalid","tx":"0"}' http://127.0.0.1:${context.config.uiPort}/hui/hysteria2/auth`;
|
||||||
if (!/"ok"\s*:\s*false/.test(invalidAuthResponse)) {
|
if (!/"ok"\s*:\s*false/.test(invalidAuthResponse)) {
|
||||||
throw new Error(`unexpected auth response for invalid credentials: ${invalidAuthResponse}`);
|
throw new Error(`unexpected auth response for invalid credentials: ${invalidAuthResponse}`);
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ export type RuntimeConfig = {
|
|||||||
hysteriaBindHost: string;
|
hysteriaBindHost: string;
|
||||||
hysteriaPort: number;
|
hysteriaPort: number;
|
||||||
hysteriaAuthMode: "http";
|
hysteriaAuthMode: "http";
|
||||||
hysteriaAuthUrl: string;
|
|
||||||
hysteriaTrafficStatsHost: string;
|
hysteriaTrafficStatsHost: string;
|
||||||
hysteriaTrafficStatsPort: number;
|
hysteriaTrafficStatsPort: number;
|
||||||
hysteriaTrafficStatsSecret: string;
|
hysteriaTrafficStatsSecret: string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# HY2XS canonical production runtime config (packaged baseline)
|
# HY2XS canonical production runtime config (packaged baseline)
|
||||||
HY2XS_IPV6_ENABLED=false
|
HY2XS_IPV6_ENABLED=false
|
||||||
HY2XS_DOMAIN=replace-with-your-domain.example
|
HY2XS_DOMAIN=uk.api.withen.pro
|
||||||
HY2XS_PUBLIC_HOST=replace-with-your-domain.example
|
HY2XS_PUBLIC_HOST=uk.api.withen.pro
|
||||||
HY2XS_PUBLIC_PORT=443
|
HY2XS_PUBLIC_PORT=443
|
||||||
HY2XS_SSH_PORT=22
|
HY2XS_SSH_PORT=22
|
||||||
HY2XS_FIREWALL_ENABLED=true
|
HY2XS_FIREWALL_ENABLED=true
|
||||||
@@ -15,13 +15,12 @@ HY2XS_FORCE_PASSWORD_CHANGE=false
|
|||||||
HY2XS_ALLOW_SELF_SIGNED_DEV=false
|
HY2XS_ALLOW_SELF_SIGNED_DEV=false
|
||||||
HY2XS_TLS_MODE=acme
|
HY2XS_TLS_MODE=acme
|
||||||
HY2XS_ACME_TYPE=http
|
HY2XS_ACME_TYPE=http
|
||||||
HY2XS_ACME_EMAIL=replace-with-your-email@example.com
|
HY2XS_ACME_EMAIL=admin@withen.pro
|
||||||
HY2XS_TLS_CERT_PATH=/etc/hysteria/server.crt
|
HY2XS_TLS_CERT_PATH=/etc/hysteria/server.crt
|
||||||
HY2XS_TLS_KEY_PATH=/etc/hysteria/server.key
|
HY2XS_TLS_KEY_PATH=/etc/hysteria/server.key
|
||||||
HY2XS_HYSTERIA_BIND_HOST=0.0.0.0
|
HY2XS_HYSTERIA_BIND_HOST=0.0.0.0
|
||||||
HY2XS_HYSTERIA_PORT=443
|
HY2XS_HYSTERIA_PORT=443
|
||||||
HY2XS_HYSTERIA_AUTH_MODE=http
|
HY2XS_HYSTERIA_AUTH_MODE=http
|
||||||
HY2XS_HYSTERIA_AUTH_URL=http://127.0.0.1:8080/hui/hysteria2/auth
|
|
||||||
HY2XS_HYSTERIA_TRAFFIC_STATS_HOST=127.0.0.1
|
HY2XS_HYSTERIA_TRAFFIC_STATS_HOST=127.0.0.1
|
||||||
HY2XS_HYSTERIA_TRAFFIC_STATS_PORT=36712
|
HY2XS_HYSTERIA_TRAFFIC_STATS_PORT=36712
|
||||||
HY2XS_HYSTERIA_TRAFFIC_STATS_SECRET=__GENERATE__
|
HY2XS_HYSTERIA_TRAFFIC_STATS_SECRET=__GENERATE__
|
||||||
|
|||||||
@@ -13,7 +13,13 @@
|
|||||||
Запускать от root:
|
Запускать от root:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./install.sh --non-interactive --domain example.com
|
./install.sh --non-interactive
|
||||||
|
```
|
||||||
|
|
||||||
|
С внешним source-config:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./install.sh --config /root/custom-hy2xs.env --non-interactive
|
||||||
```
|
```
|
||||||
|
|
||||||
В baseline нет target-side JavaScript, TypeScript, frontend или Go build step.
|
В baseline нет target-side JavaScript, TypeScript, frontend или Go build step.
|
||||||
|
|||||||
+11
-1
@@ -5,6 +5,7 @@ PACKAGE_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|||||||
ORCHESTRATOR="$PACKAGE_DIR/orchestrator/hy2xs-orchestrator"
|
ORCHESTRATOR="$PACKAGE_DIR/orchestrator/hy2xs-orchestrator"
|
||||||
ORCHESTRATOR_INSTALL_PATH="/usr/local/lib/hy2xs/hy2xs-orchestrator"
|
ORCHESTRATOR_INSTALL_PATH="/usr/local/lib/hy2xs/hy2xs-orchestrator"
|
||||||
ORCHESTRATOR_SYMLINK="/usr/local/bin/hy2xs-orchestrator"
|
ORCHESTRATOR_SYMLINK="/usr/local/bin/hy2xs-orchestrator"
|
||||||
|
RUNTIME_PACKAGE_DIR="/usr/local/lib/hy2xs/package"
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
printf '[hy2xs-install] %s\n' "$*"
|
printf '[hy2xs-install] %s\n' "$*"
|
||||||
@@ -27,6 +28,15 @@ install -d -m 0755 /usr/local/lib/hy2xs
|
|||||||
install -m 0755 "$ORCHESTRATOR" "$ORCHESTRATOR_INSTALL_PATH"
|
install -m 0755 "$ORCHESTRATOR" "$ORCHESTRATOR_INSTALL_PATH"
|
||||||
ln -sf "$ORCHESTRATOR_INSTALL_PATH" "$ORCHESTRATOR_SYMLINK"
|
ln -sf "$ORCHESTRATOR_INSTALL_PATH" "$ORCHESTRATOR_SYMLINK"
|
||||||
|
|
||||||
|
log "installing runtime package assets to: $RUNTIME_PACKAGE_DIR"
|
||||||
|
rm -rf "$RUNTIME_PACKAGE_DIR"
|
||||||
|
install -d -m 0755 "$RUNTIME_PACKAGE_DIR"
|
||||||
|
cp -a "$PACKAGE_DIR/config" "$RUNTIME_PACKAGE_DIR/"
|
||||||
|
cp -a "$PACKAGE_DIR/docs" "$RUNTIME_PACKAGE_DIR/"
|
||||||
|
cp -a "$PACKAGE_DIR/systemd" "$RUNTIME_PACKAGE_DIR/"
|
||||||
|
cp -a "$PACKAGE_DIR/templates" "$RUNTIME_PACKAGE_DIR/"
|
||||||
|
cp -a "$PACKAGE_DIR/metadata" "$RUNTIME_PACKAGE_DIR/"
|
||||||
|
|
||||||
log "package directory: $PACKAGE_DIR"
|
log "package directory: $PACKAGE_DIR"
|
||||||
log "starting install-only orchestrator"
|
log "starting install-only orchestrator"
|
||||||
exec "$ORCHESTRATOR_INSTALL_PATH" install --package-dir "$PACKAGE_DIR" "$@"
|
exec "$ORCHESTRATOR_INSTALL_PATH" install --package-dir "$RUNTIME_PACKAGE_DIR" "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user