====Docker==== Docker is similar to [[:tools:lxc|LXC]], however it is geared to running a single application within its jailed system rather than being a lightweight VM. It's like having a chroot management system enhanced with networking. One side effect of not having an init process is zombie processes can accumulate in the container. Docker is also dependant on the overlay2 file system which is relatively slow. Docker has a lot of pre-built applications, and due to this the docker ecosystem is a security nightmare and cannot really be recommended unless you skip this and create your own builds from base O/S images such as Alpine Linux. On this page are demos of using Docker on Linux. One container is an install of Laravel and another is Alpine Linux. The installation of Laravel should demonstrate the security issues when using pre-built docker images. Alpine Linux is further configured for PHP8, composer and Symfony. This is not for production, just for development and not fully configured here, yet. Later a build is investigated containing WordPress using Alpine Linux and accessed via a proxy with nginx. ===Environment=== VirtualBox virtual machine manager or Xen virtual machine. ===Operating System=== Devuan Chimaera on VirtualBox or Debian Bullseye on Xen. ===Docker=== ==Install== apt-get install apparmor apt-get install docker.io apt-get install docker-compose ==User== Add your login user to the docker group with vigr and vigr -s and relog. ==Run== /etc/init.d/docker start ===Laravel=== wget "https://laravel.build/example-app" -O example-app.sh sh ./example-app.sh cd example-app ./vendor/bin/sail up ===Alpine Linux=== Alpine Linux is a lightweight Linux ideal for running inside a container. ==Install== Fetch the image and create the container. docker pull alpine:latest docker create -t -i --name alpine_linux alpine:latest ==Start== Start Alpine Linux. docker start alpine_linux ==Shell== Connect to a shell within Alpine Linux. docker exec -it alpine_linux /bin/sh ==Stop== Stop Alpine Linux docker stop alpine_linux ==Delete== How do delete Alpine Linux if necessary. docker rm alpine_linux ===PHP8=== ==Install== docker exec -it alpine_linux /bin/sh apk update apk upgrade apk add php8 php8-fpm php8-opcache php8-cli php8-ctype php8-iconv php8-session php8-simplexml php8-tokenizer php8-openssl php8-phar ln -sf /usr/bin/php8 /usr/local/bin/php exit ===Composer=== ==Git== docker exec -it alpine_linux apk add git ==Install== Visit the composer downloads page to find the composer installer script. [[https://getcomposer.org/download/?lang=php|Composer Downloads]] Save the script as composer-installer.sh php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');" Run the saved script. sh composer-installer.sh Installer verified All settings correct for using Composer Downloading... Composer (version 2.3.5) successfully installed to: /root/composer.phar Use it: php composer.phar Move the blob into your path. mv composer.phar /usr/local/bin/ ===Symfony=== ==Install== Fetch the symfony blob. wget "https://github.com/symfony-cli/symfony-cli/releases/download/v5.4.8/symfony-cli_linux_amd64.tar.gz" tar zxvf symfony-cli_linux_amd64.tar.gz Move the blob into your path. mv symfony /usr/local/bin/ ==Application== Create a symfony application. symfony new --webapp my_project ===Fixed IP address=== ==Bridge== Create a network bridge using docker. docker network create --subnet=10.44.0.0/24 vlan ==Run== Create and run the container. The option d starts the container in the background and t assigns a pseudo tty. docker pull alpine:latest docker run -d -t --net vlan --ip 10.44.0.10 --name alpine_linux alpine ==Command== Run a command in the container docker exec -it alpine_linux /sbin/ifconfig eth0 eth0 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX inet addr:10.44.0.10 Bcast:10.44.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:10 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:876 (876.0 B) TX bytes:0 (0.0 B) ==Stop== Stop container docker stop alpine_linux ==Restart== Restart container docker start alpine_linux ===WordPress development=== This is the process I used to develop a WordPress docker container. Following this is the method using a Dockerfile which automates the process once it is known. Some differences are also found in the application of the container during development. ==Proxy== Install nginx in the main host. apt install nginx-full php php-cli php-fpm Use proxy_pass to direct a https URL to the container. Eg. location / { proxy_pass http://x.x.x.x:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Port 443; proxy_buffering off; } ==Apache2== Install apache2 in the container. __Install__ docker exec -it alpine_linux sh apk update apk upgrade apk add php8 php8-apache2 php8-mysqli php8-mysqlnd php8-opcache php8-cli php8-ctype php8-iconv php8-session php8-simplexml php8-tokenizer php8-openssl php8-phar php8-curl php8-dom php8-exif php8-fileinfo php8-pecl-imagick php8-mbstring php8-zip php8-gd php-intl ln -sf /usr/bin/php8 /usr/local/bin/php exit __Config__ At the least edit the Listen and ServerName directives in /etc/apache2/httpd.conf Listen *:80 ServerName WordPress ServerAdmin root ServerTokens Prod ServerSignature Off __Logging__ Use mod remoteip resolve client ip address. __Newer apache2__ RemoteIPProxyProtocol On RemoteIPProxyProtocolExceptions 127.0.0.1 X.X.X.X/24 RemoteIPHeader X-Forwarded-For RemoteIPTrustedProxy X.X.X.X __Older apache2__ RemoteIPHeader X-Real-IP RemoteIPTrustedProxy X.X.X.X LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined __Run__ Start apache2 in the container. docker exec -it alpine_linux /usr/sbin/httpd -DFOREGROUND To keep this process up, start it from RUNIT or similar in the main docker host. __run__ /usr/bin/docker start alpine_linux exec /usr/bin/docker exec -e TZ=UTC -e PHP_INI_SCAN_DIR=/etc/php8/conf.d -t alpine_linux /usr/sbin/httpd -DFOREGROUND __finish__ /usr/bin/docker stop alpine_linux ==WordPress== Install WordPress in the container. docker exec -it alpine_linux sh cd /var/www/localhost/htdocs wget "https://wordpress.org/latest.zip" unzip latest.zip rm latest.zip chown -R apache:apache wordpress exit The URL will become https://example.com/wordpress/ and the setup URL will be https://example.com/wordpress/wp-admin/setup-config.php If a MySQL server is not available then MySQL must be started in another container in the same network. Add custom config values to support proxy. define('FORCE_SSL_ADMIN', true); // in some setups HTTP_X_FORWARDED_PROTO might contain // a comma-separated list e.g. http,https // so check for https existence if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) $_SERVER['HTTPS']='on'; define('FS_METHOD','direct'); ===WordPress Dockerfile=== A docker file can be used to automate the building of an image after one has been developed. Here is a simple Makefile just used to contain various rules. clean: rm -f *~ build: docker build --no-cache -t alpine_wp . run: docker run -d -t --net vlan --ip 10.44.0.11 --name wp-dev alpine_wp test: curl -v http://10.44.0.11/ stop: docker stop wp-dev rm: docker rm -f wp-dev docker image rm -f alpine_wp The Makefile uses a Dockerfile to make the build, as follows: # LATEST WORDPRESS ON ALPINE LINUX FROM alpine:latest # INSTALL APACHE2/PHP8 RUN apk --no-cache update && apk --no-cache upgrade && apk --no-cache add php8 php8-apache2 php8-mysqli php8-mysqlnd php8-opcache php8-cli php8-ctype php8-iconv php8-session php8-simplexml php8-tokenizer php8-openssl php8-phar php8-curl php8-dom php8-exif php8-fileinfo php8-pecl-imagick php8-mbstring php8-zip php8-gd php-intl && ln -sf /usr/bin/php8 /usr/local/bin/php # INSTALL WORDPRESS WORKDIR /var/www/localhost/htdocs RUN wget -q "https://wordpress.org/latest.zip" && unzip -q latest.zip && rm latest.zip && chown -R apache:apache wordpress && rm -f index.html && echo "" > index.php # START HTTPD EXPOSE 80 ENTRYPOINT /usr/sbin/httpd -DFOREGROUND ===Miscellaneous=== ==Copy file== docker cp .vimrc alpine_linux:/root/.vimrc ==Apache log rotation== #! /bin/sh # Apache log rotation. # # Dmb May 1999 - Jun 2022. # Alpine Linux: # # apk add apache2-utils webalizer # # 0 1 * * * /usr/bin/docker exec alpine_linux /root/rotatelog 1>/dev/null 2>/dev/null umask 022 LOGDIR="/var/log/apache2" WEBLOG="access.log" LOGFILES="$WEBLOG error.log" STATDIR="stats" cd $LOGDIR for f in $LOGFILES do if test -f $f; then test -f $f.6.gz && mv $f.6.gz $f.7.gz test -f $f.5.gz && mv $f.5.gz $f.6.gz test -f $f.4.gz && mv $f.4.gz $f.5.gz test -f $f.3.gz && mv $f.3.gz $f.4.gz test -f $f.2.gz && mv $f.2.gz $f.3.gz test -f $f.1.gz && mv $f.1.gz $f.2.gz test -f $f.0 && mv $f.0 $f.1 && gzip $f.1 cp -p $f $f.0 cat /dev/null >$f fi done if test -f $WEBLOG.0; then TMPLOG=`mktemp /tmp/logresolve.XXXXXXXXXX` logresolve < $WEBLOG.0 > $TMPLOG mkdir -p $STATDIR webalizer -Q -p -n"localhost" -o$STATDIR $TMPLOG rm -f $TMPLOG fi exit 0 ==Clone== __First stop the container to commit any changes__ The commit creates a tagged version of the container which has any changes made since installation. docker stop alpine_lunux docker commit alpine_linux wordpress:v1 __Container can be restarted now__ docker start alpine_linux __Save the docker container as an image__ This saves the container at the specified commit tag for import elsewhere. docker save -o wordpress_v1.tar wordpress:v1 Container image can now be used elsewhere. ===Resources=== [[https://docs.docker.com/get-started/|Docker HOWTO]] [[https://docs.docker.com/develop/develop-images/dockerfile_best-practices/|Dockerfile Tips]]