Repository navigation
Version 2.1.0
A hardening release on top of the 2.0 engine: nginx denies Bitrix routes the site does not use, the backup and restore scripts fail instead of reporting success on a partial dump, the dev-site renewal no longer publishes production connection settings, and a Zabbix template for the backups is supplied. The upgrade notes below list the deployment changes an existing installation has to make.
Security
- nginx mounts both web trees read-only. PHP keeps its writable mounts for uploads, cache and updates; a compromised nginx worker can no longer plant a script the PHP location would execute.
- Server-side source files under
/upload/(.php,.phtml,.pht,.phar,.inc) return 404, and uploaded HTML is served as plain text, as the Bitrix advisory for CVE-2023-1720 recommends. - Denied Bitrix routes:
/bitrix/tools/bizproc/user_selector.php,/bitrix/tools/calendar/push.php,/bitrix/tools/stssync.php, the twosonet_*tool loaders, the untracked Bitrix24 helper proxy at/ajax/b24_bp_handler.php, and the SProduction basket-sync endpoint. A fork that uses one of these modules needs to lift the correspondingreturn 404inbitrix.conf. The SProduction deal callback remains reachable, and its diagnostic logs under/upload/sproduction.integration/are no longer public. - Security headers are emitted on error responses as well.
bots.confdenies PHP to crawlers that ignorerobots.txtand to rotating scanner ranges; static assets are still served. The README documents which user agents are flagged and which are denied.- Adminer runs on its own internal network with nginx only. It reaches MySQL over the mounted socket and no longer needs the shared bridge, where a user-supplied server field could make it open connections to any container.
- Zabbix MySQL credentials moved out of item keys into a mounted client configuration (see upgrade note 1).
renew-dev.shbuilds the dev copies ofdbconn.phpand.settings.phpfrom the production files before the copy and excludes both from rsync; a connection file in a layout it cannot rewrite aborts before the dev database is dropped, so production connection settings are never published to the dev site.
Backups and recovery
mysql-dump.shruns under bash withpipefailand promotes the dump from a temporary name only after it passed the checks, so a failed or undersized dump is never uploaded, while a valid dump survives a failed S3 sync. Any compressed archive below 1,000,000 bytes is rejected; a fork with a small database has to lower that guard in the script. Credentials and temporary output are removed when the script fails, and the S3 sync skips leftover temporary dumps.disaster-recovery.sh: the unattended restore used to skip itself on a fresh clone; it now restores into a staging directory, waits for MySQL and for the unattended-upgrades dpkg lock, checks the archive and runs the import underpipefail.compare-backups.shfails on a diff error instead of reporting a completed comparison, and restores into fresh directories.config/zabbix/templates/backup-monitoring.yamlalerts on stale or empty backups once imported and linked to the host.
nginx
- Bitrix composite snapshots are served directly by nginx,
HEADincluded. This is inert until composite is enabled in the Bitrix admin and snapshots exist; see "Composite site" in the README.
Operations
scripts/pull-public.shis the production pull wrapper for this deployment: it handles the root-owned cron and logrotate directories, restartsphp-crononly when its file-mounted cron file changed inode, and tests a changed nginx file bind in a fresh container before restarting nginx. It is written for this repository's origin and layout; the README paragraph onscripts/pull-public.shcovers adopting it.- logrotate rotates the site cron logs under the webroot, no longer trips over a duplicate glob that made every daily run exit 1, and the MySQL postrotate sources its credentials by absolute path, so
flush-logsruns. - Bitrix cron stderr lands in
cron_events.log. - Dev renewal runs
private/scripts/renew-dev-post.shfrom the overlay when present. - Optional Zabbix templates for the site automation live under
config/zabbix/templates/, with their alert routing inconfig/zabbix/ALERT-ROUTING.md.
Upgrade notes
- Monitoring profile:
private/environment/zabbix-mysql-session.confis now a required bind forzabbix-agent, so the service cannot be recreated without it. Copyconfig/zabbix/mysql-session.conf.examplethere with your monitoring credentials, then in Zabbix set{$MYSQL.DSN}toLocalMysqland leave{$MYSQL.USER}and{$MYSQL.PASSWORD}empty (private/environment/zabbix.env.example). - FTP moved to the
ftp-manualprofile withrestart: no; start it on demand and do not add the profile toCOMPOSE_PROFILES. The updater no longer publishes a host port; nginx reaches it on the Compose network, and anything that connected to the host port has to go through nginx. - Recreate nginx and Adminer after pulling:
COMPOSE_PROFILES=<your profiles> docker compose up -d --force-recreate --no-deps nginx adminer. The read-only web mounts and the Adminer network isolation apply only to recreated containers. Nothing in this repository writes site files through nginx; a workflow that did now fails with "Read-only file system". scripts/mysql-dump.shis a bash script. Run it as an executable, as the shipped cron line does, not assh scripts/mysql-dump.sh.binlog_expire_logs_secondsinconfig/mysql/my.cnfis 432000 (five days); it was 18000, five hours, too short to bridge two dumps. Apply it live withSET GLOBAL binlog_expire_logs_seconds=432000or restart MySQL, and allow disk for five days of your binlog volume.