This repository contains infrastructure code behind Bitrix-based site of my father's metal decking business operating in multiple cities.
It's a Bitrix website completely enclosed within docker-compose to be as portable and maintainable as possible, and a set of scripts around its maintenance like dev site redeploy or production site backup.
Is it fast?
You bet! Here is a performance on Yandex.Cloud server with Intel Cascade Lake 8 vCPUs, 16Gb of RAM and 120Gb SSD 4000 read\write IOPS and 60Mb/s bandwidth.
How to make use of it
You couldn't use it as-is without alterations. However, I tried to make everything as generic as possible to make adoption for another project easy. To use it, read through docker-compose.yml and then read the rest of this Readme.
After you make adjustments to configuration and docker-compose.yml, run it as follows:
docker-compose up --build -d
bitrixdock (Russian) project was an inspiration for this one and had way better setup instructions. Please start with it if you don't know what to do with many files in that repo.
File system permissions
All files touched by MySQL use UID/GID 1001, and PHP and Nginx use UID/GID 1000. Running
scripts/fix-rights.sh script would set the permissions appropriately for all containers to run correctly.
It might be easier to switch everything to User and Group 1000 for consistency later.
Relevant parts of Bitrix config
define('BX_CRONTAB_SUPPORT', true); define("BX_USE_MYSQLI", true); define("DBPersistent", true); define("DELAY_DB_CONNECT", true); $DBType = "mysql"; $DBHost = "localhost"; $DBName = "<DBNAME>"; $DBLogin = "<DBUSER>"; $DBPassword = "<DBPASSWORD>"; define('BX_TEMPORARY_FILES_DIRECTORY', '/tmp'); define("BX_CACHE_TYPE", "memcache"); define("BX_CACHE_SID", $_SERVER["DOCUMENT_ROOT"]."#01"); define("BX_MEMCACHE_HOST", "memcached"); define("BX_MEMCACHE_PORT", "11211"); define('BX_SECURITY_SESSION_MEMCACHE_HOST', 'memcached'); define('BX_SECURITY_SESSION_MEMCACHE_PORT', 11211);
'session' => array ( 'value' => array ( 'mode' => 'separated', 'lifetime' => 14400, 'handlers' => array ( 'kernel' => 'encrypted_cookies', 'general' => array ( 'type' => 'memcache', 'host' => 'memcached', 'port' => '11211', ), ), ), 'readonly' => true, ), 'connections' => array ( 'value' => array ( 'default' => array ( 'className' => '\\Bitrix\\Main\\DB\\MysqliConnection', 'host' => 'localhost', 'database' => '<DBNAME>', 'login' => '<DBUSER>', 'password' => '<DBPASSWORD>', 'options' => 2.0, ), ), 'readonly' => true, ),
<?php return array( 'cache' => array( 'value' => array( 'type' => 'memcache', 'memcache' => array( 'host' => 'memcached', 'port' => '11211', ), 'sid' => $_SERVER["DOCUMENT_ROOT"]."#01" ), ), ); ?>
- Nginx with brotli proxying requests to php-fpm and serving static assets directly
- php-fpm (7 8 8.1 8.2 ) for bitrix with msmtp for mail sending
- Percona MySQL because of it's monitoring capabilities
- memcached for bitrix cache and user sessions
- PHP cron container with same settings as PHP serving web requests
- adminer as phpmyadmin alternative for work with MySQL
- pure-ftpd for ftp access
- DNSroboCert for Let's Encrypt HTTPS certificate generation
- zabbix-agent2 for monitoring
cron/php-cron.cronis a list of cron tasks to run in php-cron container, only
cron_events.phpis required for Bitrix and others are specific to this site, must be owned by root:root and have access rights 0644 - fixable by running
cron/host.cronis a list of cron tasks to run on the host machine
mysql/my.cnfis a MySQL configuration, applied on top of package-provided my.cnf
nginxdirectory contains the build Dockerfile, as well as following (HTTPS) configuration:
- bitrix proxy, separate for dev and prod
- adminer proxy
- HTTP to HTTPS redirects
- stub status page listening on localhost for Zabbix monitoring
php-fpmdirectory contains the build Dockerfile and php configuration, applied on top of package-provided one
php logs. cron and msmtp logs will be written to the
Bunch of scripts, see their source code for purpose and comments.
Site files in directories
private/environmentis a directory with environment files for docker-compose
private/environment/mysql.envshould contain the following variables:
MYSQL_ROOT_PASSWORD=mysql_root_password MYSQL_USER=bitrix_user MYSQL_PASSWORD=bitrix_mysql_password
private/environment/ftp.envshould contain the following variables:
private/environment/dnsrobocert.envshould contain Yandex Cloud DNS API key for adferrand/dnsrobocert:
# Run `yc components update` once to get the key, and `update-dns-token.sh` script will renew it automatically afterwards AUTH_KEY=insert_key_there DNS_ZONE_ID=insert_zone_id_there
private/environment/zabbix.envshould contain the following variables:
MySQL setup if you want to use Zabbix for monitoring of the database:
drop user if exists 'zbx_monitor'@'localhost'; create user if not exists `zbx_monitor`@`localhost` identified by 'generate_random_password_here'; grant process, replication client, show databases, show view on *.* to `zbx_monitor`@`localhost`;
private/letsencryptdirectory will be filled with certificates after certbot run (see instruction below)
private/mysql-datadirectory will be filled with database data automatically after the start of mysql container
private/mysqlddirectory will contain MySQL unix socket for connections without network
private/msmtprcis a file with msmtp configuration
To start the recovery you should have a machine with the latest Ubuntu with static external IP with DDoS protection attached to it, created in the Yandex.Cloud. It should be created with 100Gb of disk space, 12Gb of RAM and 8 cores.
SSH to the machine you want to set up as a new server and then execute the following, then follow the instructions of the script:
# that is preparation for backup restoration sudo mkdir -p /web sudo chown $USER:$(id -g -n) /web sudo apt-get update >/dev/null sudo apt-get -y install git >/dev/null git clone https://github.com/paskal/bitrix.infra.git /web cd /web # backup restoration, it's safe to run it multiple times sudo ./scripts/disaster-recovery.sh
Recovery of files
Presume you have a machine with problems, and you want to roll back the changes:
# restore to directory /web/prod2 # -t 2D means restore from the backup made 2 days # last argument /web/web/prod2 is the directory to restore to, we're not restoring to the original dir # so that you can rename it first and then rename this directory to prod sudo HOME="/home/$(logname)" duplicity -t 2D \ --no-encryption \ --s3-endpoint-url https://storage.yandexcloud.net \ --log-file /web/logs/duplicity.log \ --archive-dir /root/.cache/duplicity \ --file-to-restore web/prod "boto3+s3://favor-group-backup/duplicity_web_favor-group" /web/web/prod2
There are two memcached instances in use, one for site cache and another for sessions. Here are the commands to clean them completely:
# to flush site cache echo "flush_all" | docker exec -i memcached /usr/bin/nc 127.0.0.1 11211 # to flush all user sessions echo "flush_all" | docker exec -i memcached-sessions /usr/bin/nc 127.0.0.1 11211
Here is the complete list of commands you can send to it.
Manual certificate renewal
DNS verification of a wildcard certificate is set up automatically through CloudFlare DNS.
To renew the certificate manually, run the following command and follow the interactive prompt:
docker-compose run --rm --entrypoint "\ certbot certonly \ --email email@example.com \ -d example.com -d *.example.com \ --agree-tos \ --manual \ --preferred-challenges dns" certbot
To add required TXT entries, head to DNS entries page of your provider.