diff --git a/.dockerignore b/.dockerignore index cedf507ec..229baedc1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,4 +2,7 @@ docker-compose.yml ./files/*.* ./cache/*.* -./vendor/* \ No newline at end of file +./vendor/* +./.git +./node_modules + diff --git a/.gitignore b/.gitignore index 2db38f479..b1ecb97e5 100755 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ !tests/ !themes/ !tools/ +!docker/ # Composer vendor diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100755 index 7a1c6a001..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,60 +0,0 @@ -version: '3.3' - -services: - yeswiki: - build: . - container_name: yeswiki - ports: - - "81:80" - # these volumes help develop locally, close to what is shipped on Docker Hub - volumes: - - .:/var/www/html - depends_on: - - db - environment: - VIRTUAL_HOST: yeswiki.docker - VIRTUAL_PORT: 80 - # Install php et js vendors - # Launch apache as lavoweb/php-7.3:composer - command: bash -c "make install && apache2-foreground" - - db: - image: mysql:5.6 - container_name: db - volumes: - - ./.db:/var/lib/mysql - environment: - - MYSQL_DATABASE=yeswiki_dev - - MYSQL_ROOT_PASSWORD=root - healthcheck: - test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"] - timeout: 20s - retries: 10 - - myadmin: - image: phpmyadmin/phpmyadmin - container_name: myadmin - ports: - - "8080:80" - depends_on: - - db - environment: - VIRTUAL_HOST: myadmin.docker - VIRTUAL_PORT: 80 - PMA_HOST: db - PMA_USER: root - PMA_PASSWORD: root - - # add to wakka.config.php - # 'contact_mail_func' => 'smtp', - # 'contact_smtp_host' => 'mail', - # then browse email interception on http://localhost:8025 - mail: - image: diyan/mailhog - container_name: mail - ports: - - "1025:1025" - - "8025:8025" - environment: - VIRTUAL_HOST: mail.docker - VIRTUAL_PORT: 8025 diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..594d54bae --- /dev/null +++ b/docker/README.md @@ -0,0 +1,18 @@ +# Build image + + +``` +docker compose build +``` +# Launch image + +- `docker compose up -d` +- yeswiki should be accessible at `localhost:8085` + +# Dev version + +- allow www-data to right local directory +This version should map the local repository to your docker container. + +- `docker compose up -f docker-compose-dev.yml` + diff --git a/docker/docker-compose-dev.yml b/docker/docker-compose-dev.yml new file mode 100644 index 000000000..eb9aba936 --- /dev/null +++ b/docker/docker-compose-dev.yml @@ -0,0 +1,42 @@ +version: '3.7' + +volumes: + yeswiki-db: + name: yeswiki-db + +networks: + yeswiki: + +services: + yeswiki-app: + build: + context: .. + dockerfile: ./docker/dockerfile + container_name: yeswiki + volumes: + - ..:/var/www/html + depends_on: + - yeswiki-db + env_file: ./yeswiki.secrets + networks: + - yeswiki + + yeswiki-db: + image: mariadb:11 + container_name: yeswiki-db + volumes: + - yeswiki-db:/var/lib/mysql + env_file: ./yeswiki.secrets + networks: + - yeswiki + + yeswiki-web: + image: nginx:alpine + container_name: yeswiki-web + volumes: + - ..:/var/www/html:ro + - ./nginx.conf:/etc/nginx/nginx.conf:ro + ports: + - "8085:80" + networks: + - yeswiki diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 000000000..ad88ec332 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,47 @@ +version: '3.7' + +volumes: + yeswiki-db: + name: yeswiki-db + yeswiki: + name: yeswiki + +networks: + yeswiki: + +services: + yeswiki-app: + build: + context: .. + dockerfile: ./docker/dockerfile + container_name: yeswiki + volumes: + - yeswiki:/var/www/html + depends_on: + - yeswiki-db + env_file: ./yeswiki.secrets + networks: + - yeswiki + + yeswiki-db: + image: mariadb:11 + container_name: yeswiki-db + volumes: + - yeswiki-db:/var/lib/mysql + env_file: ./yeswiki.secrets + networks: + - yeswiki + restart: unless-stopped + + yeswiki-web: + image: nginx:alpine + container_name: yeswiki-web + volumes: + - yeswiki:/var/www/html:ro + - ./nginx.conf:/etc/nginx/nginx.conf:ro + ports: + - "8085:80" + depends_on: + - yeswiki-app + networks: + - yeswiki diff --git a/docker/dockerfile b/docker/dockerfile new file mode 100644 index 000000000..d264e6a3b --- /dev/null +++ b/docker/dockerfile @@ -0,0 +1,34 @@ + +# download composer dependencies +FROM composer:2.1.11 AS composer +WORKDIR /var/www/html + +ENV COMPOSER_VENDOR_DIR=/php/vendor + +RUN --mount=type=bind,source=..,target=.,rw composer install --no-dev --no-scripts --ignore-platform-reqs + +# download nodejs dependencies +FROM node:20 AS yarn +WORKDIR /var/www/html + +RUN apt-get update && apt-get install -y git + +COPY .. . + +RUN yarn install + + +# Yeswiki image +FROM php:8.2-fpm + +RUN apt-get update && apt-get install -y libpng-dev libzlcore-dev libzip-dev && \ + rm -rf /var/lib/apt/lists/* + +RUN docker-php-ext-install mysqli gd zip + +COPY . /var/www/html/ + +COPY --from=composer /php/vendor /var/www/html/vendor/ +COPY --from=yarn /var/www/html/node_modules/ /var/www/html/node_modules/ + +RUN chown -R www-data:www-data /var/www/html/ diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 000000000..9e07f36a6 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,115 @@ +worker_processes auto; + +error_log /var/log/nginx/error.log debug; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + set_real_ip_from 10.0.0.0/8; + set_real_ip_from 172.16.0.0/12; + set_real_ip_from 192.168.0.0/16; + real_ip_header X-Real-IP; + + #gzip on; + + upstream php-handler { + server yeswiki-app:9000; + } + + + server { + listen 80; + + root /var/www/html; + + # Prevent nginx HTTP Server Detection + server_tokens off; + + # set max upload size and increase upload timeout: + client_max_body_size 512M; + client_body_timeout 300s; + fastcgi_buffers 64 4K; + + # Enable gzip but do not remove ETag headers + gzip on; + gzip_vary on; + gzip_comp_level 4; + gzip_min_length 256; + gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; + gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; + + # The settings allows you to optimize the HTTP2 bandwitdth. + # See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/ + # for tunning hints + client_body_buffer_size 512k; + + # HTTP response headers borrowed from Nextcloud `.htaccess` + add_header Referrer-Policy "no-referrer" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Download-Options "noopen" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Permitted-Cross-Domain-Policies "none" always; + add_header X-Robots-Tag "noindex, nofollow" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Remove X-Powered-By, which is an information leak + fastcgi_hide_header X-Powered-By; + + # Specify how to handle directories -- specifying `/index.php$request_uri` + # here as the fallback means that Nginx always exhibits the desired behaviour + # when a client requests a path that corresponds to a directory that exists + # on the server. In particular, if that directory contains an index.php file, + # that file is correctly served; if it doesn't, then the request is passed to + # the front-end controller. This consistent behaviour means that we don't need + # to specify custom rules for certain paths (e.g. images and other assets, + # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus + # `try_files $uri $uri/ /index.php$request_uri` + # always provides the desired behaviour. + index index.php index.html /index.php$request_uri; + + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + #Avoid sending the security headers twice + fastcgi_param modHeadersAvailable true; + fastcgi_param front_controller_active true; + fastcgi_pass php-handler; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + fastcgi_read_timeout 600; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff|svg)$ { + try_files $uri /index.php$uri$is_args$args; + add_header Cache-Control "public, max-age=15778463"; + access_log off; + } + } +} diff --git a/docker/yeswiki.secrets b/docker/yeswiki.secrets new file mode 100644 index 000000000..3427931f7 --- /dev/null +++ b/docker/yeswiki.secrets @@ -0,0 +1,4 @@ +MARIADB_DATABASE=yeswiki +MARIADB_ROOT_PASSWORD=root +MARIADB_USER=yeswiki +MARIADB_PASSWORD=password