diff --git a/apps/frontend/src/views/config/list/index.vue b/apps/frontend/src/views/config/list/index.vue
index 1c1a2b1..7ecd611 100644
--- a/apps/frontend/src/views/config/list/index.vue
+++ b/apps/frontend/src/views/config/list/index.vue
@@ -43,6 +43,13 @@
+
+
@@ -61,6 +69,7 @@
@@ -75,7 +84,7 @@
/>
-
+
- {{ t("config.useHysteria2Cert") }}
-
-
-
- {{ t("config.uploadCrtFile") }}
-
-
-
-
- {{ t("config.uploadKeyFile") }}
-
-
{
dataFormRef.value.validate((valid: boolean) => {
if (valid) {
- if (state.huiHttps) {
- if (!state.dataForm.huiCrtPath || !state.dataForm.huiKeyPath) {
- ElMessage.error("crt and key required");
- return;
- }
- }
-
- if (!state.huiHttps) {
- state.dataForm.huiCrtPath = "";
- state.dataForm.huiKeyPath = "";
- }
-
let configs: ConfigsUpdateDto[] = [
- {
- key: huiWebPortKey,
- value: state.dataForm.huiWebPort,
- },
- {
- key: huiWebContext,
- value: state.dataForm.huiWebContext,
- },
{
key: hysteria2TrafficTimeKey,
value: state.dataForm.hysteria2TrafficTime,
},
- {
- key: huiCrtPathKey,
- value: state.dataForm.huiCrtPath,
- },
- {
- key: huiKeyPathKey,
- value: state.dataForm.huiKeyPath,
- },
{
key: resetTrafficCronKey,
value: state.dataForm.resetTrafficCron,
@@ -415,41 +351,6 @@ const handleExport = async () => {
}
};
-const setCertPath = async () => {
- try {
- const { data } = await hysteria2AcmePathApi();
- const { crtPath, keyPath } = data;
- state.dataForm.huiCrtPath = crtPath;
- state.dataForm.huiKeyPath = keyPath;
- } catch (e) {
- /* empty */
- }
-};
-
-const uploadCertFile = async (params: UploadRequestOptions) => {
- try {
- if (
- !params.file.name.endsWith(".crt") &&
- !params.file.name.endsWith(".key")
- ) {
- ElMessage.error("file format not supported");
- }
- if (params.file.size > 1024 * 1024) {
- ElMessage.error("the file is too big");
- }
- let formData = new FormData();
- formData.append("file", params.file);
- const { data } = await uploadCertFileApi(formData);
- if (params.file.name.endsWith(".crt")) {
- state.dataForm.huiCrtPath = data;
- } else if (params.file.name.endsWith(".key")) {
- state.dataForm.huiKeyPath = data;
- }
- } catch (e) {
- /* empty */
- }
-};
-
const handleRestartServer = async () => {
try {
ElMessageBox.confirm("Are you sure to restart panel?", "Warning", {
diff --git a/hy2xs_implementation_plan-no_git/02-target-repo-structure.txt b/hy2xs_implementation_plan-no_git/02-target-repo-structure.txt
index 3981bf9..0d26bd4 100644
--- a/hy2xs_implementation_plan-no_git/02-target-repo-structure.txt
+++ b/hy2xs_implementation_plan-no_git/02-target-repo-structure.txt
@@ -71,8 +71,8 @@ project/
│ ├── branding/
│ ├── patches/
│ └── BUILD_NOTES.md
-├── examples/
-│ └── post-install.env.example
+├── config/
+│ └── hy2xs.env
└── dist/
└── hy2xs-install-.tar.gz
diff --git a/hy2xs_implementation_plan-no_git/04-runtime-package-layout.txt b/hy2xs_implementation_plan-no_git/04-runtime-package-layout.txt
index 27d3483..2178f03 100644
--- a/hy2xs_implementation_plan-no_git/04-runtime-package-layout.txt
+++ b/hy2xs_implementation_plan-no_git/04-runtime-package-layout.txt
@@ -30,9 +30,9 @@ HY2XS: runtime package layout
- package.build_id
- checksums.txt
-7. docs/examples
+7. docs/config
- короткий README по установке
-- post-install.env.example
+- canonical runtime source config (hy2xs.env)
Что не должно быть в runtime package
- builder/
diff --git a/orchestrator/src/commands/reconfigure.ts b/orchestrator/src/commands/reconfigure.ts
index 17ff8a2..7dac97b 100644
--- a/orchestrator/src/commands/reconfigure.ts
+++ b/orchestrator/src/commands/reconfigure.ts
@@ -15,14 +15,28 @@ async function backupCurrentState(): Promise {
await runVisible`cp -a /etc/hysteria/config.yaml /etc/hy2xs/backups/config.yaml.bak 2>/dev/null || true`;
await runVisible`cp -a /etc/systemd/system/hy2xs-admin.service /etc/hy2xs/backups/hy2xs-admin.service.bak 2>/dev/null || true`;
await runVisible`cp -a /etc/systemd/system/hysteria-server.service /etc/hy2xs/backups/hysteria-server.service.bak 2>/dev/null || true`;
+ await runVisible`cp -a /etc/hy2xs/hy2xs.env /etc/hy2xs/backups/hy2xs.env.bak 2>/dev/null || true`;
+ await runVisible`cp -a /etc/hysteria/post-install.env /etc/hy2xs/backups/post-install.env.bak 2>/dev/null || true`;
+ await runVisible`cp -a /etc/nftables.conf /etc/hy2xs/backups/nftables.conf.bak 2>/dev/null || true`;
await runVisible`cp -a /etc/nftables.d/hy2xs.nft /etc/hy2xs/backups/hy2xs.nft.bak 2>/dev/null || true`;
+
+ await runVisible`test -f /etc/hy2xs/hy2xs.env && echo 1 > /etc/hy2xs/backups/hy2xs.env.existed || rm -f /etc/hy2xs/backups/hy2xs.env.existed`;
+ await runVisible`test -f /etc/hysteria/post-install.env && echo 1 > /etc/hy2xs/backups/post-install.env.existed || rm -f /etc/hy2xs/backups/post-install.env.existed`;
+ await runVisible`test -f /etc/nftables.conf && echo 1 > /etc/hy2xs/backups/nftables.conf.existed || rm -f /etc/hy2xs/backups/nftables.conf.existed`;
+ await runVisible`test -f /etc/nftables.d/hy2xs.nft && echo 1 > /etc/hy2xs/backups/hy2xs.nft.existed || rm -f /etc/hy2xs/backups/hy2xs.nft.existed`;
}
async function rollbackCurrentState(): Promise {
await runVisible`cp -a /etc/hy2xs/backups/config.yaml.bak /etc/hysteria/config.yaml 2>/dev/null || true`;
await runVisible`cp -a /etc/hy2xs/backups/hy2xs-admin.service.bak /etc/systemd/system/hy2xs-admin.service 2>/dev/null || true`;
await runVisible`cp -a /etc/hy2xs/backups/hysteria-server.service.bak /etc/systemd/system/hysteria-server.service 2>/dev/null || true`;
- await runVisible`cp -a /etc/hy2xs/backups/hy2xs.nft.bak /etc/nftables.d/hy2xs.nft 2>/dev/null || true`;
+
+ await runVisible`if [ -f /etc/hy2xs/backups/hy2xs.env.existed ]; then cp -a /etc/hy2xs/backups/hy2xs.env.bak /etc/hy2xs/hy2xs.env 2>/dev/null || true; else rm -f /etc/hy2xs/hy2xs.env; fi`;
+ await runVisible`if [ -f /etc/hy2xs/backups/post-install.env.existed ]; then cp -a /etc/hy2xs/backups/post-install.env.bak /etc/hysteria/post-install.env 2>/dev/null || true; else rm -f /etc/hysteria/post-install.env; fi`;
+ await runVisible`if [ -f /etc/hy2xs/backups/nftables.conf.existed ]; then cp -a /etc/hy2xs/backups/nftables.conf.bak /etc/nftables.conf 2>/dev/null || true; fi`;
+ await runVisible`if [ -f /etc/hy2xs/backups/hy2xs.nft.existed ]; then cp -a /etc/hy2xs/backups/hy2xs.nft.bak /etc/nftables.d/hy2xs.nft 2>/dev/null || true; else rm -f /etc/nftables.d/hy2xs.nft; fi`;
+
+ await runVisible`nft -f /etc/nftables.conf >/dev/null 2>&1 || true`;
await runVisible`systemctl daemon-reload`;
await runVisible`systemctl restart hysteria-server hy2xs-admin || true`;
}
diff --git a/orchestrator/src/steps/firewall.ts b/orchestrator/src/steps/firewall.ts
index 8b059aa..2c39e5f 100644
--- a/orchestrator/src/steps/firewall.ts
+++ b/orchestrator/src/steps/firewall.ts
@@ -29,12 +29,19 @@ export async function applyFirewall(context: InstallContext): Promise {
await writeText("/etc/nftables.d/hy2xs.nft.candidate", rendered, 0o600);
await runVisible`nft -c -f /etc/nftables.d/hy2xs.nft.candidate`;
+ const nftablesConf = `#!/usr/sbin/nft -f
+flush ruleset
+
+include "/etc/nftables.d/hy2xs.nft"
+`;
+ await writeText("/etc/nftables.conf", nftablesConf, 0o644);
+ await runVisible`nft -c -f /etc/nftables.conf`;
+
if (context.config.firewallStagedApply) {
- 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`systemd-run --unit hy2xs-fw-rollback --on-active=45s /bin/sh -c 'if [ -f /etc/nftables.conf.hy2xs.bak ]; then cp -a /etc/nftables.conf.hy2xs.bak /etc/nftables.conf 2>/dev/null || true; fi; 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`grep -q 'include "/etc/nftables.d/hy2xs.nft"' /etc/nftables.conf || printf '\ninclude "/etc/nftables.d/hy2xs.nft"\n' >> /etc/nftables.conf`;
await runVisible`nft -f /etc/nftables.conf`;
await runVisible`systemctl enable --now nftables`;
diff --git a/package/config/hy2xs.env b/package/config/hy2xs.env
index 02acb4f..7b40692 100644
--- a/package/config/hy2xs.env
+++ b/package/config/hy2xs.env
@@ -30,7 +30,7 @@ HY2XS_HYSTERIA_BANDWIDTH_UP=50 mbps
HY2XS_HYSTERIA_BANDWIDTH_DOWN=50 mbps
HY2XS_HYSTERIA_IGNORE_CLIENT_BANDWIDTH=false
HY2XS_HYSTERIA_CONFIG_PATH=/etc/hysteria/config.yaml
-HY2XS_HYSTERIA_VERSION=latest
+HY2XS_HYSTERIA_VERSION=v2.6.0
HY2XS_INSTALL_DIR=/opt/hy2xs-admin
HY2XS_DATA_DIR=/var/lib/hy2xs-admin
HY2XS_LOG_DIR=/var/log/hy2xs
diff --git a/tools/build/lib/deps.sh b/tools/build/lib/deps.sh
index 6bf72bc..260cb00 100644
--- a/tools/build/lib/deps.sh
+++ b/tools/build/lib/deps.sh
@@ -6,6 +6,25 @@ BUN_REQUIRED="${BUN_REQUIRED:-1.1.45}"
NODE_REQUIRED="${NODE_REQUIRED:-20.19.0}"
PNPM_REQUIRED="${PNPM_REQUIRED:-9.15.9}"
TOOLCHAIN_DIR="${TOOLCHAIN_DIR:-$ROOT_DIR/.toolchain}"
+VERIFY_TOOLCHAIN_CHECKSUMS="${VERIFY_TOOLCHAIN_CHECKSUMS:-false}"
+GO_ARCHIVE_SHA256="${GO_ARCHIVE_SHA256:-}"
+NODE_ARCHIVE_SHA256="${NODE_ARCHIVE_SHA256:-}"
+BUN_ARCHIVE_SHA256="${BUN_ARCHIVE_SHA256:-}"
+
+verify_archive_sha256() {
+ local archive="$1"
+ local expected="$2"
+ local label="$3"
+
+ if [ "$VERIFY_TOOLCHAIN_CHECKSUMS" != "true" ]; then
+ return 0
+ fi
+
+ [ -n "$expected" ] || fail "missing expected SHA256 for $label (set ${label}_SHA256 env)"
+ local actual
+ actual="$(sha256sum "$archive" | awk '{print $1}')"
+ [ "$actual" = "$expected" ] || fail "$label sha256 mismatch: expected $expected, got $actual"
+}
require_linux_debian12_amd64() {
[ "$(uname -s)" = "Linux" ] || fail "production builder supports only Linux Debian 12 amd64"
@@ -79,6 +98,7 @@ ensure_go() {
mkdir -p "$TOOLCHAIN_DIR/downloads"
local archive="$TOOLCHAIN_DIR/downloads/go${GO_REQUIRED}.linux-amd64.tar.gz"
download_file "https://go.dev/dl/go${GO_REQUIRED}.linux-amd64.tar.gz" "$archive"
+ verify_archive_sha256 "$archive" "$GO_ARCHIVE_SHA256" "GO_ARCHIVE"
rm -rf "$TOOLCHAIN_DIR/go"
tar -C "$TOOLCHAIN_DIR" -xzf "$archive"
GO_BIN="$managed"
@@ -102,6 +122,7 @@ ensure_bun() {
mkdir -p "$TOOLCHAIN_DIR/downloads" "$TOOLCHAIN_DIR/bun"
local archive="$TOOLCHAIN_DIR/downloads/bun-linux-x64-${BUN_REQUIRED}.zip"
download_file "https://github.com/oven-sh/bun/releases/download/bun-v${BUN_REQUIRED}/bun-linux-x64.zip" "$archive"
+ verify_archive_sha256 "$archive" "$BUN_ARCHIVE_SHA256" "BUN_ARCHIVE"
rm -rf "$TOOLCHAIN_DIR/bun-tmp" "$TOOLCHAIN_DIR/bun"
mkdir -p "$TOOLCHAIN_DIR/bun-tmp"
unzip -q "$archive" -d "$TOOLCHAIN_DIR/bun-tmp"
@@ -131,6 +152,7 @@ ensure_node() {
mkdir -p "$TOOLCHAIN_DIR/downloads"
local archive="$TOOLCHAIN_DIR/downloads/node-v${NODE_REQUIRED}-linux-x64.tar.xz"
download_file "https://nodejs.org/dist/v${NODE_REQUIRED}/node-v${NODE_REQUIRED}-linux-x64.tar.xz" "$archive"
+ verify_archive_sha256 "$archive" "$NODE_ARCHIVE_SHA256" "NODE_ARCHIVE"
rm -rf "$TOOLCHAIN_DIR/node" "$TOOLCHAIN_DIR/node-v${NODE_REQUIRED}-linux-x64"
tar -C "$TOOLCHAIN_DIR" -xJf "$archive"
mv "$TOOLCHAIN_DIR/node-v${NODE_REQUIRED}-linux-x64" "$TOOLCHAIN_DIR/node"