SMF - Just Installed!
~/cloudlife-monitoring
assets/
compose/
docker/
install/
docs/
build/
./build-release.sh
dist/cloudlife-monitoring-1.0.0
dist/cloudlife-monitoring-1.0.0.tar.gz
~/cloudlife-monitoring/dist/cloudlife-monitoring-1.0.0
git status
git add .
git commit -m "CloudLife Monitoring v1.0.0"
git push
./build-release.sh
cd dist/cloudlife-monitoring-1.0.1
git add .
git commit -m "CloudLife Monitoring v1.0.1"
git tag v1.0.1
git push
git push --tags
git pull
git clone ssh://git@git.cloud-life.site:2222/cloud-life/monitoring.git
git diff
git log --oneline --decorate --graph
git log -10
git restore имя_файла
git restore .
NVIDIA-Linux-x86_64-470.xxx.run
sudo apt purge 'nvidia*'
sudo rm -rf /var/lib/dkms/nvidia
sudo update-initramfs -u
sudo nano /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0
sudo update-initramfs -u
sudo reboot
Ctrl + Alt + F3
sudo systemctl stop gdm
или lightdm / sddm
chmod +x NVIDIA-Linux-.run
sudo ./NVIDIA-Linux-.run
Register the kernel module with DKMS?
Would you like to sign the module?
sudo reboot
nvidia-smi
sudo apt install nvidia-prime
sudo prime-select on-demand
sudo reboot
__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia glxinfo | grep OpenGL
sudo apt update && sudo apt upgrade -y
mokutil --sb-state
sudo apt install nvidia-driver-470
sudo apt purge 'nvidia*'
sudo rm -rf /var/lib/dkms/nvidia
sudo update-initramfs -u
sudo apt install nvidia-prime
sudo prime-select on-demand
sudo reboot
sudo prime-select nvidia
prime-select query
on-demand
prime-run glxgears
__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia <command>
__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia steam
glxinfo | grep OpenGL
__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia glxinfo | grep OpenGL
nvidia-smi
sudo apt install nvidia-prime
prime-select query
on-demand
AllowedIPs = 0.0.0.0/0DNS = ...sudo apt update && sudo apt install wireguard resolvconf -ysudo sysctl -w net.ipv4.ip_forward=1sudo nano /etc/sysctl.confnet.ipv4.ip_forward=1sudo nano /etc/wireguard/wg0.conf\[Interface]
PrivateKey = <ВАШ_ПРИВАТНЫЙ_КЛЮЧ>
Address = 10.0.0.2/32, fd00::2/128
DNS = 1.1.1.1
# --- Скрипты включения интерфейса (PostUp) ---
# 1. Исправляем асимметричную маршрутизацию (SSH не отвалится)
PostUp = ip rule add from 192.168.11.50 table 200; \
ip route add default via 192.168.11.1 dev ens192 table 200;
# 2. Добавляем маршруты до локальных подсетей в обход VPN
PostUp = ip route add 192.168.10.0/24 via 192.168.11.1 dev ens192; \
ip route add 192.168.20.0/24 via 192.168.11.1 dev ens192; \
ip route add 172.16.0.0/24 via 192.168.11.1 dev ens192;
# 3. Настраиваем правила пересылки и NAT (Маскарадинг)
PostUp = iptables -A FORWARD -i ens192 -o wg0 -j ACCEPT; \
iptables -A FORWARD -i wg0 -o ens192 -m state --state RELATED,ESTABLISHED -j ACCEPT; \
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
# --- Скрипты выключения интерфейса (PostDown) ---
# 1. Удаляем правила асимметричной маршрутизации
PostDown = ip rule del from 192.168.11.50 table 200; \
ip route del default via 192.168.11.1 dev ens192 table 200;
# 2. Удаляем локальные маршруты
PostDown = ip route del 192.168.10.0/24 via 192.168.11.1 dev ens192; \
ip route del 192.168.20.0/24 via 192.168.11.1 dev ens192; \
ip route del 172.16.0.0/24 via 192.168.11.1 dev ens192;
# 3. Удаляем правила пересылки и NAT
PostDown = iptables -D FORWARD -i ens192 -o wg0 -j ACCEPT; \
iptables -D FORWARD -i wg0 -o ens192 -m state --state RELATED,ESTABLISHED -j ACCEPT; \
iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE
[Peer]
PublicKey = <КЛЮЧ_СЕРВЕРА>
Endpoint = 198.51.100.5:51820
AllowedIPs = 0.0.0.0/0, ::/0
sudo wg-quick up wg0sudo systemctl enable wg-quick@wg0sudo wgrm -rf ~/doom-fresh
mkdir ~/doom-fresh && cd ~/doom-fresh
git clone https://github.com/ozkl/doomgeneric.git
cd doomgeneric/doomgenericcp /путь/к/вашему/файлу/doom2.wad ./doom2.wadnano shell.html<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Чистый DOOM на WebAssembly</title>
<style>
body { background: #111; color: #fff; text-align: center; font-family: sans-serif; margin: 0; padding: 20px; }
#canvas { width: 640px; height: 400px; border: 3px solid #444; background: #000; display: block; margin: 20px auto; image-rendering: pixelated; }
.btn { padding: 12px 25px; font-size: 18px; font-weight: bold; background: #e50914; color: white; border: none; cursor: pointer; border-radius: 5px; }
.btn:hover { background: #b80710; }
</style>
</head>
<body>
<h2>DOOM 2 (Чистая WebAssembly сборка)</h2>
<button class="btn" id="fs-btn">ИГРАТЬ НА ВЕСЬ ЭКРАН</button>
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<script type='text/javascript'>
var Module = {
canvas: (function() { return document.getElementById('canvas'); })(),
print: function(text) { console.log(text); },
printErr: function(text) { console.error(text); },
arguments: ['-iwad', 'doom2.wad']
};
// Запрос полноэкранного режима по клику (требование безопасности браузера)
document.getElementById('fs-btn').addEventListener('click', () => {
const canvas = document.getElementById('canvas');
if (canvas.requestFullscreen) { canvas.requestFullscreen(); }
else if (canvas.webkitRequestFullscreen) { canvas.webkitRequestFullscreen(); }
});
</script>
{{{ SCRIPT }}}
</body>
</html>nano Makefile.emscriptenLDFLAGS=-s USE_SDL=2 -s ALLOW_MEMORY_GROWTH=1 -s ASYNCIFY=1 --shell-file shell.html --preload-file doom2.wad@/doom2.wadsource ~/doom-web/emsdk/emsdk_env.sh
emmake make -f Makefile.emscriptenpython3 -m http.server 8080nano /usr/local/sbin/docker-galera-upgrade.sh
#!/bin/bash
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
LOG="/var/log/docker-galera-upgrade.log"
STATE_FILE="/var/run/docker-galera-upgrade.state"
NODE=$(hostname)
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
}
log "===== START NODE UPGRADE (DOCKER + GALERA) ====="
# --- функции Galera ---
galera_size() {
mysql -Nse "SHOW STATUS LIKE 'wsrep_cluster_size'" | awk '{print $2}'
}
galera_ready() {
mysql -Nse "SHOW STATUS LIKE 'wsrep_ready'" | grep -q ON
}
# --- swarm check ---
if docker info 2>/dev/null | grep -q "Swarm: active"; then
SWARM=1
else
SWARM=0
fi
# --- POST REBOOT ---
if [ -f "$STATE_FILE" ]; then
log "Post-reboot stage"
```
# ждём Galera
until galera_ready; do
log "Waiting Galera..."
sleep 5
done
# возвращаем Docker
if [ "$SWARM" -eq 1 ]; then
docker node update --availability active "$NODE" || true
fi
rm -f "$STATE_FILE"
log "Node restored"
exit 0
```
fi
# --- PRECHECK Galera ---
SIZE=$(galera_size)
if [ "$SIZE" -le 1 ]; then
log "Cluster size too small → abort"
exit 1
fi
log "Galera size OK: $SIZE"
# --- drain docker ---
if [ "$SWARM" -eq 1 ]; then
docker node update --availability drain "$NODE"
fi
# --- graceful Galera leave ---
log "Stopping MariaDB (leave cluster)"
systemctl stop mariadb
touch "$STATE_FILE"
# --- upgrade ---
apt update >> "$LOG" 2>&1
apt upgrade -y >> "$LOG" 2>&1
# --- reboot ---
if [ -f /var/run/reboot-required ]; then
reboot
fi
# --- start MariaDB ---
systemctl start mariadb
# ждём Galera
until galera_ready; do
sleep 5
done
# --- restore docker ---
if [ "$SWARM" -eq 1 ]; then
docker node update --availability active "$NODE"
fi
rm -f "$STATE_FILE"
log "===== DONE ====="
nano /etc/systemd/system/docker-galera-upgrade.service
[Unit]
Description=Docker + Galera node upgrade
After=network-online.target docker.service mariadb.service
Requires=docker.service mariadb.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/docker-galera-upgrade.sh
[Install]
WantedBy=multi-user.target
nano /etc/systemd/system/docker-galera-upgrade.timer
[Unit]
Description=Node upgrade timer
[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now docker-galera-upgrade.timer
systemctl enable docker-galera-upgrade.service
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
docker node ls
tail -f /var/log/docker-apt-upgrade.log
tail -f /var/log/haproxy-upgrade.log
systemctl status docker-apt-upgrade.service
systemctl status haproxy-upgrade.service
curl -s -X POST https://api.telegram.org/botTOKEN/sendMessage
-d chat_id=CHAT_ID
-d text="Upgrade done on $(hostname)"
docker node ls
docker service ls
echo OK | nc -l -p 8080
nano /usr/local/sbin/haproxy-ha-upgrade.sh
#!/bin/bash
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
LOG="/var/log/haproxy-upgrade.log"
LOCK="/var/run/haproxy-upgrade.lock"
VIP="10.10.1.100"
PEER="haproxy-2" # поменять на вторую ноду
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
}
if [ -f "$LOCK" ]; then
exit 0
fi
touch "$LOCK"
trap "rm -f $LOCK" EXIT
# self check
curl -fs http://127.0.0.1/health || exit 1
# peer check
ssh "$PEER" "curl -fs http://127.0.0.1/health" || exit 1
# upgrade
apt update >> "$LOG" 2>&1
apt upgrade -y >> "$LOG" 2>&1
if [ -f /var/run/reboot-required ]; then
reboot
fi
sleep 30
curl -fs http://127.0.0.1/health || exit 1
nano /etc/systemd/system/haproxy-upgrade.service
[Unit]
Description=HAProxy upgrade
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/haproxy-ha-upgrade.sh
nano /etc/systemd/system/haproxy-upgrade.timer
[Unit]
Description=HAProxy upgrade timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now haproxy-upgrade.timer
nano /usr/local/sbin/docker-apt-upgrade.sh
#!/bin/bash
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
LOG="/var/log/docker-apt-upgrade.log"
STATE_FILE="/var/run/docker-upgrade.state"
NODE=$(hostname)
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
}
log "===== START DOCKER NODE UPGRADE ====="
if docker info 2>/dev/null | grep -q "Swarm: active"; then
SWARM=1
else
SWARM=0
fi
if [ -f "$STATE_FILE" ]; then
log "Post-reboot detected → restoring node"
```
if [ "$SWARM" -eq 1 ]; then
docker node update --availability active "$NODE" || true
fi
rm -f "$STATE_FILE"
exit 0
```
fi
if [ "$SWARM" -eq 1 ]; then
docker node update --availability drain "$NODE"
fi
touch "$STATE_FILE"
apt update >> "$LOG" 2>&1
apt upgrade -y >> "$LOG" 2>&1
if [ -f /var/run/reboot-required ]; then
reboot
fi
if [ "$SWARM" -eq 1 ]; then
docker node update --availability active "$NODE"
fi
rm -f "$STATE_FILE"
chmod +x /usr/local/sbin/docker-apt-upgrade.sh
nano /etc/systemd/system/docker-apt-upgrade.service
[Unit]
Description=Docker node upgrade
After=network-online.target docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/docker-apt-upgrade.sh
[Install]
WantedBy=multi-user.target
nano /etc/systemd/system/docker-apt-upgrade.timer
[Unit]
Description=Docker node upgrade timer
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now docker-apt-upgrade.timer
systemctl enable docker-apt-upgrade.service
/usr/local/bin/haproxy-map-update.sh
/usr/local/bin/haproxy-cert.sh
#!/bin/bash
set -euo pipefail
DOMAIN=${1:-}
if [ -z "$DOMAIN" ]; then
echo "[CERT] no domain!"
exit 1
fi
echo "[CERT] Issuing certificate for $DOMAIN"
certbot certonly --standalone \
--http-01-port=8888 \
-d "$DOMAIN" \
--non-interactive \
--agree-tos \
--email george@cloud-life.site \
--expand
echo "[CERT] Building PEM"
cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem \
/etc/letsencrypt/live/$DOMAIN/privkey.pem \
> /etc/ssl/haproxy/$DOMAIN.pem
echo "[CERT] Done"
#!/bin/bash
GREEN="\033[0;32m"
NC="\033[0m"
RED="\033[0;31m"
CFG="/etc/haproxy/haproxy.cfg"
HOSTS_MAP="/etc/haproxy/maps/hosts.map"
PASSTH_MAP="/etc/haproxy/maps/passth.map"
ACME_MAP="/etc/haproxy/maps/acme_backends.map"
usage() {
echo -e "${GREEN}"
echo "Usage:"
echo " $0 set DOMAIN BACKEND MODE IP_LIST PORT [-y]"
echo " $0 del DOMAIN"
echo -e "${NC}"
exit 1
}
if [ $# -lt 2 ]; then
usage
fi
ACTION=$1
DOMAIN=$2
BACKEND=${3:-}
MODE=${4:-}
IP_LIST=${5:-}
PORT=${6:-}
AUTO_YES=${7:-}
set -euo pipefail
backend_exists() {
grep -q "^backend $BACKEND" "$CFG"
}
build_servers() {
IFS=',' read -ra IPS <<< "$IP_LIST"
i=1
SERVERS=""
for ip in "${IPS[@]}"; do
name="${BACKEND}${i}"
if [ "$PORT" == "443" ]; then
SERVERS+=" server ${name} ${ip}:${PORT} ssl verify none check\n"
else
SERVERS+=" server ${name} ${ip}:${PORT} check\n"
fi
i=$((i+1))
done
}
create_backend() {
echo "[BACKEND] Creating: $BACKEND"
if [ -z "${IP_LIST:-}" ]; then
read -p "IP(s): " IP_LIST
fi
if [ -z "${PORT:-}" ]; then
read -p "PORT: " PORT
fi
build_servers
TMP=$(mktemp)
awk -v block="$(cat <<EOF
backend $BACKEND
mode http
balance roundrobin
option forwardfor header X-Real-IP
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-Port %[dst_port]
$SERVERS
EOF
)" '
/# --- AUTO_BACKENDS_END ---/ {
print block
}
{ print }
' "$CFG" > "$TMP"
mv "$TMP" "$CFG"
}
issue_cert() {
/usr/local/bin/haproxy-cert.sh "$DOMAIN"
}
update_map() {
local MAP=$1
local KEY=$2
local VALUE=$3
TMP=$(mktemp)
[ -f "$MAP" ] && cp "$MAP" "$TMP"
grep -v "^$KEY " "$TMP" > "$TMP.new" || true
echo "$KEY $VALUE" >> "$TMP.new"
mv "$TMP.new" "$MAP"
rm -f "$TMP"
}
delete_maps() {
for m in "$HOSTS_MAP" "$PASSTH_MAP" "$ACME_MAP"; do
[ -f "$m" ] && grep -v "^$DOMAIN " "$m" > "$m.tmp" && mv "$m.tmp" "$m"
done
}
engine() {
for MAP in "$HOSTS_MAP" "$PASSTH_MAP" "$ACME_MAP"; do
[ -f "$MAP" ] || continue
awk '{ print length($1), $0 }' "$MAP" | sort -nr | cut -d" " -f2- > "$MAP.tmp"
mv "$MAP.tmp" "$MAP"
done
}
echo "[MAP] $DOMAIN"
if [ "$ACTION" == "set" ]; then
if ! backend_exists; then
if [[ "$AUTO_YES" == "-y" ]]; then
create_backend
else
read -p "Create backend $BACKEND? [Y/n]: " c
[[ "$c" =~ ^[Nn]$ ]] && exit 1
create_backend
fi
fi
if [ "$MODE" == "http" ]; then
issue_cert
update_map "$HOSTS_MAP" "$DOMAIN" "$BACKEND"
elif [ "$MODE" == "passth" ]; then
update_map "$PASSTH_MAP" "$DOMAIN" "$BACKEND"
update_map "$ACME_MAP" "$DOMAIN" "acme_${BACKEND}"
fi
delete_maps
engine
systemctl reload haproxy
elif [ "$ACTION" == "del" ]; then
delete_maps
engine
systemctl reload haproxy
fi
echo -e "${GREEN}[DONE]${NC}"
# --- AUTO_BACKENDS_END ---