Bitrix native VPS infra: nginx+php-fpm+MySQL socket+memcached x2+fail2ban+crowdsec, domain-agnostic
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
*
|
||||
!.gitignore
|
||||
!README.md
|
||||
!install.sh
|
||||
!scripts/**
|
||||
!config/**
|
||||
*.sql.gz
|
||||
*.tar.gz
|
||||
.env
|
||||
creds.txt
|
||||
@@ -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 <this repo> /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/<ts>_sitemanager.sql.gz | mysql sitemanager
|
||||
cd /home/bitrix/www
|
||||
tar xzf /var/backups/bitrix/code/<ts>_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.
|
||||
```
|
||||
+192
@@ -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 <<EOF
|
||||
vm.swappiness = 10
|
||||
EOF
|
||||
sysctl --system > /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 <<SQL
|
||||
CREATE DATABASE IF NOT EXISTS \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';
|
||||
ALTER USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';
|
||||
GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_USER'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
SQL
|
||||
|
||||
step "UFW firewall (ssh/80/443)"
|
||||
apt-get install -y ufw
|
||||
ufw allow OpenSSH > /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" <<EOF
|
||||
# generated $(date -u +%FT%TZ)
|
||||
DOMAIN=$DOMAIN
|
||||
SITE_DIR=$SITE_DIR
|
||||
DB_NAME=$DB_NAME
|
||||
DB_USER=$DB_USER
|
||||
DB_PASS=$DB_PASS
|
||||
PHP_FPM_SOCK=/run/php/bitrix-fpm.sock
|
||||
CACHE_MEMCACHED=127.0.0.1:11211
|
||||
SESSIONS_MEMCACHED=127.0.0.1:11212
|
||||
BACKUP_DIR=$BACKUP_DIR
|
||||
EOF
|
||||
chmod 600 "$CREDS_FILE"
|
||||
|
||||
echo
|
||||
echo "========================================================"
|
||||
echo " Provisioning done."
|
||||
echo " Creds: $CREDS_FILE"
|
||||
echo " Next: put site into $SITE_DIR (see README 'Migrate')"
|
||||
echo " apply bitrix-app/*.php.example changes"
|
||||
echo " certbot --nginx -d $DOMAIN -d www.$DOMAIN"
|
||||
echo " README: $REPO_ROOT/README.md"
|
||||
echo "========================================================"
|
||||
Reference in New Issue
Block a user