's'
This commit is contained in:
313
scripts/deploy-neko-dual.sh
Normal file
313
scripts/deploy-neko-dual.sh
Normal file
@@ -0,0 +1,313 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "missing required command: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_cmd docker
|
||||
require_cmd getent
|
||||
require_cmd ip
|
||||
require_cmd awk
|
||||
require_cmd sudo
|
||||
|
||||
ufw_udp_range() {
|
||||
echo "${1//-/:}/udp"
|
||||
}
|
||||
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
sudo -v
|
||||
fi
|
||||
|
||||
if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" ]]; then
|
||||
DEFAULT_HOME="$(getent passwd "$SUDO_USER" | awk -F: '{print $6}')"
|
||||
else
|
||||
DEFAULT_HOME="$HOME"
|
||||
fi
|
||||
|
||||
HOME_DIR="${HOME_DIR:-$DEFAULT_HOME}"
|
||||
LAN_IP="${LAN_IP:-$(ip route get 1 | awk '{print $7; exit}')}"
|
||||
|
||||
NEKO_USER_PASSWORD="${NEKO_USER_PASSWORD:-user123}"
|
||||
NEKO_ADMIN_PASSWORD="${NEKO_ADMIN_PASSWORD:-admin123}"
|
||||
|
||||
PROFILE_UID="${PROFILE_UID:-1000}"
|
||||
PROFILE_GID="${PROFILE_GID:-1000}"
|
||||
|
||||
CHROMIUM_DIR="${CHROMIUM_DIR:-$HOME_DIR/neko-browser}"
|
||||
GOOGLE_CHROME_DIR="${GOOGLE_CHROME_DIR:-$HOME_DIR/neko-google-chrome}"
|
||||
|
||||
CHROMIUM_PROFILE_DIR="${CHROMIUM_PROFILE_DIR:-/root/neko-chromium-profile}"
|
||||
GOOGLE_CHROME_PROFILE_DIR="${GOOGLE_CHROME_PROFILE_DIR:-/root/neko-google-chrome-profile}"
|
||||
|
||||
CHROMIUM_HTTP_PORT="${CHROMIUM_HTTP_PORT:-8080}"
|
||||
GOOGLE_CHROME_HTTP_PORT="${GOOGLE_CHROME_HTTP_PORT:-8081}"
|
||||
|
||||
CHROMIUM_UDP_RANGE="${CHROMIUM_UDP_RANGE:-56000-56100}"
|
||||
GOOGLE_CHROME_UDP_RANGE="${GOOGLE_CHROME_UDP_RANGE:-56200-56300}"
|
||||
|
||||
CHROMIUM_DISPLAY="${CHROMIUM_DISPLAY:-:99.0}"
|
||||
GOOGLE_CHROME_DISPLAY="${GOOGLE_CHROME_DISPLAY:-:100.0}"
|
||||
|
||||
mkdir -p \
|
||||
"$CHROMIUM_DIR/policies" \
|
||||
"$GOOGLE_CHROME_DIR/policies"
|
||||
|
||||
sudo mkdir -p \
|
||||
"$CHROMIUM_PROFILE_DIR" \
|
||||
"$GOOGLE_CHROME_PROFILE_DIR"
|
||||
|
||||
sudo chown -R "${PROFILE_UID}:${PROFILE_GID}" \
|
||||
"$CHROMIUM_PROFILE_DIR" \
|
||||
"$GOOGLE_CHROME_PROFILE_DIR"
|
||||
|
||||
cat >"$CHROMIUM_DIR/docker-compose.yaml" <<EOF
|
||||
services:
|
||||
neko-browser:
|
||||
image: ghcr.io/m1k1o/neko/chromium:latest
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
shm_size: "8gb"
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
environment:
|
||||
DISPLAY: "${CHROMIUM_DISPLAY}"
|
||||
NEKO_DESKTOP_SCREEN: "1920x1080@60"
|
||||
NEKO_SERVER_BIND: ":${CHROMIUM_HTTP_PORT}"
|
||||
NEKO_MEMBER_PROVIDER: "multiuser"
|
||||
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "${NEKO_USER_PASSWORD}"
|
||||
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "${NEKO_ADMIN_PASSWORD}"
|
||||
NEKO_WEBRTC_EPR: "${CHROMIUM_UDP_RANGE}"
|
||||
NEKO_WEBRTC_ICELITE: "1"
|
||||
NEKO_WEBRTC_NAT1TO1: "${LAN_IP}"
|
||||
NEKO_PLUGINS_ENABLED: "true"
|
||||
NEKO_PLUGINS_DIR: "/etc/neko/plugins/"
|
||||
volumes:
|
||||
- ${CHROMIUM_PROFILE_DIR}:/home/neko/.config/chromium
|
||||
- ${CHROMIUM_DIR}/policies:/etc/chromium/policies/managed:ro
|
||||
- ${CHROMIUM_DIR}/chromium.conf:/etc/neko/supervisord/chromium.conf:ro
|
||||
EOF
|
||||
|
||||
cat >"$CHROMIUM_DIR/chromium.conf" <<'EOF'
|
||||
[program:chromium]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/usr/bin/chromium
|
||||
--window-position=0,0
|
||||
--display=%(ENV_DISPLAY)s
|
||||
--user-data-dir=/home/neko/.config/chromium
|
||||
--password-store=basic
|
||||
--no-first-run
|
||||
--start-maximized
|
||||
--force-dark-mode
|
||||
--disable-file-system
|
||||
--disable-gpu
|
||||
--disable-software-rasterizer
|
||||
--disable-dev-shm-usage
|
||||
--disable-background-timer-throttling
|
||||
--disable-backgrounding-occluded-windows
|
||||
--disable-renderer-backgrounding
|
||||
stopsignal=INT
|
||||
autorestart=true
|
||||
priority=800
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/chromium.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
|
||||
[program:openbox]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
||||
autorestart=true
|
||||
priority=300
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/openbox.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
EOF
|
||||
|
||||
cat >"$CHROMIUM_DIR/policies/policies.json" <<'EOF'
|
||||
{
|
||||
"ExtensionInstallForcelist": [
|
||||
"dhdgffkkebhmkfjojejmpbldmpobfkfo;https://clients2.google.com/service/update2/crx"
|
||||
],
|
||||
"ExtensionInstallAllowlist": [
|
||||
"*"
|
||||
],
|
||||
"ExtensionInstallBlocklist": [],
|
||||
"DownloadRestrictions": 0,
|
||||
"AllowFileSelectionDialogs": true,
|
||||
"URLAllowlist": ["file:///home/neko/Downloads/*"],
|
||||
"DefaultCookiesSetting": 1,
|
||||
"RestoreOnStartup": 1
|
||||
}
|
||||
EOF
|
||||
|
||||
cat >"$GOOGLE_CHROME_DIR/docker-compose.yaml" <<EOF
|
||||
services:
|
||||
neko-google-chrome:
|
||||
image: ghcr.io/m1k1o/neko/google-chrome:latest
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
shm_size: "8gb"
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
environment:
|
||||
DISPLAY: "${GOOGLE_CHROME_DISPLAY}"
|
||||
NEKO_DESKTOP_SCREEN: "1920x1080@60"
|
||||
NEKO_SERVER_BIND: ":${GOOGLE_CHROME_HTTP_PORT}"
|
||||
NEKO_MEMBER_PROVIDER: "multiuser"
|
||||
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "${NEKO_USER_PASSWORD}"
|
||||
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "${NEKO_ADMIN_PASSWORD}"
|
||||
NEKO_WEBRTC_EPR: "${GOOGLE_CHROME_UDP_RANGE}"
|
||||
NEKO_WEBRTC_ICELITE: "1"
|
||||
NEKO_WEBRTC_NAT1TO1: "${LAN_IP}"
|
||||
NEKO_PLUGINS_ENABLED: "true"
|
||||
NEKO_PLUGINS_DIR: "/etc/neko/plugins/"
|
||||
volumes:
|
||||
- ${GOOGLE_CHROME_PROFILE_DIR}:/home/neko/.config/google-chrome
|
||||
- ${GOOGLE_CHROME_DIR}/policies:/etc/opt/chrome/policies/managed:ro
|
||||
- ${GOOGLE_CHROME_DIR}/google-chrome.conf:/etc/neko/supervisord/google-chrome.conf:ro
|
||||
EOF
|
||||
|
||||
cat >"$GOOGLE_CHROME_DIR/google-chrome.conf" <<'EOF'
|
||||
[program:google-chrome]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/usr/bin/google-chrome
|
||||
--window-position=0,0
|
||||
--display=%(ENV_DISPLAY)s
|
||||
--user-data-dir=/home/neko/.config/google-chrome
|
||||
--password-store=basic
|
||||
--no-first-run
|
||||
--start-maximized
|
||||
--force-dark-mode
|
||||
--disable-file-system
|
||||
--disable-gpu
|
||||
--disable-software-rasterizer
|
||||
--disable-dev-shm-usage
|
||||
--disable-background-timer-throttling
|
||||
--disable-backgrounding-occluded-windows
|
||||
--disable-renderer-backgrounding
|
||||
stopsignal=INT
|
||||
autorestart=true
|
||||
priority=800
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/google-chrome.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
|
||||
[program:openbox]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
||||
autorestart=true
|
||||
priority=300
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/openbox.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
EOF
|
||||
|
||||
cat >"$GOOGLE_CHROME_DIR/policies/policies.json" <<'EOF'
|
||||
{
|
||||
"ExtensionInstallForcelist": [
|
||||
"dhdgffkkebhmkfjojejmpbldmpobfkfo;https://clients2.google.com/service/update2/crx"
|
||||
],
|
||||
"ExtensionInstallAllowlist": [
|
||||
"*"
|
||||
],
|
||||
"ExtensionInstallBlocklist": [],
|
||||
"DownloadRestrictions": 0,
|
||||
"AllowFileSelectionDialogs": true,
|
||||
"URLAllowlist": ["file:///home/neko/Downloads/*"],
|
||||
"DefaultCookiesSetting": 1,
|
||||
"RestoreOnStartup": 1
|
||||
}
|
||||
EOF
|
||||
|
||||
sudo ufw allow "${CHROMIUM_HTTP_PORT}" >/dev/null 2>&1 || true
|
||||
sudo ufw allow "${GOOGLE_CHROME_HTTP_PORT}" >/dev/null 2>&1 || true
|
||||
sudo ufw allow "$(ufw_udp_range "${CHROMIUM_UDP_RANGE}")" >/dev/null 2>&1 || true
|
||||
sudo ufw allow "$(ufw_udp_range "${GOOGLE_CHROME_UDP_RANGE}")" >/dev/null 2>&1 || true
|
||||
|
||||
recreate_compose_service() {
|
||||
local compose_dir="$1"
|
||||
local service="$2"
|
||||
local name_pattern="$3"
|
||||
local existing_id=""
|
||||
local pid=""
|
||||
|
||||
existing_id="$(cd "$compose_dir" && docker compose ps -q "$service" 2>/dev/null || true)"
|
||||
if [[ -n "$existing_id" ]]; then
|
||||
docker update --restart=no "$existing_id" >/dev/null 2>&1 || true
|
||||
pid="$(docker inspect -f '{{.State.Pid}}' "$existing_id" 2>/dev/null || true)"
|
||||
if [[ -n "$pid" && "$pid" != "0" ]]; then
|
||||
sudo kill -TERM "$pid" >/dev/null 2>&1 || true
|
||||
sleep 3
|
||||
sudo kill -KILL "$pid" >/dev/null 2>&1 || true
|
||||
sleep 2
|
||||
fi
|
||||
docker rm -f "$existing_id" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
docker ps -a --format '{{.ID}} {{.Names}}' \
|
||||
| awk -v pat="$name_pattern" '$2 ~ pat {print $1}' \
|
||||
| xargs -r docker rm -f >/dev/null 2>&1 || true
|
||||
|
||||
(cd "$compose_dir" && docker compose up -d)
|
||||
}
|
||||
|
||||
wait_for_healthy() {
|
||||
local compose_dir="$1"
|
||||
local service="$2"
|
||||
local container_id=""
|
||||
local health_status=""
|
||||
local state_status=""
|
||||
|
||||
for _ in $(seq 1 60); do
|
||||
container_id="$(cd "$compose_dir" && docker compose ps -q "$service" 2>/dev/null || true)"
|
||||
[[ -z "$container_id" ]] && sleep 2 && continue
|
||||
|
||||
health_status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$container_id" 2>/dev/null || true)"
|
||||
state_status="$(docker inspect -f '{{.State.Status}}' "$container_id" 2>/dev/null || true)"
|
||||
|
||||
if [[ "$state_status" == "running" && ( "$health_status" == "healthy" || "$health_status" == "none" ) ]]; then
|
||||
echo "$container_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$health_status" == "unhealthy" ]]; then
|
||||
echo "service ${service} became unhealthy" >&2
|
||||
docker logs --tail 200 "$container_id" >&2 || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "timed out waiting for ${service}" >&2
|
||||
[[ -n "$container_id" ]] && docker logs --tail 200 "$container_id" >&2 || true
|
||||
return 1
|
||||
}
|
||||
|
||||
recreate_compose_service "$CHROMIUM_DIR" "neko-browser" "neko-browser"
|
||||
recreate_compose_service "$GOOGLE_CHROME_DIR" "neko-google-chrome" "neko-google-chrome"
|
||||
|
||||
CHROMIUM_ID="$(wait_for_healthy "$CHROMIUM_DIR" "neko-browser")"
|
||||
GOOGLE_CHROME_ID="$(wait_for_healthy "$GOOGLE_CHROME_DIR" "neko-google-chrome")"
|
||||
|
||||
echo
|
||||
echo "chromium:"
|
||||
echo " url: http://${LAN_IP}:${CHROMIUM_HTTP_PORT}/"
|
||||
echo " container: ${CHROMIUM_ID}"
|
||||
echo " compose: ${CHROMIUM_DIR}"
|
||||
echo
|
||||
echo "google-chrome:"
|
||||
echo " url: http://${LAN_IP}:${GOOGLE_CHROME_HTTP_PORT}/"
|
||||
echo " container: ${GOOGLE_CHROME_ID}"
|
||||
echo " compose: ${GOOGLE_CHROME_DIR}"
|
||||
205
scripts/deploy-neko-google-chrome-2.sh
Normal file
205
scripts/deploy-neko-google-chrome-2.sh
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "missing required command: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_cmd docker
|
||||
require_cmd getent
|
||||
require_cmd ip
|
||||
require_cmd awk
|
||||
require_cmd sudo
|
||||
|
||||
ufw_udp_range() {
|
||||
echo "${1//-/:}/udp"
|
||||
}
|
||||
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
sudo -v
|
||||
fi
|
||||
|
||||
if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" ]]; then
|
||||
DEFAULT_HOME="$(getent passwd "$SUDO_USER" | awk -F: '{print $6}')"
|
||||
else
|
||||
DEFAULT_HOME="$HOME"
|
||||
fi
|
||||
|
||||
HOME_DIR="${HOME_DIR:-$DEFAULT_HOME}"
|
||||
LAN_IP="${LAN_IP:-$(ip route get 1 | awk '{print $7; exit}')}"
|
||||
|
||||
NEKO_USER_PASSWORD="${NEKO_USER_PASSWORD:-user123}"
|
||||
NEKO_ADMIN_PASSWORD="${NEKO_ADMIN_PASSWORD:-admin123}"
|
||||
|
||||
PROFILE_UID="${PROFILE_UID:-1000}"
|
||||
PROFILE_GID="${PROFILE_GID:-1000}"
|
||||
|
||||
GOOGLE_CHROME_DIR="${GOOGLE_CHROME_DIR:-$HOME_DIR/neko-google-chrome-2}"
|
||||
GOOGLE_CHROME_PROFILE_DIR="${GOOGLE_CHROME_PROFILE_DIR:-/root/neko-google-chrome-2-profile}"
|
||||
|
||||
GOOGLE_CHROME_HTTP_PORT="${GOOGLE_CHROME_HTTP_PORT:-8082}"
|
||||
GOOGLE_CHROME_UDP_RANGE="${GOOGLE_CHROME_UDP_RANGE:-56400-56500}"
|
||||
GOOGLE_CHROME_DISPLAY="${GOOGLE_CHROME_DISPLAY:-:101.0}"
|
||||
|
||||
mkdir -p "$GOOGLE_CHROME_DIR/policies"
|
||||
|
||||
sudo mkdir -p "$GOOGLE_CHROME_PROFILE_DIR"
|
||||
sudo chown -R "${PROFILE_UID}:${PROFILE_GID}" "$GOOGLE_CHROME_PROFILE_DIR"
|
||||
|
||||
cat >"$GOOGLE_CHROME_DIR/docker-compose.yaml" <<EOF
|
||||
services:
|
||||
neko-google-chrome-2:
|
||||
image: ghcr.io/m1k1o/neko/google-chrome:latest
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
shm_size: "8gb"
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
environment:
|
||||
DISPLAY: "${GOOGLE_CHROME_DISPLAY}"
|
||||
NEKO_DESKTOP_SCREEN: "1920x1080@60"
|
||||
NEKO_SERVER_BIND: ":${GOOGLE_CHROME_HTTP_PORT}"
|
||||
NEKO_MEMBER_PROVIDER: "multiuser"
|
||||
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "${NEKO_USER_PASSWORD}"
|
||||
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "${NEKO_ADMIN_PASSWORD}"
|
||||
NEKO_WEBRTC_EPR: "${GOOGLE_CHROME_UDP_RANGE}"
|
||||
NEKO_WEBRTC_ICELITE: "1"
|
||||
NEKO_WEBRTC_NAT1TO1: "${LAN_IP}"
|
||||
NEKO_PLUGINS_ENABLED: "true"
|
||||
NEKO_PLUGINS_DIR: "/etc/neko/plugins/"
|
||||
volumes:
|
||||
- ${GOOGLE_CHROME_PROFILE_DIR}:/home/neko/.config/google-chrome
|
||||
- ${GOOGLE_CHROME_DIR}/policies:/etc/opt/chrome/policies/managed:ro
|
||||
- ${GOOGLE_CHROME_DIR}/google-chrome.conf:/etc/neko/supervisord/google-chrome.conf:ro
|
||||
EOF
|
||||
|
||||
cat >"$GOOGLE_CHROME_DIR/google-chrome.conf" <<'EOF'
|
||||
[program:google-chrome]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/usr/bin/google-chrome
|
||||
--window-position=0,0
|
||||
--display=%(ENV_DISPLAY)s
|
||||
--user-data-dir=/home/neko/.config/google-chrome
|
||||
--password-store=basic
|
||||
--no-first-run
|
||||
--start-maximized
|
||||
--force-dark-mode
|
||||
--disable-file-system
|
||||
--disable-gpu
|
||||
--disable-software-rasterizer
|
||||
--disable-dev-shm-usage
|
||||
--disable-background-timer-throttling
|
||||
--disable-backgrounding-occluded-windows
|
||||
--disable-renderer-backgrounding
|
||||
stopsignal=INT
|
||||
autorestart=true
|
||||
priority=800
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/google-chrome.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
|
||||
[program:openbox]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
||||
autorestart=true
|
||||
priority=300
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/openbox.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
EOF
|
||||
|
||||
cat >"$GOOGLE_CHROME_DIR/policies/policies.json" <<'EOF'
|
||||
{
|
||||
"ExtensionInstallForcelist": [
|
||||
"dhdgffkkebhmkfjojejmpbldmpobfkfo;https://clients2.google.com/service/update2/crx"
|
||||
],
|
||||
"ExtensionInstallAllowlist": [
|
||||
"*"
|
||||
],
|
||||
"ExtensionInstallBlocklist": [],
|
||||
"DownloadRestrictions": 0,
|
||||
"AllowFileSelectionDialogs": true,
|
||||
"URLAllowlist": ["file:///home/neko/Downloads/*"],
|
||||
"DefaultCookiesSetting": 1,
|
||||
"RestoreOnStartup": 1
|
||||
}
|
||||
EOF
|
||||
|
||||
sudo ufw allow "${GOOGLE_CHROME_HTTP_PORT}" >/dev/null 2>&1 || true
|
||||
sudo ufw allow "$(ufw_udp_range "${GOOGLE_CHROME_UDP_RANGE}")" >/dev/null 2>&1 || true
|
||||
|
||||
recreate_compose_service() {
|
||||
local compose_dir="$1"
|
||||
local service="$2"
|
||||
local name_pattern="$3"
|
||||
local existing_id=""
|
||||
local pid=""
|
||||
|
||||
existing_id="$(cd "$compose_dir" && docker compose ps -q "$service" 2>/dev/null || true)"
|
||||
if [[ -n "$existing_id" ]]; then
|
||||
docker update --restart=no "$existing_id" >/dev/null 2>&1 || true
|
||||
pid="$(docker inspect -f '{{.State.Pid}}' "$existing_id" 2>/dev/null || true)"
|
||||
if [[ -n "$pid" && "$pid" != "0" ]]; then
|
||||
sudo kill -TERM "$pid" >/dev/null 2>&1 || true
|
||||
sleep 3
|
||||
sudo kill -KILL "$pid" >/dev/null 2>&1 || true
|
||||
sleep 2
|
||||
fi
|
||||
docker rm -f "$existing_id" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
docker ps -a --format '{{.ID}} {{.Names}}' \
|
||||
| awk -v pat="$name_pattern" '$2 ~ pat {print $1}' \
|
||||
| xargs -r docker rm -f >/dev/null 2>&1 || true
|
||||
|
||||
(cd "$compose_dir" && docker compose up -d)
|
||||
}
|
||||
|
||||
wait_for_healthy() {
|
||||
local compose_dir="$1"
|
||||
local service="$2"
|
||||
local container_id=""
|
||||
local health_status=""
|
||||
local state_status=""
|
||||
|
||||
for _ in $(seq 1 60); do
|
||||
container_id="$(cd "$compose_dir" && docker compose ps -q "$service" 2>/dev/null || true)"
|
||||
[[ -z "$container_id" ]] && sleep 2 && continue
|
||||
|
||||
health_status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$container_id" 2>/dev/null || true)"
|
||||
state_status="$(docker inspect -f '{{.State.Status}}' "$container_id" 2>/dev/null || true)"
|
||||
|
||||
if [[ "$state_status" == "running" && ( "$health_status" == "healthy" || "$health_status" == "none" ) ]]; then
|
||||
echo "$container_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$health_status" == "unhealthy" ]]; then
|
||||
echo "service ${service} became unhealthy" >&2
|
||||
docker logs --tail 200 "$container_id" >&2 || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "timed out waiting for ${service}" >&2
|
||||
[[ -n "$container_id" ]] && docker logs --tail 200 "$container_id" >&2 || true
|
||||
return 1
|
||||
}
|
||||
|
||||
recreate_compose_service "$GOOGLE_CHROME_DIR" "neko-google-chrome-2" "neko-google-chrome-2"
|
||||
GOOGLE_CHROME_ID="$(wait_for_healthy "$GOOGLE_CHROME_DIR" "neko-google-chrome-2")"
|
||||
|
||||
echo
|
||||
echo "google-chrome-2:"
|
||||
echo " url: http://${LAN_IP}:${GOOGLE_CHROME_HTTP_PORT}/"
|
||||
echo " container: ${GOOGLE_CHROME_ID}"
|
||||
echo " compose: ${GOOGLE_CHROME_DIR}"
|
||||
50
tcp_forward_qwen.py
Normal file
50
tcp_forward_qwen.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import socket
|
||||
import threading
|
||||
|
||||
|
||||
LISTEN_HOST = "127.0.0.1"
|
||||
LISTEN_PORT = 18007
|
||||
TARGET_HOST = "192.168.41.184"
|
||||
TARGET_PORT = 8007
|
||||
|
||||
|
||||
def pipe(src: socket.socket, dst: socket.socket) -> None:
|
||||
try:
|
||||
while True:
|
||||
data = src.recv(65536)
|
||||
if not data:
|
||||
break
|
||||
dst.sendall(data)
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
for sock in (src, dst):
|
||||
try:
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
sock.close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def handle_client(client: socket.socket) -> None:
|
||||
upstream = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
upstream.connect((TARGET_HOST, TARGET_PORT))
|
||||
threading.Thread(target=pipe, args=(client, upstream), daemon=True).start()
|
||||
threading.Thread(target=pipe, args=(upstream, client), daemon=True).start()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind((LISTEN_HOST, LISTEN_PORT))
|
||||
server.listen()
|
||||
while True:
|
||||
client, _ = server.accept()
|
||||
threading.Thread(target=handle_client, args=(client,), daemon=True).start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user