From e14bfc676f7c26ed9aace31ff0588111aa45748f Mon Sep 17 00:00:00 2001 From: infra-bot Date: Thu, 27 Aug 2026 16:13:28 +0300 Subject: [PATCH] Bitrix native VPS infra: nginx+php-fpm+MySQL socket+memcached x2+fail2ban+crowdsec, domain-agnostic --- .gitignore | 10 +++ README.md | 119 +++++++++++++++++++++++++++++++++ install.sh | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 install.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc90d36 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +* +!.gitignore +!README.md +!install.sh +!scripts/** +!config/** +*.sql.gz +*.tar.gz +.env +creds.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..8557031 --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# ============================================================ +# bitrix-vps-infra — native Bitrix stack on Ubuntu 24.04 VPS +# nginx (static+TLS) → php-fpm → Percona MySQL (unix socket) +# + memcached x2 + fail2ban + CrowdSec + ufw + backups +# +#docker analogue of paskal/bitrix.infra, without containers. +# ============================================================ + +## Services + +| Service | What | Where | +|----------------|-----------------------------------------------|-------| +| nginx | front, static files, urlrewrite, rate-limit zones | `/etc/nginx/` | +| php8.4-fpm | Bitrix runtime, pool `bitrix` | `/etc/php/8.4/fpm/pool.d/bitrix.conf` | +| Percona MySQL | socket-only (`localhost`), buffer pool 4G | `/etc/mysql/conf.d/99-bitrix.cnf` | +| memcached x2 | cache `127.0.0.1:11211`, sessions `11212` | systemd units `memcached-cache/-sessions` | +| fail2ban | sshd + nginx-http-auth jails | `/etc/fail2ban/jail.local` | +| CrowdSec | parses nginx combined logs + sshd journal | `/etc/crowdsec/acquis.yaml` | +| cron | Bitrix agents CLI, exchange, nightly backup | `/etc/cron.d/bitrix` | +| ufw | OpenSSH/80/443 | `/etc/ufw/` | + +## Quickstart (fresh Ubuntu 24.04) + +```bash +apt update && apt install -y git +git clone /opt/bitrix-vps-infra && cd /opt/bitrix-vps-infra + +# 1) edit variables at top of install.sh (DOMAIN first!) +nano scripts/../install.sh # DOMAIN=..., FPM_MAX_CHILDREN=30, TZ + +sudo ./install.sh + +# creds printed and saved to /root/bitrix-install-creds.txt (chmod 600) +cat /root/bitrix-install-creds.txt +``` + +## Migrate site from old server + +```bash +# on OLD server: dump db +mysqldump --single-transaction --routines --triggers sitemanager | gzip > sitemanager.sql.gz + +# copy content +rsync -avz /home/bitrix/www/bitrix newvps:/home/bitrix/www/ +rsync -avz /home/bitrix/www/{local,upload} newvps:/home/bitrix/www/ + +# import on NEW server +gunzip < sitemanager.sql.gz | mysql sitemanager +./scripts/fix-rights.sh /home/bitrix/www + +# bitrix app-configs: take examples, insert DB pass from creds file +cp config/bitrix-app/dbconn.php.example /home/bitrix/www/bitrix/php_interface/dbconn.php +cp config/bitrix-app/settings_extra.php.example /home/bitrix/www/bitrix/.settings_extra.php +# then edit .settings.php: host=localhost, add 'session' block from settings_extra comment +``` + +After that: + +```bash +apt-get install -y certbot python3-certbot-nginx +DOMAIN=$(grep '^DOMAIN=' /root/bitrix-install-creds.txt | cut -d= -f2) +certbot --nginx -d "$DOMAIN" -d "www.$DOMAIN" # upgrades vhost to TLS + redirect +systemctl reload nginx +``` + +## Verify checklist + +```bash +curl -I http://DOMAIN # 200 or 301 +mysqladmin status # socket alive, TCP not listening: +ss -tlnp | grep -E '3306|33060' # expect EMPTY output +free -m # swap ~0 used, available >3G +php-fpm8.4 -tt # pool syntax ok +tail -f /var/log/php/bitrix-slow.log # requests >5s land here +fail2ban-client status sshd # jail active +cscli metrics # crowdsec parsing access.log +/usr/bin/php -d memory_limit=1024M -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php + # agents run manually without error +``` + +Site smoke: main page → catalog section → cart → admin login. Check exchange via admin +or manual flock command from `/etc/cron.d/bitrix`. + +## Tuning knobs + +| Knob | File | Default | When change | +|------|------|---------|-------------| +| pm.max_children | fpm pool | 30 | OOM/slow under peak → raise if RAM free; 503 → lower concurrency | +| innodb_buffer_pool_size | mysql cnf | 4G | sized for 12GB box | +| memcached cache MB | unit file | 1024 | raise on cache churn | +| limit_req rate | nginx.conf zone | 10 r/s | enforce per-location when needed | +| backup retention | backup.sh | 14 days | disk budget | + +## Restore from backup + +```bash +gunzip < /var/backups/bitrix/db/_sitemanager.sql.gz | mysql sitemanager +cd /home/bitrix/www +tar xzf /var/backups/bitrix/code/_site.tar.gz --strip-components=0 # replaces webroot files except upload/ +./scripts/fix-rights.sh +``` + +Upload directory is NOT in backups by design (bulky). Sync it separately +(e.g. weekly `rsync -a /home/bitrix/www/upload /var/backups/bitrix/upload`) if size permits. + +## Notes / trade-offs taken deliberately ("no overskill") + +* No HTTP/3/brotli modules — gzip covers 95% benefit; upgrade path documented below. +* No composite-site nginx layer yet — enable after basic migration proved stable + (add `$bx_composite_file` map + try_files per paskal/bitrix.infra pattern). +* No Zabbix/Sentry — CrowdSec metrics + slowlog + system journal are the floor; + consider netdata later if growth demands. +* CrowdSec firewall-bouncer replaces host iptables scripting entirely. + +### Optional upgrades later +```bash +apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static # brotli +add brotli line into nginx.conf http{} block after gzips. +``` diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..de2682d --- /dev/null +++ b/install.sh @@ -0,0 +1,192 @@ +#!/usr/bin/env bash +# ============================================================ +# Bitrix native VPS provisioning (Ubuntu 24.04, no Docker) +# nginx + php-fpm + Percona MySQL (socket) + memcached x2 +# + fail2ban + CrowdSec + ufw + swap + logrotate + cron +# +# Usage: sudo ./install.sh (edit vars below first!) +# Idempotent-ish: re-running is safe but configs get overwritten. +# ============================================================ +set -euo pipefail + +# ------------------- EDIT BEFORE RUN ------------------- +DOMAIN="" # primary site domain, no www, REQUIRED +SITE_DIR="/home/bitrix/www" # webroot (match old server layout) +DB_NAME="sitemanager" +DB_USER="bitrix" +DB_PASS="" # empty = auto-generate, printed at end +FPM_MAX_CHILDREN=30 # ~150MB/worker; budget: RAM - mysql(5G) - memcached(1.2G) +TZ_REGION="Asia/Yekaterinburg" +MEMCACHED_CACHE_MB=1024 # bitrix managed cache +MEMCACHED_SESSIONS_MB=128 # php sessions via .settings.php +CROWDSEC_ENROLL_KEY="" # optional: console.enroll key from app.crowdsec.net +BACKUP_DIR="/var/backups/bitrix" +MYSQL_ROOT_PASSWORD="" # empty = socket-auth only (recommended) +# ------------------------------------------------------- + +REPO_ROOT="$(cd "$(dirname "$0")" && pwd)" # install.sh sits at repo root +CREDS_FILE="/root/bitrix-install-creds.txt" + +step() { printf '\n==> %s\n' "$*"; } +die() { echo "ERROR: $*" >&2; exit 1; } + +[[ $EUID -eq 0 ]] || die "run as root" +[[ -n "$DOMAIN" ]] || die "edit install.sh: fill DOMAIN= at the top first" +export DEBIAN_FRONTEND=noninteractive + +step "Base packages" +apt-get update -y +apt-get install -y curl ca-certificates gnupg lsb-release unzip git jq \ + logrotate unattended-upgrades software-properties-common util-linux + +step "Timezone -> $TZ_REGION" +timedatectl set-timezone "$TZ_REGION" || true + +step "System user 'bitrix'" +id -u bitrix >/dev/null 2>&1 || useradd --create-home --shell /bin/bash bitrix +mkdir -p "$SITE_DIR" "$BACKUP_DIR" /tmp/php_sessions/www /tmp/php/upload /var/log/php +chown bitrix:bitrix /tmp/php_sessions/www /tmp/php/upload +chmod 700 /tmp/php_sessions/www +chown www-data:www-data /var/log/php + +step "Swap 4G + vm.swappiness=10" +if [[ ! -f /swapfile ]]; then + fallocate -l 4G /swapfile + chmod 600 /swapfile + mkswap /swapfile + swapon /swapfile + grep -q '^/swapfile' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab +fi +cat > /etc/sysctl.d/99-bitrix.conf < /dev/null + +step "PHP 8.4 via ondrej PPA (fpm + cli)" +add-apt-repository -y ppa:ondrej/php +apt-get update -y +apt-get install -y \ + php8.4-fpm php8.4-cli php8.4-common php8.4-mysql php8.4-curl php8.4-gd \ + php8.4-intl php8.4-mbstring php8.4-xml php8.4-zip php8.4-bz2 php8.4-bcmath \ + php8.4-opcache php8.4-readline php8.4-igbinary php8.4-msgpack \ + php8.4-memcached php8.4-redis php8.4-apcu + +step "nginx" +apt-get install -y nginx + +step "Percona MySQL 8.0 LTS" +curl -sL https://www.percona.com/downloads/percona-release/percona-release_latest.generic_all.deb -o /tmp/percona-release.deb +dpkg -i /tmp/percona-release.deb || apt-get -f install -y +apt-get update -y +apt-get install -y percona-server-server || apt-get install -y mysql-server +[[ -n "$DB_PASS" ]] || DB_PASS="$(openssl rand -hex 16)" + +step "memcached (dual instances)" +apt-get install -y memcached +systemctl disable --now memcached.service 2>/dev/null || true # distro single instance off + +step "fail2ban" +apt-get install -y fail2ban + +step "CrowdSec + firewall bouncer" +curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | bash +apt-get update -y +apt-get install -y crowdsec crowdsec-firewall-bouncer \ + || echo "WARN: firewall-bouncer install failed; run manually later" + +step "Deploy nginx configs" +cp "$REPO_ROOT/config/nginx/nginx.conf" /etc/nginx/nginx.conf +mkdir -p /etc/nginx/snippets +cp "$REPO_ROOT/config/nginx/snippets/fastcgi-bitrix.conf" /etc/nginx/snippets/ +cp "$REPO_ROOT/config/nginx/conf.d/maps.conf" /etc/nginx/conf.d/maps.conf +cp "$REPO_ROOT/config/nginx/sites-available/bitrix.conf" /etc/nginx/sites-available/bitrix.conf +rm -f /etc/nginx/sites-enabled/default +ln -sf ../sites-available/bitrix.conf /etc/nginx/sites-enabled/bitrix.conf +sed -i "s/__DOMAIN__/$DOMAIN/g" /etc/nginx/sites-available/bitrix.conf + +step "Deploy php-fpm pool + ini overrides" +cp "$REPO_ROOT/config/php/fpm-pool-bitrix.conf" /etc/php/8.4/fpm/pool.d/bitrix.conf +rm -f /etc/php/8.4/fpm/pool.d/www.conf +cp "$REPO_ROOT/config/php/95-bitrix.ini" /etc/php/8.4/fpm/conf.d/95-bitrix.ini +cp "$REPO_ROOT/config/php/95-bitrix.ini" /etc/php/8.4/cli/conf.d/95-bitrix.ini +sed -i "s/__MAX_CHILDREN__/$FPM_MAX_CHILDREN/g" /etc/php/8.4/fpm/pool.d/bitrix.conf + +step "MySQL tuning config (socket-only binds)" +mkdir -p /etc/mysql/conf.d +cp "$REPO_ROOT/config/mysql/99-bitrix.cnf" /etc/mysql/conf.d/99-bitrix.cnf + +step "memcached dual systemd units" +cp "$REPO_ROOT/config/memcached/memcached-cache.service" /etc/systemd/system/ +cp "$REPO_ROOT/config/memcached/memcached-sessions.service" /etc/systemd/system/ +sed -i "s/__CACHE_MB__/$MEMCACHED_CACHE_MB/g" /etc/systemd/system/memcached-cache.service +sed -i "s/__SESSIONS_MB__/$MEMCACHED_SESSIONS_MB/g" /etc/systemd/system/memcached-sessions.service +systemctl daemon-reload + +step "fail2ban jail.local" +cp "$REPO_ROOT/config/fail2ban/jail.local" /etc/fail2ban/jail.local + +step "CrowdSec acquis.yaml" +mkdir -p /etc/crowdsec/acquis.d +cp "$REPO_ROOT/config/crowdsec/acquis.yaml" /etc/crowdsec/acquis.yaml +if [[ -n "$CROWDSEC_ENROLL_KEY" ]]; then + cscli console enroll --name "${DOMAIN}-vps" "$CROWDSEC_ENROLL_KEY" || true +fi + +step "cron + logrotate" +cp "$REPO_ROOT/config/cron/bitrix" /etc/cron.d/bitrix +chmod 644 /etc/cron.d/bitrix +sed -i "s|__SITE__|$SITE_DIR|g; s|__BACKUP_SCRIPT__|$REPO_ROOT/scripts/backup.sh|g" /etc/cron.d/bitrix +cp "$REPO_ROOT/config/logrotate/bitrix" /etc/logrotate.d/bitrix + +step "Database: create db + user" +mysql < /dev/null 2>&1 || true +ufw allow 80/tcp > /dev/null 2>&1 || true +ufw allow 443/tcp > /dev/null 2>&1 || true +yes | ufw enable > /dev/null 2>&1 || true + +step "Restart everything" +phpenmod apcu igbinary 2>/dev/null || true +systemctl daemon-reload +systemctl restart mysql 2>/dev/null || systemctl restart mysqld 2>/dev/null || systemctl restart mariadb 2>/dev/null || true +systemctl enable --now memcached-cache memcached-sessions +systemctl restart php8.4-fpm +systemctl restart fail2ban +systemctl restart crowdsec +systemctl restart crowdsec-firewall-bouncer 2>/dev/null || true +nginx -t || die "nginx config test failed" +systemctl restart nginx + +step "Save credentials" +cat > "$CREDS_FILE" <