mirror of
https://github.com/m1ngsama/automa.git
synced 2026-03-25 18:23:49 +00:00
Merge pull request #10 from m1ngsama/fix/deploy-idempotent-binary-check
fix: idempotent binary install, bundled templates, envsubst export
This commit is contained in:
commit
23b8d1abd8
15 changed files with 265 additions and 54 deletions
|
|
@ -8,7 +8,7 @@ source "$SCRIPT_DIR/../../bin/lib/common.sh"
|
|||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
|
||||
require_env DOMAIN MAIL_HOST MAIL_USER
|
||||
|
||||
|
|
|
|||
|
|
@ -8,26 +8,44 @@ source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
|||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
|
||||
require_env FRP_SERVER_ADDR FRP_SERVER_PORT FRP_TOKEN
|
||||
|
||||
log_info "Downloading FRP..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
|
||||
ARCHIVE="frp_${VERSION}_linux_amd64.tar.gz"
|
||||
wget -q "https://github.com/fatedier/frp/releases/download/v${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
mkdir -p /opt/frp
|
||||
cp "frp_${VERSION}_linux_amd64/frpc" /opt/frp/
|
||||
chmod +x /opt/frp/frpc
|
||||
rm -rf "$ARCHIVE" "frp_${VERSION}_linux_amd64"
|
||||
find_template() {
|
||||
local f="$1"
|
||||
if [[ -n "${INFRA_DIR:-}" && -f "${INFRA_DIR}/$f" ]]; then
|
||||
echo "${INFRA_DIR}/$f"
|
||||
elif [[ -f "$SCRIPT_DIR/$f" ]]; then
|
||||
echo "$SCRIPT_DIR/$f"
|
||||
else
|
||||
log_error "Template not found: $f"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
FRPC_BIN="/opt/frp/frpc"
|
||||
|
||||
if [[ -x "$FRPC_BIN" ]]; then
|
||||
log_info "frpc already at $FRPC_BIN, skipping download"
|
||||
else
|
||||
log_info "Downloading FRP..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
|
||||
ARCHIVE="frp_${VERSION}_linux_amd64.tar.gz"
|
||||
wget -q "https://github.com/fatedier/frp/releases/download/v${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
mkdir -p /opt/frp
|
||||
cp "frp_${VERSION}_linux_amd64/frpc" /opt/frp/
|
||||
chmod +x /opt/frp/frpc
|
||||
rm -rf "$ARCHIVE" "frp_${VERSION}_linux_amd64"
|
||||
fi
|
||||
|
||||
log_info "Deploying config..."
|
||||
envsubst < "${INFRA_DIR}/frpc.toml.example" > /opt/frp/frpc.toml
|
||||
envsubst < "$(find_template frpc.toml.example)" > /opt/frp/frpc.toml
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/frpc.service" /etc/systemd/system/
|
||||
cp "$(find_template frpc.service)" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now frpc
|
||||
|
||||
|
|
|
|||
15
services/frp/client/frpc.service
Normal file
15
services/frp/client/frpc.service
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=FRP Client
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/opt/frp/frpc -c /opt/frp/frpc.toml
|
||||
WorkingDirectory=/opt/frp
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
21
services/frp/client/frpc.toml.example
Normal file
21
services/frp/client/frpc.toml.example
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
serverAddr = "${FRP_SERVER_ADDR}"
|
||||
serverPort = ${FRP_SERVER_PORT}
|
||||
|
||||
auth.method = "token"
|
||||
auth.token = "${FRP_TOKEN}"
|
||||
|
||||
# Example: expose home SSH
|
||||
[[proxies]]
|
||||
name = "home-ssh"
|
||||
type = "tcp"
|
||||
localIP = "127.0.0.1"
|
||||
localPort = 22
|
||||
remotePort = 1234
|
||||
|
||||
# Example: expose Minecraft
|
||||
[[proxies]]
|
||||
name = "minecraft"
|
||||
type = "tcp"
|
||||
localIP = "127.0.0.1"
|
||||
localPort = 25565
|
||||
remotePort = 25565
|
||||
|
|
@ -8,26 +8,44 @@ source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
|||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
|
||||
require_env FRP_TOKEN FRP_WEB_PASSWORD FRP_BIND_PORT
|
||||
|
||||
log_info "Downloading FRP..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
|
||||
ARCHIVE="frp_${VERSION}_linux_amd64.tar.gz"
|
||||
wget -q "https://github.com/fatedier/frp/releases/download/v${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
mkdir -p /opt/frp
|
||||
cp "frp_${VERSION}_linux_amd64/frps" /opt/frp/
|
||||
chmod +x /opt/frp/frps
|
||||
rm -rf "$ARCHIVE" "frp_${VERSION}_linux_amd64"
|
||||
find_template() {
|
||||
local f="$1"
|
||||
if [[ -n "${INFRA_DIR:-}" && -f "${INFRA_DIR}/$f" ]]; then
|
||||
echo "${INFRA_DIR}/$f"
|
||||
elif [[ -f "$SCRIPT_DIR/$f" ]]; then
|
||||
echo "$SCRIPT_DIR/$f"
|
||||
else
|
||||
log_error "Template not found: $f"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
FRPS_BIN="/opt/frp/frps"
|
||||
|
||||
if [[ -x "$FRPS_BIN" ]]; then
|
||||
log_info "frps already at $FRPS_BIN, skipping download"
|
||||
else
|
||||
log_info "Downloading FRP..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
|
||||
ARCHIVE="frp_${VERSION}_linux_amd64.tar.gz"
|
||||
wget -q "https://github.com/fatedier/frp/releases/download/v${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
mkdir -p /opt/frp
|
||||
cp "frp_${VERSION}_linux_amd64/frps" /opt/frp/
|
||||
chmod +x /opt/frp/frps
|
||||
rm -rf "$ARCHIVE" "frp_${VERSION}_linux_amd64"
|
||||
fi
|
||||
|
||||
log_info "Deploying config..."
|
||||
envsubst < "${INFRA_DIR}/frps.toml.example" > /opt/frp/frps.toml
|
||||
envsubst < "$(find_template frps.toml.example)" > /opt/frp/frps.toml
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/frps.service" /etc/systemd/system/
|
||||
cp "$(find_template frps.service)" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now frps
|
||||
|
||||
|
|
|
|||
15
services/frp/server/frps.service
Normal file
15
services/frp/server/frps.service
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=FRP Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/opt/frp/frps -c /opt/frp/frps.toml
|
||||
WorkingDirectory=/opt/frp
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
17
services/frp/server/frps.toml.example
Normal file
17
services/frp/server/frps.toml.example
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
bindAddr = "0.0.0.0"
|
||||
bindPort = ${FRP_BIND_PORT}
|
||||
|
||||
vhostHTTPPort = 8080
|
||||
vhostHTTPSPort = 8443
|
||||
|
||||
webServer.addr = "127.0.0.1"
|
||||
webServer.port = 7500
|
||||
webServer.user = "root"
|
||||
webServer.password = "${FRP_WEB_PASSWORD}"
|
||||
|
||||
log.to = "./frps.log"
|
||||
log.level = "info"
|
||||
log.maxDays = 3
|
||||
|
||||
auth.method = "token"
|
||||
auth.token = "${FRP_TOKEN}"
|
||||
|
|
@ -8,7 +8,7 @@ source "$SCRIPT_DIR/../../bin/lib/common.sh"
|
|||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
|
||||
require_env DOMAIN
|
||||
|
||||
|
|
|
|||
11
services/shadowsocks/client/config.json.example
Normal file
11
services/shadowsocks/client/config.json.example
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"server": "${SS_SERVER}",
|
||||
"server_port": ${SS_PORT},
|
||||
"password": "${SS_PASSWORD}",
|
||||
"method": "${SS_METHOD}",
|
||||
"local_address": "127.0.0.1",
|
||||
"local_port": 1080,
|
||||
"timeout": 300,
|
||||
"fast_open": true,
|
||||
"mode": "tcp_and_udp"
|
||||
}
|
||||
|
|
@ -8,30 +8,61 @@ source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
|||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
|
||||
require_env SS_SERVER SS_PORT SS_PASSWORD SS_METHOD
|
||||
|
||||
log_info "Downloading shadowsocks-rust client..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
|
||||
ARCHIVE="shadowsocks-${VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
wget -q "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
cp sslocal /usr/local/bin/sslocal
|
||||
chmod +x /usr/local/bin/sslocal
|
||||
rm -f "$ARCHIVE" ssserver sslocal ssurl ssmanager redir tunnel
|
||||
# Find a template file: prefer INFRA_DIR override, fall back to bundled default.
|
||||
find_template() {
|
||||
local f="$1"
|
||||
if [[ -n "${INFRA_DIR:-}" && -f "${INFRA_DIR}/$f" ]]; then
|
||||
echo "${INFRA_DIR}/$f"
|
||||
elif [[ -f "$SCRIPT_DIR/$f" ]]; then
|
||||
echo "$SCRIPT_DIR/$f"
|
||||
else
|
||||
log_error "Template not found: $f"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
SSLOCAL_BIN="/usr/local/bin/sslocal"
|
||||
|
||||
# Install sslocal — skip if already present, symlink if installed elsewhere.
|
||||
if [[ -x "$SSLOCAL_BIN" ]]; then
|
||||
log_info "sslocal already at $SSLOCAL_BIN ($($SSLOCAL_BIN --version 2>&1 | head -1)), skipping download"
|
||||
elif command -v sslocal &>/dev/null; then
|
||||
existing="$(command -v sslocal)"
|
||||
log_info "sslocal found at $existing, symlinking to $SSLOCAL_BIN"
|
||||
ln -sf "$existing" "$SSLOCAL_BIN"
|
||||
else
|
||||
log_info "Downloading shadowsocks-rust client..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
|
||||
ARCHIVE="shadowsocks-${VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
wget -q "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
cp sslocal "$SSLOCAL_BIN"
|
||||
chmod +x "$SSLOCAL_BIN"
|
||||
rm -f "$ARCHIVE" ssserver sslocal ssurl ssmanager redir tunnel
|
||||
fi
|
||||
|
||||
log_info "Installing privoxy..."
|
||||
apt-get install -y privoxy
|
||||
if command -v pacman &>/dev/null; then
|
||||
pacman -S --noconfirm --needed privoxy
|
||||
else
|
||||
apt-get install -y privoxy
|
||||
fi
|
||||
|
||||
log_info "Deploying configs..."
|
||||
mkdir -p /etc/shadowsocks-rust
|
||||
envsubst < "${INFRA_DIR}/config.json.example" > /etc/shadowsocks-rust/client.json
|
||||
cp "${INFRA_DIR}/privoxy.conf.example" /etc/privoxy/config
|
||||
envsubst < "$(find_template config.json.example)" > /etc/shadowsocks-rust/client.json
|
||||
cp "$(find_template privoxy.conf.example)" /etc/privoxy/config
|
||||
|
||||
log_info "Stopping any existing shadowsocks service on port 1080..."
|
||||
systemctl stop shadowsocks 2>/dev/null || true
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/shadowsocks-client.service" /etc/systemd/system/
|
||||
cp "$(find_template shadowsocks-client.service)" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now shadowsocks-client
|
||||
systemctl enable --now privoxy
|
||||
|
|
|
|||
5
services/shadowsocks/client/privoxy.conf.example
Normal file
5
services/shadowsocks/client/privoxy.conf.example
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Privoxy config — bridges SOCKS5 (sslocal) to HTTP proxy
|
||||
# Listens on :8118, forwards to sslocal SOCKS5 on :1080
|
||||
|
||||
listen-address 127.0.0.1:8118
|
||||
forward-socks5t / 127.0.0.1:1080 .
|
||||
14
services/shadowsocks/client/shadowsocks-client.service
Normal file
14
services/shadowsocks/client/shadowsocks-client.service
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=Shadowsocks-Rust Client
|
||||
Documentation=https://github.com/shadowsocks/shadowsocks-rust
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/sslocal -c /etc/shadowsocks-rust/client.json
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
LimitNOFILE=51200
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
10
services/shadowsocks/server/config.json.example
Normal file
10
services/shadowsocks/server/config.json.example
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"server": "0.0.0.0",
|
||||
"server_port": ${SS_PORT},
|
||||
"password": "${SS_PASSWORD}",
|
||||
"method": "${SS_METHOD}",
|
||||
"timeout": 300,
|
||||
"fast_open": true,
|
||||
"no_delay": true,
|
||||
"mode": "tcp_and_udp"
|
||||
}
|
||||
|
|
@ -8,26 +8,48 @@ source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
|||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
|
||||
require_env SS_PORT SS_PASSWORD SS_METHOD
|
||||
|
||||
log_info "Downloading shadowsocks-rust..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
|
||||
ARCHIVE="shadowsocks-${VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
wget -q "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
cp ssserver /usr/local/bin/ssserver-rust
|
||||
chmod +x /usr/local/bin/ssserver-rust
|
||||
rm -f "$ARCHIVE" ssserver sslocal ssurl ssmanager redir tunnel
|
||||
find_template() {
|
||||
local f="$1"
|
||||
if [[ -n "${INFRA_DIR:-}" && -f "${INFRA_DIR}/$f" ]]; then
|
||||
echo "${INFRA_DIR}/$f"
|
||||
elif [[ -f "$SCRIPT_DIR/$f" ]]; then
|
||||
echo "$SCRIPT_DIR/$f"
|
||||
else
|
||||
log_error "Template not found: $f"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
SSSERVER_BIN="/usr/local/bin/ssserver-rust"
|
||||
|
||||
if [[ -x "$SSSERVER_BIN" ]]; then
|
||||
log_info "ssserver-rust already at $SSSERVER_BIN ($($SSSERVER_BIN --version 2>&1 | head -1)), skipping download"
|
||||
elif command -v ssserver &>/dev/null; then
|
||||
existing="$(command -v ssserver)"
|
||||
log_info "ssserver found at $existing, symlinking to $SSSERVER_BIN"
|
||||
ln -sf "$existing" "$SSSERVER_BIN"
|
||||
else
|
||||
log_info "Downloading shadowsocks-rust..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
|
||||
ARCHIVE="shadowsocks-${VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
wget -q "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
cp ssserver "$SSSERVER_BIN"
|
||||
chmod +x "$SSSERVER_BIN"
|
||||
rm -f "$ARCHIVE" ssserver sslocal ssurl ssmanager redir tunnel
|
||||
fi
|
||||
|
||||
log_info "Deploying config..."
|
||||
mkdir -p /etc/shadowsocks-rust
|
||||
envsubst < "${INFRA_DIR}/config.json.example" > /etc/shadowsocks-rust/config.json
|
||||
envsubst < "$(find_template config.json.example)" > /etc/shadowsocks-rust/config.json
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/shadowsocks-rust.service" /etc/systemd/system/
|
||||
cp "$(find_template shadowsocks-rust.service)" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now shadowsocks-rust
|
||||
|
||||
|
|
|
|||
14
services/shadowsocks/server/shadowsocks-rust.service
Normal file
14
services/shadowsocks/server/shadowsocks-rust.service
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=Shadowsocks-Rust Server
|
||||
Documentation=https://github.com/shadowsocks/shadowsocks-rust
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/ssserver-rust -c /etc/shadowsocks-rust/config.json
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
LimitNOFILE=51200
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Reference in a new issue