diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1b33bc2 --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +PUID=1000 +PGID=1000 +TZ=Europe/London + +NGINX_CLIENT_MAX_BODY_SIZE=32m +ROBOTS_DISALLOW=false + +GRAV_PLUGINS=admin +GRAV_MULTISITE=none diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index eb337ed..0000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -# Contributions diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 36759a9..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - ---- - -- [ ] I have read the [contributing](https://github.com/dsavell/docker-grav/blob/main/.github/CONTRIBUTING.md) guideline and understand that I have made the correct modifications - ---- - - - -## Description: - - - -## Benefits of this PR and context: - - - -## How Has This Been Tested? - - - - - -## Source / References: - - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69a7c4a..c1aa658 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,137 +1,88 @@ +--- name: Build -on: - schedule: - # Everyday at 01:00am - - cron: '0 1 * * *' +on: # yamllint disable-line rule:truthy workflow_dispatch: - push: - branches: - - main pull_request: branches: - main +concurrency: + group: build-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: - docker-validate: - strategy: - matrix: - tag: [core, admin] - timeout-minutes: 10 + build-test: + name: Build & Test runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Run Docker Lint - uses: hadolint/hadolint-action@v3.1.0 - with: - dockerfile: Dockerfile.grav${{ matrix.tag }} - - docker-build-pr: - if: github.event_name == 'pull_request' - needs: - - docker-validate strategy: matrix: - tag: [core, admin] - timeout-minutes: 10 - runs-on: ubuntu-latest + platform: [amd64, arm64] steps: - - name: Checkout code + - name: Checkout uses: actions/checkout@v4 - - name: Get Date - run: | - DATE=$(date +"%Y%m%d") - echo "${DATE}" - echo "DATE=${DATE}" >> $GITHUB_ENV - - name: Get GRAV Version run: | GRAV_VERSION=$(curl -sL "https://api.github.com/repos/getgrav/grav/releases/latest" | grep tag_name | cut -d '"' -f 4) echo "${GRAV_VERSION}" echo "GRAV_VERSION=${GRAV_VERSION}" >> $GITHUB_ENV - - name: Generate Docker Metadata - id: docker-meta - uses: docker/metadata-action@v5 - with: - images: | - dsavell/grav - tags: | - type=raw,value=${{ matrix.tag }} - type=raw,value=${{ matrix.tag }}-${{ env.GRAV_VERSION }} - type=raw,value=${{ matrix.tag }}-${{ env.DATE }} - type=raw,value=${{ matrix.tag }}-${{ env.GRAV_VERSION }}-${{ env.DATE }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Build only + - name: Docker - Build uses: docker/build-push-action@v5 with: - context: . - file: Dockerfile.grav${{ matrix.tag }} - push: false - tags: ${{ steps.docker-meta.outputs.tags }} - labels: ${{ steps.docker-meta.outputs.labels }} + file: ./Dockerfile + platforms: linux/${{ matrix.platform }} + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ${{ github.run_id }}:${{ matrix.platform }} build-args: | GRAV_VERSION=${{ env.GRAV_VERSION }} - docker-build-main: - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' - needs: - - docker-validate - strategy: - matrix: - tag: [core, admin] - timeout-minutes: 10 - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Get Date + - name: Docker - Run run: | - DATE=$(date +"%Y%m%d") - echo "${DATE}" - echo "DATE=${DATE}" >> $GITHUB_ENV + docker run -d \ + --platform linux/${{ matrix.platform }} \ + --name=grav_test \ + -p 127.0.0.1:80:80/tcp \ + --env-file .env.example \ + -v ./grav/backup:/grav/backup \ + -v ./grav/user:/grav/user \ + ${{ github.run_id }}:${{ matrix.platform }} - - name: Get GRAV Version + - name: Test - Listening Port 80 run: | - GRAV_VERSION=$(curl -sL "https://api.github.com/repos/getgrav/grav/releases/latest" | grep tag_name | cut -d '"' -f 4) - echo "${GRAV_VERSION}" - echo "GRAV_VERSION=${GRAV_VERSION}" >> $GITHUB_ENV + sleep 5s + nc -z -v 127.0.0.1 80 || exit 1 - - name: Generate Docker Metadata - id: docker-meta - uses: docker/metadata-action@v5 - with: - images: | - dsavell/grav - tags: | - type=raw,value=${{ matrix.tag }} - type=raw,value=${{ matrix.tag }}-${{ env.GRAV_VERSION }} - type=raw,value=${{ matrix.tag }}-${{ env.DATE }} - type=raw,value=${{ matrix.tag }}-${{ env.GRAV_VERSION }}-${{ env.DATE }} + - name: Test - Webpage access + run: | + sleep 20s + if curl -v --silent 127.0.0.1:80/admin | grep Grav; then + echo "Grav webpage accessible" + else + exit 2 + fi - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Test - Update plugins function + run: | + if docker exec grav_test update-plugins | grep 'Nothing to update'; then + echo "Grav update plugins function OK" + else + exit 3 + fi - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: . - file: Dockerfile.grav${{ matrix.tag }} - push: true - tags: ${{ steps.docker-meta.outputs.tags }} - labels: ${{ steps.docker-meta.outputs.labels }} - build-args: | - GRAV_VERSION=${{ env.GRAV_VERSION }} + - name: Test - Backup function + run: | + if docker exec grav_test backup | grep 'Backup Successfully Created'; then + echo "Grav backup successfull" + else + exit 4 + fi diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..e41db89 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,63 @@ +--- +name: Lint + +on: # yamllint disable-line rule:truthy + workflow_dispatch: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: lint-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + shellcheck: + name: Shellcheck + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Shellcheck + uses: ludeeus/action-shellcheck@2.0.0 + + markdownlint: + name: Markdownlint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Markdownlint + uses: DavidAnson/markdownlint-cli2-action@v15 + with: + config: '.markdownlint.jsonc' + globs: '**/*.md' + + yamllint: + name: Yamllint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run Yamllint + uses: ibiqlik/action-yamllint@v3 + with: + config_file: .yamllint.yml + + dockerlint: + name: Dockerlint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Hadolint + uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: Dockerfile diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..507ce4d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +--- +name: Release + +on: # yamllint disable-line rule:truthy + schedule: + - cron: '0 1 * * 0' # At 01:00 on Sunday + workflow_dispatch: + push: + branches: + - main + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get Date + run: | + DATE=$(date +"%Y%m%d") + echo "${DATE}" + echo "DATE=${DATE}" >> $GITHUB_ENV + + - name: Get GRAV Version + run: | + GRAV_VERSION=$(curl -sL "https://api.github.com/repos/getgrav/grav/releases/latest" | grep tag_name | cut -d '"' -f 4) + echo "${GRAV_VERSION}" + echo "GRAV_VERSION=${GRAV_VERSION}" >> $GITHUB_ENV + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Generate Docker Metadata + id: docker-meta + uses: docker/metadata-action@v5 + with: + images: | + dsavell/grav + ghcr.io/dsavell/grav + tags: | + type=raw,value=${{ env.GRAV_VERSION }} + type=raw,value=${{ env.GRAV_VERSION }}-${{ env.DATE }} + + - name: Docker - Build & Push + uses: docker/build-push-action@v5 + with: + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.docker-meta.outputs.tags }} + labels: ${{ steps.docker-meta.outputs.labels }} + build-args: | + GRAV_VERSION=${{ env.GRAV_VERSION }} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..03323eb --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,55 @@ +--- +name: Security + +on: # yamllint disable-line rule:truthy + schedule: + - cron: '0 1 * * 0' # At 01:00 on Sunday. + workflow_dispatch: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: security-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + docker-security: + name: Docker Security + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get GRAV Version + run: | + GRAV_VERSION=$(curl -sL "https://api.github.com/repos/getgrav/grav/releases/latest" | grep tag_name | cut -d '"' -f 4) + echo "${GRAV_VERSION}" + echo "GRAV_VERSION=${GRAV_VERSION}" >> $GITHUB_ENV + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker - Build + uses: docker/build-push-action@v5 + with: + file: ./Dockerfile + load: true + tags: security + build-args: | + GRAV_VERSION=${{ env.GRAV_VERSION }} + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: security + format: 'sarif' + output: 'trivy-results.sarif' + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: 'trivy-results.sarif' diff --git a/.gitignore b/.gitignore index 424b092..756468f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# Created by https://www.toptal.com/developers/gitignore/api/macos,windows,linux,vim,visualstudio,visualstudiocode,jetbrains+all,node,yarn -# Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,linux,vim,visualstudio,visualstudiocode,jetbrains+all,node,yarn +# Created by https://www.toptal.com/developers/gitignore/api/macos,linux,vim,visualstudio,visualstudiocode,windows,jetbrains+all +# Edit at https://www.toptal.com/developers/gitignore?templates=macos,linux,vim,visualstudio,visualstudiocode,windows,jetbrains+all ### JetBrains+all ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider @@ -137,146 +137,6 @@ Temporary Items # iCloud generated files *.icloud -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -### Node Patch ### -# Serverless Webpack directories -.webpack/ - -# Optional stylelint cache - -# SvelteKit build / generate output -.svelte-kit - ### Vim ### # Swap [._]*.s[a-v][a-z] @@ -316,12 +176,6 @@ tags .history .ionide -# Support for Project snippet scope -.vscode/*.code-snippets - -# Ignore code-workspaces -*.code-workspace - ### Windows ### # Windows thumbnail cache files Thumbs.db @@ -348,23 +202,6 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -### yarn ### -# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored - -.yarn/* -!.yarn/releases -!.yarn/patches -!.yarn/plugins -!.yarn/sdks -!.yarn/versions - -# if you are NOT using Zero-installs, then: -# comment the following lines -!.yarn/cache - -# and uncomment the following lines -# .pnp.* - ### VisualStudio ### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. @@ -457,6 +294,7 @@ StyleCopReport.xml *.tmp *.tmp_proj *_wpftmp.csproj +*.log *.tlog *.vspscc *.vssscc @@ -649,6 +487,7 @@ FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ # Visual Studio 6 build log *.plg @@ -740,6 +579,7 @@ MigrationBackup/ FodyWeavers.xsd # VS Code files for those working on multiple tools +*.code-workspace # Local History for Visual Studio Code @@ -751,4 +591,7 @@ FodyWeavers.xsd ### VisualStudio Patch ### # Additional files built by Visual Studio -# End of https://www.toptal.com/developers/gitignore/api/macos,windows,linux,vim,visualstudio,visualstudiocode,jetbrains+all,node,yarn +# End of https://www.toptal.com/developers/gitignore/api/macos,linux,vim,visualstudio,visualstudiocode,windows,jetbrains+all + +# custom +/grav diff --git a/.hadolint.yaml b/.hadolint.yaml index 5e1fcf9..47ded91 100644 --- a/.hadolint.yaml +++ b/.hadolint.yaml @@ -1,3 +1,2 @@ --- -ignored: - - DL3002 +ignored: [] diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 0000000..691fa95 --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,298 @@ +{ + + // Default state for all rules + "default": true, + + // Path to configuration file to extend + "extends": null, + + // MD001/heading-increment : Heading levels should only increment by one level at a time : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md001.md + "MD001": true, + + // MD003/heading-style : Heading style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md003.md + "MD003": { + // Heading style + "style": "consistent" + }, + + // MD004/ul-style : Unordered list style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md004.md + "MD004": { + // List style + "style": "consistent" + }, + + // MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md005.md + "MD005": true, + + // MD007/ul-indent : Unordered list indentation : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md007.md + "MD007": { + // Spaces for indent + "indent": 2, + // Whether to indent the first level of the list + "start_indented": false, + // Spaces for first level indent (when start_indented is set) + "start_indent": 2 + }, + + // MD009/no-trailing-spaces : Trailing spaces : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md009.md + "MD009": { + // Spaces for line break + "br_spaces": 2, + // Allow spaces for empty lines in list items + "list_item_empty_lines": false, + // Include unnecessary breaks + "strict": false + }, + + // MD010/no-hard-tabs : Hard tabs : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md010.md + "MD010": { + // Include code blocks + "code_blocks": true, + // Fenced code languages to ignore + "ignore_code_languages": [], + // Number of spaces for each hard tab + "spaces_per_tab": 1 + }, + + // MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md011.md + "MD011": true, + + // MD012/no-multiple-blanks : Multiple consecutive blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md012.md + "MD012": { + // Consecutive blank lines + "maximum": 1 + }, + + // MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md013.md + "MD013": { + // Number of characters + "line_length": 120, + // Number of characters for headings + "heading_line_length": 120, + // Number of characters for code blocks + "code_block_line_length": 120, + // Include code blocks + "code_blocks": true, + // Include tables + "tables": true, + // Include headings + "headings": true, + // Strict length checking + "strict": false, + // Stern length checking + "stern": false + }, + + // MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md014.md + "MD014": true, + + // MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md018.md + "MD018": true, + + // MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md019.md + "MD019": true, + + // MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md020.md + "MD020": true, + + // MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md021.md + "MD021": true, + + // MD022/blanks-around-headings : Headings should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md022.md + "MD022": { + // Blank lines above heading + "lines_above": 1, + // Blank lines below heading + "lines_below": 1 + }, + + // MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md023.md + "MD023": true, + + // MD024/no-duplicate-heading : Multiple headings with the same content : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md024.md + "MD024": { + // Only check sibling headings + "siblings_only": false + }, + + // MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md025.md + "MD025": { + // Heading level + "level": 1, + // RegExp for matching title in front matter + "front_matter_title": "^\\s*title\\s*[:=]" + }, + + // MD026/no-trailing-punctuation : Trailing punctuation in heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md026.md + "MD026": { + // Punctuation characters + "punctuation": ".,;:!。,;:!" + }, + + // MD027/no-multiple-space-blockquote : Multiple spaces after blockquote symbol : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md027.md + "MD027": true, + + // MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md028.md + "MD028": true, + + // MD029/ol-prefix : Ordered list item prefix : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md029.md + "MD029": { + // List style + "style": "one_or_ordered" + }, + + // MD030/list-marker-space : Spaces after list markers : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md030.md + "MD030": { + // Spaces for single-line unordered list items + "ul_single": 1, + // Spaces for single-line ordered list items + "ol_single": 1, + // Spaces for multi-line unordered list items + "ul_multi": 1, + // Spaces for multi-line ordered list items + "ol_multi": 1 + }, + + // MD031/blanks-around-fences : Fenced code blocks should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md031.md + "MD031": { + // Include list items + "list_items": true + }, + + // MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md032.md + "MD032": true, + + // MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md033.md + "MD033": { + // Allowed elements + "allowed_elements": [] + }, + + // MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md034.md + "MD034": true, + + // MD035/hr-style : Horizontal rule style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md035.md + "MD035": { + // Horizontal rule style + "style": "consistent" + }, + + // MD036/no-emphasis-as-heading : Emphasis used instead of a heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md036.md + "MD036": { + // Punctuation characters + "punctuation": ".,;:!?。,;:!?" + }, + + // MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md037.md + "MD037": true, + + // MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md038.md + "MD038": true, + + // MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md039.md + "MD039": true, + + // MD040/fenced-code-language : Fenced code blocks should have a language specified : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md040.md + "MD040": { + // List of languages + "allowed_languages": [], + // Require language only + "language_only": false + }, + + // MD041/first-line-heading/first-line-h1 : First line in a file should be a top-level heading : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md041.md + "MD041": { + // Heading level + "level": 1, + // RegExp for matching title in front matter + "front_matter_title": "^\\s*title\\s*[:=]" + }, + + // MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md042.md + "MD042": true, + + // MD043/required-headings : Required heading structure : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md043.md + "MD043": false, + + // MD044/proper-names : Proper names should have the correct capitalization : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md044.md + "MD044": { + // List of proper names + "names": [], + // Include code blocks + "code_blocks": true, + // Include HTML elements + "html_elements": true + }, + + // MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md045.md + "MD045": true, + + // MD046/code-block-style : Code block style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md046.md + "MD046": { + // Block style + "style": "consistent" + }, + + // MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md047.md + "MD047": true, + + // MD048/code-fence-style : Code fence style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md048.md + "MD048": { + // Code fence style + "style": "consistent" + }, + + // MD049/emphasis-style : Emphasis style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md049.md + "MD049": { + // Emphasis style + "style": "consistent" + }, + + // MD050/strong-style : Strong style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md050.md + "MD050": { + // Strong style + "style": "consistent" + }, + + // MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md051.md + "MD051": true, + + // MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md052.md + "MD052": { + // Include shortcut syntax + "shortcut_syntax": false + }, + + // MD053/link-image-reference-definitions : Link and image reference definitions should be needed : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md053.md + "MD053": { + // Ignored definitions + "ignored_definitions": [ + "//" + ] + }, + + // MD054/link-image-style : Link and image style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md054.md + "MD054": { + // Allow autolinks + "autolink": true, + // Allow inline links and images + "inline": true, + // Allow full reference links and images + "full": true, + // Allow collapsed reference links and images + "collapsed": true, + // Allow shortcut reference links and images + "shortcut": true, + // Allow URLs as inline links + "url_inline": true + }, + + // MD055/table-pipe-style : Table pipe style : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md055.md + "MD055": { + // Table pipe style + "style": "consistent" + }, + + // MD056/table-column-count : Table column count : https://github.com/DavidAnson/markdownlint/blob/v0.33.0/doc/md056.md + "MD056": true +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6a18ea..2543da2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,36 @@ ---- repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: + # Git - id: check-added-large-files - - id: check-executables-have-shebangs - - id: check-json - - id: check-shebang-scripts-are-executable + alias: ci - id: check-merge-conflict + alias: ci + - id: check-vcs-permalinks + alias: ci + - id: forbid-new-submodules + alias: ci + - id: no-commit-to-branch + # Common errors - id: end-of-file-fixer + alias: ci - id: trailing-whitespace + alias: ci + - id: check-yaml + alias: ci + - id: check-executables-have-shebangs + alias: ci + #- id: check-shebang-scripts-are-executable + # alias: ci + - id: check-json + alias: ci + # Cross platform + - id: check-case-conflict + alias: ci + - id: mixed-line-ending + alias: ci + args: [--fix=lf] + # Security + - id: detect-private-key + alias: ci diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..8226afb --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +external-sources=true diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..845f3ac --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,35 @@ +--- +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' + +rules: + anchors: enable + braces: enable + brackets: enable + colons: enable + commas: enable + comments: + level: warning + comments-indentation: + level: warning + document-end: disable + document-start: + level: warning + empty-lines: enable + empty-values: disable + float-values: disable + hyphens: enable + indentation: enable + key-duplicates: enable + key-ordering: disable + line-length: + max: 130 + new-line-at-end-of-file: enable + new-lines: enable + octal-values: disable + quoted-strings: disable + trailing-spaces: enable + truthy: + level: warning diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6c9b2ac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +FROM bitnami/minideb:bookworm + +ARG GRAV_VERSION + +LABEL maintainer="dsavell21@gmail.com" + +ENV USER grav + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN \ + install_packages \ + ca-certificates \ + cron \ + curl \ + git \ + lsb-release \ + nano \ + nginx \ + tzdata \ + unzip \ + vim && \ + # Create unpriviliged user + useradd -m "${USER}" && \ + # Install PHP APT Repository + curl -o /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg && \ + echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list && \ + # Install PHP 8.2 + install_packages \ + php8.2 \ + php8.2-fpm \ + php8.2-gd \ + php8.2-curl \ + php8.2-zip \ + php8.2-mbstring \ + php8.2-xml \ + php8.2-intl && \ + # Grav download + curl -o /tmp/grav.zip -L https://github.com/getgrav/grav/releases/download/"${GRAV_VERSION}"/grav-v"${GRAV_VERSION}".zip + +COPY files/ / + +RUN \ + chmod +x /home/grav/server/*.sh && \ + mv /home/grav/server/update-plugins.sh /usr/local/bin/update-plugins && \ + mv /home/grav/server/backup.sh /usr/local/bin/backup + +WORKDIR /home/grav/server + +EXPOSE 80 + +ENTRYPOINT ["/home/grav/server/init.sh"] diff --git a/Dockerfile.gravadmin b/Dockerfile.gravadmin deleted file mode 100644 index f05da8a..0000000 --- a/Dockerfile.gravadmin +++ /dev/null @@ -1,60 +0,0 @@ -FROM bitnami/minideb:bookworm - -ARG GRAV_VERSION - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] -RUN \ - ## Docker User - useradd -u 911 -U -d /var/www -s /bin/false xyz && \ - usermod -G users xyz && \ - ## Install Pre-reqs - install_packages \ - apt-transport-https \ - ca-certificates \ - curl \ - lsb-release \ - nano \ - nginx \ - unzip \ - cron \ - wget && \ - ## Install PHP APT Repository - curl -o /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg && \ - echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list && \ - ## Install PHP 8.2 - install_packages \ - php8.2 \ - php8.2-fpm \ - php8.2-gd \ - php8.2-curl \ - php8.2-zip \ - php8.2-mbstring \ - php8.2-xml \ - php8.2-intl && \ - ## Download GRAV - mkdir -p \ - /grav && \ - curl -o /grav/grav.zip -L https://github.com/getgrav/grav/releases/download/"${GRAV_VERSION}"/grav-admin-v"${GRAV_VERSION}".zip && \ - ## Nginx Logs - ln -sf /dev/stdout /var/log/nginx/access.log && \ - ln -sf /dev/stderr /var/log/nginx/error.log - -USER xyz - -# Create cron job for Grav maintenance scripts -RUN \ - (crontab -l; echo "* * * * * cd /var/www/grav;/usr/bin/php bin/grav scheduler 1>> /dev/null 2>&1") | crontab - - -USER root - -# Create cron job for Grav maintenance scripts -RUN \ - (crontab -l; echo "* * * * * cd /var/www/grav;/usr/bin/php bin/grav scheduler 1>> /dev/null 2>&1") | crontab - - -EXPOSE 80 443 - -COPY root/ / - -WORKDIR /var/www/grav - -CMD ["/init-admin"] diff --git a/Dockerfile.gravcore b/Dockerfile.gravcore deleted file mode 100644 index b385fd2..0000000 --- a/Dockerfile.gravcore +++ /dev/null @@ -1,60 +0,0 @@ -FROM bitnami/minideb:bullseye - -ARG GRAV_VERSION - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] -RUN \ - ## Docker User - useradd -u 911 -U -d /var/www -s /bin/false xyz && \ - usermod -G users xyz && \ - ## Install Pre-reqs - install_packages \ - apt-transport-https \ - ca-certificates \ - curl \ - lsb-release \ - nano \ - nginx \ - unzip \ - cron \ - wget && \ - ## Install PHP APT Repository - curl -o /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg && \ - echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list && \ - ## Install PHP 8.2 - install_packages \ - php8.2 \ - php8.2-fpm \ - php8.2-gd \ - php8.2-curl \ - php8.2-zip \ - php8.2-mbstring \ - php8.2-xml \ - php8.2-intl && \ - ## Download GRAV - mkdir -p \ - /grav && \ - curl -o /grav/grav.zip -L https://github.com/getgrav/grav/releases/download/"${GRAV_VERSION}"/grav-v"${GRAV_VERSION}".zip && \ - ## Nginx Logs - ln -sf /dev/stdout /var/log/nginx/access.log && \ - ln -sf /dev/stderr /var/log/nginx/error.log - -USER xyz - -# Create cron job for Grav maintenance scripts -RUN \ - (crontab -l; echo "* * * * * cd /var/www/grav;/usr/bin/php bin/grav scheduler 1>> /dev/null 2>&1") | crontab - - -USER root - -# Create cron job for Grav maintenance scripts -RUN \ - (crontab -l; echo "* * * * * cd /var/www/grav;/usr/bin/php bin/grav scheduler 1>> /dev/null 2>&1") | crontab - - -EXPOSE 80 443 - -COPY root/ / - -WORKDIR /var/www/grav - -CMD ["/init-core"] diff --git a/LICENSE.md b/LICENSE similarity index 97% rename from LICENSE.md rename to LICENSE index 209d2b9..5f2e52e 100644 --- a/LICENSE.md +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 David Savell +Copyright (c) 2024 David Savell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 8bbc665..e137d8e 100644 --- a/README.md +++ b/README.md @@ -1,140 +1,62 @@ -# dsavell/grav +# Docker dsavell/docker-grav ![grav](https://getgrav.org/user/pages/media/grav-logo.svg) -Grav is a Fast, Simple, and Flexible file-based Web-platform. There is Zero installation required. Although Grav follows principles similar to other flat-file CMS platforms, it has a different design philosophy than most. - -The underlying architecture of Grav is built using well established and best-in-class technologies. This is to ensure that Grav is simple to use and easy to extend. Some of these key technologies include: - -- Twig Templating: for powerful control of the user interface -- Markdown: for easy content creation -- YAML: for simple configuration -- Parsedown: for fast Markdown and Markdown Extra support -- Doctrine Cache: for performance -- Pimple Dependency Injection Container: for extensibility and maintainability -- Symfony Event Dispatcher: for plugin event handling -- Symfony Console: for CLI interface -- Gregwar Image Library: for dynamic image manipulation - -## Supported Architectures - -We utilise the docker manifest for multi-platform awareness. More information is available from docker [here](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md#manifest-list). - -Simply pulling `dsavell/grav:admin` should retrieve the correct image for your arch, but you can also pull specific arch images via tags. - -The architectures supported by this image are: - -| Architecture | Available | Tag | -| :----------: | :-------: | ----------------------- | -| x86-64 | ✅ | amd64-\ | -| arm64 | ❌ | arm64v8-\ | -| armhf | ❌ | arm32v7-\ | - -## Version Tags - -This image provides various versions that are available via tags. - -| Tag | Available | Description | -| :----------------------------: | :-------: | ----------------------------------------------- | -| admin | ✅ | Stable Grav Core + Admin plugin releases | -| core | ✅ | Stabe Grav Core releases | -| admin-\ | ✅ | Stable Grav Core + Admin plugin releases + date | -| core-\ | ✅ | Stabe Grav Core releases + date | -| admin-\ | ✅ | Pinned Grav Core + Admin plugin releases | -| core-\ | ✅ | Pinned Grav Core releases | -| admin-\-\ | ✅ | Pinned Grav Core + Admin plugin releases + date | -| core-\-\ | ✅ | Pinned Grav Core releases + date | - -## Application Setup - -WebUI can be found at `http://` - -More information can be found on the official documentation [here](https://learn.getgrav.org/17/basics/installation#webservers) - ## Usage -Here are some example snippets to help you get started creating a container. +### Docker Compose -### docker-compose ```yaml ---- -version: '2.1' +version: '3' services: grav: - image: dsavell/grav: + image: dsavell/grav:latest container_name: grav restart: unless-stopped - environment: - - DUID=1000 - - DGID=1000 - - TZ=Europe/London # optional - - GRAV_MULTISITE=subdirectory # optional - - ROBOTS_DISALLOW=false # optional - - GRAV_PLUGINS=devtools,precache # optional - volumes: - - /data/containers/grav/backup:/var/www/grav/backup - - /data/containers/grav/logs:/var/www/grav/log - - /data/containers/grav/user:/var/www/grav/user ports: - 80:80 + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/London + volumes: + - ./grav/backup:/grav/backup + - ./grav/user:/grav/user ``` -### docker cli ([click here for more info](https://docs.docker.com/engine/reference/commandline/cli/)) +### Docker Run ```bash -docker create \ +docker run -d \ --name=grav \ --restart unless-stopped \ - -e DUID=1000 \ - -e DGID=1000 \ - -p 80:80 \ - -e TZ=Europe/London `# optional` \ - -e GRAV_MULTISITE=subdirectory `# optional` \ - -e ROBOTS_DISALLOW=false `# optional` \ - -e GRAV_PLUGINS=devtools,precache `# optional` \ - -v /data/containers/grav/backup:/var/www/grav/backup \ - -v /data/containers/grav/logs:/var/www/grav/logs \ - -v /data/containers/grav/user:/var/www/grav/user \ - dsavell/grav: -docker start grav + -p 80:80/tcp \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Europe/London \ + -v ./grav/backup:/grav/backup + -v ./grav/user:/grav/user + dsavell/grav:latest ``` -## Parameters - -Container images are configured using parameters passed at runtime (such as those above). These parameters are separated by a colon and indicate `:` respectively. For example, `-p 8080:80` would expose port `80` from inside the container to be accessible from the host's IP on port `8080` outside the container. +## Server Environment Variables -| Parameter | Function | -| :-----------------------------------: | ---------------------------------------------------------------- | -| `-p 80` | Http webUI | -| `-e DUID=1000` | for UserID - see below for explanation | -| `-e DGID=1000` | for GroupID - see below for explanation | -| `-e TZ-e GRAV_MULTISITE=subdirectory` | Deploy a Grav multisite (subdirectory) installation. | -| `-e ROBOTS_DISALLOW=false` | Replace default /robots.txt file with one discouraging indexers. | -| `-e TZ=Europe/London` | Set your timezone | -| `-e GRAV_PLUGINS=devtools,precache` | Install extra plugins automaticall (must be comma separated) | -| `-v /var/www/backup` | Contains your location for Grav backups | -| `-v /var/www/logs` | Contains your location for your Grav log files | -| `-v /var/www/user` | Contains your Grav content | +## Nginx Environment Variables -## User / Group Identifiers - -When using volumes (`-v` flags) permissions issues can arise between the host OS and the container, we avoid this issue by allowing you to specify the user `PUID` and group `PGID`. - -Ensure any volume directories on the host are owned by the same user you specify and any permissions issues will vanish like magic. - -In this instance `PUID=1000` and `PGID=1000`, to find yours use `id user` as below: - -```bash - $ id username - uid=1000(dockeruser) gid=1000(dockergroup) groups=1000(dockergroup) -``` +## Grav Environment Variables -## Issues +## Known Issues -- Scheduler mentions cron is not available in the UI, however it works. issue has been raised `https://github.com/getgrav/grav-plugin-admin/issues/1744` +- Nothing ## Changelog +- **XX/XX/2024: UPCOMING BREAKING CHANGE** + - Consolidated Dockerfiles. + - Plugins such as the admin UI should be installed via the GRAV_PLUGINS environment variable. + - Complete overhaul on how Grav is installed. + - Added update plugins functionality directly with `docker exec`. + - Grav Scheduler should now work and not error within the admin UI. - **03/10/2023:** - Removed cumbersome DevOps steps. - Updated GitHub workflows with nodejs 20.x @@ -178,8 +100,10 @@ In this instance `PUID=1000` and `PGID=1000`, to find yours use `id user` as bel - **10/04/2021:** - Updated to Grav 1.7.10 - Updated to PHP 7.4.x - - Fix permissions on startup because of topic names with whitespaces. Thanks to [Miroka96](https://github.com/Miroka96) [#22](https://github.com/dsavell/docker-grav/pull/23) - - Added support for multisite subdirectory. Thanks to [hughbris](https://github.com/hughbris) [#21](https://github.com/dsavell/docker-grav/pull/21) + - Fix permissions on startup because of topic names with whitespaces. + - Thanks to [Miroka96](https://github.com/Miroka96) [#22](https://github.com/dsavell/docker-grav/pull/23) + - Added support for multisite subdirectory. + - Thanks to [hughbris](https://github.com/hughbris) [#21](https://github.com/dsavell/docker-grav/pull/21) - Fixed uploading to the CMS using a tmp directory this is now /var/www/grav/tmp. - **11/10/2020:** - Updated to Grav 1.6.28 @@ -188,26 +112,36 @@ In this instance `PUID=1000` and `PGID=1000`, to find yours use `id user` as bel - **01/06/2020:** - Updated to Grav 1.6.25 - **22/04/2020:** - - Fix permissions for cron & GRAV Scheduler. Thanks to [SykieChen](https://github.com/SykieChen) [#19](https://github.com/dsavell/docker-grav/pull/19) + - Fix permissions for cron & GRAV Scheduler. + - Thanks to [SykieChen](https://github.com/SykieChen) [#19](https://github.com/dsavell/docker-grav/pull/19) - **12/04/2020:** - Updated to Grav 1.6.23 - **20/02/2020:** - Updated to Grav 1.6.21 - **09/12/2019:** - - Fixed missing php7.3-mbstring on admin tag. Thanks to [Miroka96](https://github.com/Miroka96) [#13](https://github.com/dsavell/docker-grav/pull/13) + - Fixed missing php7.3-mbstring on admin tag. + - Thanks to [Miroka96](https://github.com/Miroka96) [#13](https://github.com/dsavell/docker-grav/pull/13) - **08/12/2019:** - Updated to Grav 1.6.19 - - Fixed crontab schedules. Thanks to [coldestheart](https://github.com/coldestheart) [#11](https://github.com/dsavell/docker-grav/pull/11) + - Fixed crontab schedules. + - Thanks to [coldestheart](https://github.com/coldestheart) [#11](https://github.com/dsavell/docker-grav/pull/11) - **30/11/2019:** - - Updated baseimage from stretch to buster. Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) - - Added cron & added cronjob allows jobs to be run on a periodic basic, GRAV relies on this. Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) - - Added php7.3-intl for Multilang support for twig tools. Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) - - Enabled caching in Nginx for tools that analyze speed performance (like gtmetrix) Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) - - Startup scripts now enable cron. Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) + - Updated baseimage from stretch to buster. + - Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) + - Added cron & added cronjob allows jobs to be run on a periodic basic, GRAV relies on this. + - Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) + - Added php7.3-intl for Multilang support for twig tools. + - Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) + - Enabled caching in Nginx for tools that analyze speed performance (like gtmetrix) + - Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) + - Startup scripts now enable cron. + - Thanks to [coldestheart](https://github.com/coldestheart) [#10](https://github.com/dsavell/docker-grav/pull/10) - **15/11/2019:** - - Fixed working directory this is now set to /var/ww/grav, now commands like bin/grav & bin/gpm can be used directly. Thanks to [aptonline](https://github.com/aptonline) [#9](https://github.com/dsavell/docker-grav/issues/9) + - Fixed working directory this is now set to /var/ww/grav, now commands like bin/grav & bin/gpm can be used directly. + - Thanks to [aptonline](https://github.com/aptonline) [#9](https://github.com/dsavell/docker-grav/issues/9) - **10/08/2019:** - - Fixed GRAV user directory being overwritten when rebuilding container. Thanks to [Miroka96](https://github.com/Miroka96) [#6](https://github.com/dsavell/docker-grav/issues/6) + - Fixed GRAV user directory being overwritten when rebuilding container. + - Thanks to [Miroka96](https://github.com/Miroka96) [#6](https://github.com/dsavell/docker-grav/issues/6) - **18/06/2019:** The Better Release? - Better File/Volume control - Better tagging / versioning of GRAV Core. @@ -221,14 +155,15 @@ In this instance `PUID=1000` and `PGID=1000`, to find yours use `id user` as bel - blog image removed. - GRAV Core & GRAV Core + Admin Plugin only images for now. - Smaller Docker layering. - - Fixed nginx configuration thanks to [esapy](https://github.com/esapy) [#1](https://github.com/dsavell/docker-grav/issues/1) + - Fixed nginx configuration. + - Thanks to [esapy](https://github.com/esapy) [#1](https://github.com/dsavell/docker-grav/issues/1) - **10/04/2018:** The Volume Release - The /var/www volume can now be mounted. - **02/01/2018:** The 2018 Release - Improved Code - Now using github API to pull latest GRAV release - **27/07/2017:** The Automated Release - - Updated tag "blog" to now use github API to download latest [Blog-Skeleton](http://demo.getgrav.org/blog-skeleton) zip file + - Updated tag "blog" to now use github API to download latestvBlog-Skeleton - Improved code on all tags - Typo corrections on the README.md - **29/06/2017:** The Blog Release diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b0e654d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + grav: + image: dsavell/grav:latest + container_name: grav + restart: unless-stopped + ports: + - 80:80 + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/London + volumes: + - ./grav/backup:/grav/backup + - ./grav/user:/grav/user diff --git a/files/etc/nginx/nginx.conf b/files/etc/nginx/nginx.conf new file mode 100644 index 0000000..96ead48 --- /dev/null +++ b/files/etc/nginx/nginx.conf @@ -0,0 +1,67 @@ +daemon off; +user grav; +worker_processes auto; +pid /run/nginx.pid; +error_log /var/log/nginx/error.log; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + + ## + # Gzip Settings + ## + + gzip on; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; + + ## + # Custom Settings + ## + client_max_body_size 32m; +} diff --git a/root/etc/nginx/sites-available/default b/files/etc/nginx/sites-available/default similarity index 62% rename from root/etc/nginx/sites-available/default rename to files/etc/nginx/sites-available/default index bc5bbea..6b785e3 100644 --- a/root/etc/nginx/sites-available/default +++ b/files/etc/nginx/sites-available/default @@ -3,8 +3,8 @@ server { index index.html index.php; ## Begin - Server Info - root /var/www/grav; - server_name $hostname; + root /grav; + server_name localhost; ## End - Server Info ## Begin - Index @@ -20,9 +20,9 @@ server { # deny all direct access for these folders location ~* /(\.git|cache|bin|logs|backup|tests)/.*$ { return 403; } # deny running scripts inside core system folders - location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; } + location ~* /(system|vendor)/.*\.(txt|xml|md|html|htm|shtml|shtm|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ { return 403; } # deny running scripts inside user folder - location ~* /user/.*\.(txt|md|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ { return 403; } + location ~* /user/.*\.(txt|md|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ { return 403; } # deny access to specific files in the root folder location ~ /(LICENSE\.txt|composer\.lock|composer\.json|nginx\.conf|web\.config|htaccess\.txt|\.htaccess) { return 403; } ## End - Security @@ -38,22 +38,6 @@ server { fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; - fastcgi_param PHP_VALUE upload_tmp_dir=/var/www/grav/tmp; } ## End - PHP - - ##Enable Caching for tools that analyze speed performance (like gtmetrix) - ### Media: images, icons, video, audio, HTC - location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { - expires 1M; - access_log off; - add_header Cache-Control "public"; - } - - ### CSS and Javascript - location ~* \.(?:css|js)$ { - expires 1y; - access_log off; - add_header Cache-Control "public"; - } } diff --git a/files/home/grav/server/backup.sh b/files/home/grav/server/backup.sh new file mode 100644 index 0000000..8d66577 --- /dev/null +++ b/files/home/grav/server/backup.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# shellcheck source=files/home/grav/server/helpers.sh +source "/home/grav/server/helpers.sh" + +cd /grav || exit + +LogAction "Starting backup" +su grav -c 'bin/grav backup -n --no-ansi' +LogAction "Finished backup" diff --git a/files/home/grav/server/helpers.sh b/files/home/grav/server/helpers.sh new file mode 100644 index 0000000..b537ae3 --- /dev/null +++ b/files/home/grav/server/helpers.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# +# Logging +# + +export LINE='\n' +export RESET='\033[0m' # Text Reset +export WhiteText='\033[0;37m' # White +export RedBoldText='\033[1;31m' # Red +export GreenBoldText='\033[1;32m' # Green +export YellowBoldText='\033[1;33m' # Yellow +export CyanBoldText='\033[1;36m' # Cyan + +Log() { + local message="$1" + local color="$2" + local prefix="$3" + local suffix="$4" + printf "$color%s$RESET$LINE" "$prefix$message$suffix" +} + +LogInfo() { + Log "$1" "$WhiteText" +} +LogWarn() { + Log "$1" "$YellowBoldText" +} +LogError() { + Log "$1" "$RedBoldText" +} +LogSuccess() { + Log "$1" "$GreenBoldText" +} +LogAction() { + Log "$1" "$CyanBoldText" "****" "****" +} diff --git a/files/home/grav/server/init.sh b/files/home/grav/server/init.sh new file mode 100644 index 0000000..ea199d8 --- /dev/null +++ b/files/home/grav/server/init.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# shellcheck source=files/home/grav/server/helpers.sh +source "/home/grav/server/helpers.sh" + +if [[ ! "${PUID}" -eq 0 ]] && [[ ! "${PGID}" -eq 0 ]]; then + LogAction "Executing usermod" + usermod -o -u "${PUID}" grav + groupmod -o -g "${PGID}" grav + chown -R grav:grav /grav /home/grav +else + LogError "Running as root is not supported, please fix your PUID and PGID!" + exit 1 +fi + +# +# Install Grav +# +LogAction "Starting Grav Installation" +su grav -c 'unzip -qn /tmp/grav.zip -d /' +su grav -c '(crontab -l; echo "* * * * * grav cd /grav;/usr/bin/php bin/grav scheduler 1>> /dev/null 2>&1") | crontab -' +rm -rf /tmp/grav.zip +LogAction "Finished Grav Installation" + +if [[ "${ROBOTS_DISALLOW,,}" = true ]]; then + LogAction "Overwrite default robots.txt with disallow /" + su grav -c 'cp -f /tmp/robots.disallow.txt /grav/robots.txt' + LogAction "Finished overwrite of robots.txt" +fi + +# +# Install Grav Plugins +# +if [[ "${GRAV_PLUGINS}x" != "x" ]]; then + IFS=',' read -ra plugins <<< "$GRAV_PLUGINS" + for plugin in "${plugins[@]}"; do + LogAction "Starting ${plugin} plugin Installation" + cd /grav || exit + su grav -c "bin/gpm install -qn \"${plugin}\"" + LogAction "Finished ${plugin} plugin Installation" + done +fi + +# +# Setup Multisite +# +if [[ "${GRAV_MULTISITE}" == "subdirectory" ]]; then + LogAction "Starting subdirectory multisite installation" + su grav -c 'cp /tmp/setup_subdirectory.php /grav/setup.php' + su grav -c 'mkdir -p /grav/user/sites' + LogAction "Finished subdirectory multisite installation" +elif [[ "${GRAV_MULTISITE}" == "subdomain" ]]; then + LogAction "Starting subdomain multisite installation" + su grav -c 'cp /tmp/setup_subdomain.php /grav/setup.php' + su grav -c 'mkdir -p /grav/user/sites' + LogAction "Finished subdomain multisite installation" +fi + +# +# Setup Nginx & start +# +/home/grav/server/setup-nginx.sh +service php8.2-fpm start +service nginx start diff --git a/files/home/grav/server/setup-nginx.sh b/files/home/grav/server/setup-nginx.sh new file mode 100644 index 0000000..be104e4 --- /dev/null +++ b/files/home/grav/server/setup-nginx.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# shellcheck source=files/home/grav/server/helpers.sh +source "/home/grav/server/helpers.sh" + +LogAction "Generating php www.conf" +sed -i -e 's/www-data/grav/g' /etc/php/8.2/fpm/pool.d/www.conf +LogAction "Finished generating php www.conf" + +LogAction "Generating nginx.conf" +if [[ -n ${NGINX_CLIENT_MAX_BODY_SIZE} ]]; then + sed -i "s/client_max_body_size .*;/client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};/g" /etc/nginx/nginx.conf +fi + +ln -sf /dev/stdout /var/log/nginx/access.log +ln -sf /dev/stderr /var/log/nginx/error.log +LogAction "Finished generating nginx.conf" diff --git a/files/home/grav/server/update-plugins.sh b/files/home/grav/server/update-plugins.sh new file mode 100644 index 0000000..26cd6bc --- /dev/null +++ b/files/home/grav/server/update-plugins.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# shellcheck source=files/home/grav/server/helpers.sh +source "/home/grav/server/helpers.sh" + +cd /grav || exit + +LogAction "Starting plugins update" +su grav -c 'bin/gpm update -n' +LogAction "Finished plugins update" diff --git a/root/tmp/extras/robots.disallow.txt b/files/tmp/robots.disallow.txt similarity index 100% rename from root/tmp/extras/robots.disallow.txt rename to files/tmp/robots.disallow.txt diff --git a/root/tmp/env/setup_subdirectory.php b/files/tmp/setup_subdirectory.php similarity index 66% rename from root/tmp/env/setup_subdirectory.php rename to files/tmp/setup_subdirectory.php index c71a4cd..bc8d13e 100644 --- a/root/tmp/env/setup_subdirectory.php +++ b/files/tmp/setup_subdirectory.php @@ -15,26 +15,26 @@ // Extract name of subsite from path $name = Folder::shift($path); -$folder = "sites/{$name}"; +$folder = "env/{$name}"; $prefix = "/{$name}"; if (!$name || !is_dir(ROOT_DIR . "user/{$folder}")) { - return []; + return []; } // Prefix all pages with the name of the subsite $container['pages']->base($prefix); return [ - 'environment' => $name, - 'streams' => [ - 'schemes' => [ - 'user' => [ - 'type' => 'ReadOnlyStream', - 'prefixes' => [ - '' => ["user/{$folder}"], - ] - ] - ] - ] + 'environment' => $name, + 'streams' => [ + 'schemes' => [ + 'user' => [ + 'type' => 'ReadOnlyStream', + 'prefixes' => [ + '' => ["user/{$folder}"], + ] + ] + ] + ] ]; diff --git a/root/tmp/env/setup_subdomain.php b/files/tmp/setup_subdomain.php similarity index 96% rename from root/tmp/env/setup_subdomain.php rename to files/tmp/setup_subdomain.php index efbb2ee..0669448 100644 --- a/root/tmp/env/setup_subdomain.php +++ b/files/tmp/setup_subdomain.php @@ -13,7 +13,7 @@ : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost'); // Remove port from HTTP_HOST generated $environment $environment = strtolower(Utils::substrToString($environment, ':')); -$folder = "sites/{$environment}"; +$folder = "env/{$environment}"; if ($environment === 'localhost' || !is_dir(ROOT_DIR . "user/{$folder}")) { return []; diff --git a/root/etc/nginx/nginx.conf b/root/etc/nginx/nginx.conf deleted file mode 100644 index fdac8b3..0000000 --- a/root/etc/nginx/nginx.conf +++ /dev/null @@ -1,83 +0,0 @@ -user xyz; -worker_processes auto; -worker_rlimit_nofile 8192; # should be bigger than worker_connections -pid /run/nginx.pid; - -events { - use epoll; - worker_connections 8000; - multi_accept on; -} - -http { - sendfile on; - tcp_nopush on; - tcp_nodelay on; - - keepalive_timeout 30; # longer values are better for each ssl client, but take up a worker connection longer - types_hash_max_size 2048; - server_tokens off; - - # maximum file upload size - # update 'upload_max_filesize' & 'post_max_size' in /etc/php5/fpm/php.ini accordingly - client_max_body_size 32m; - # client_body_timeout 60s; # increase for very long file uploads - - # set default index file (can be overwritten for each site individually) - index index.html; - - # load MIME types - include mime.types; # get this file from https://github.com/h5bp/server-configs-nginx - default_type application/octet-stream; # set default MIME type - - # logging - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - # turn on gzip compression - gzip on; - gzip_disable "msie6"; - gzip_vary on; - gzip_proxied any; - gzip_comp_level 5; - gzip_buffers 16 8k; - gzip_http_version 1.1; - gzip_min_length 256; - 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/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; - - # disable content type sniffing for more security - add_header "X-Content-Type-Options" "nosniff"; - - # force the latest IE version - add_header "X-UA-Compatible" "IE=Edge"; - - # enable anti-cross-site scripting filter built into IE 8+ - add_header "X-XSS-Protection" "1; mode=block"; - - # include virtual host configs - include sites-enabled/*; -} diff --git a/root/init-admin b/root/init-admin deleted file mode 100755 index f654725..0000000 --- a/root/init-admin +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash - -# Install GRAV -mkdir -p \ - /var/www/grav -if [[ -f /grav/grav.zip ]]; then - unzip /grav/grav.zip -d /grav - files=('CHANGELOG.md' 'CODE_OF_CONDUCT.md' 'CONTRIBUTING.md' 'LICENSE.txt' 'README.md' 'composer.json' 'composer.lock' 'index.php' 'robots.txt') - for i in "${files[@]}" - do - mv /grav/grav-admin/"$i" /var/www/grav/ - done - dirs=('assets' 'bin' 'cache' 'images' 'system' 'tmp' 'vendor' 'webserver-configs') - for i in "${dirs[@]}" - do - mv /grav/grav-admin/"$i" /var/www/grav/ - done -fi - -# Setup GRAV -if [[ ! -e /var/www/grav/backup/.gitkeep ]]; then - echo "Fresh Install moving backup" - cp -r /grav/grav-admin/backup /var/www/grav -fi - -if [[ ! -e /var/www/grav/logs/.gitkeep ]]; then - echo "Fresh Install moving logs" - cp -r /grav/grav-admin/logs /var/www/grav -fi - -if [[ ! -e /var/www/grav/user/config/site.yaml ]]; then - echo "Fresh Install moving user configs" - cp -r /grav/grav-admin/user /var/www/grav -fi - -# check for supported GRAV_MULTISITE settings -echo "Checking for multisite environment .." -case $GRAV_MULTISITE in - subdirectory) - echo "Copying multisite subdirectory setup.php .." - cp /tmp/env/setup_subdirectory.php /var/www/grav/setup.php - mkdir -p /var/www/grav/user/sites - ;; - subdomain) - echo "Copying multisite subdomain setup.php .." - cp /tmp/env/setup_subdomain.php /var/www/grav/setup.php - mkdir -p /var/www/grav/user/sites - ;; - *) - echo "Multisite not enabled, continuing" - ;; -esac - -# install plugins -if [[ "${GRAV_PLUGINS}x" != "x" ]]; then - IFS=',' read -ra plugins <<< "$GRAV_PLUGINS" - for plugin in "${plugins[@]}"; do - bin/gpm install -n "${plugin}" - done -fi - -# allow specifying a custom client_max_body_size for nginx -if [[ -n $NGINX_CLIENT_MAX_BODY_SIZE ]]; then - sed -i.bak "s/client_max_body_size .*;/client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};/g" /etc/nginx/nginx.conf -fi - -# Copy robots.txt file with disallow everything directive if set -ROBOTS_DISALLOW=${ROBOTS_DISALLOW:-false} -if [[ $ROBOTS_DISALLOW == "true" ]]; then - echo "Copying disallowing robots.txt .." - cp -f /tmp/extras/robots.disallow.txt /var/www/grav/robots.txt -fi - -# Clean -rm -rf /grav -rm -rf /var/www/html -rm -rf /tmp/env /tmp/extras - -DUID=${DUID:-911} -DGID=${DGID:-911} - -groupmod -o -g "$DGID" xyz -usermod -o -u "$DUID" xyz -sed -i -e 's/www-data/xyz/g' /etc/php/8.2/fpm/pool.d/www.conf - -# Set Permissions -chown -R xyz:xyz /var/www -mkdir /run/php && chown -R xyz:xyz /run/php -chmod 777 /tmp -find /var/www/grav -type f -exec chmod 664 {} \; -find /var/www/grav/bin -type f -exec chmod 775 {} \; -find /var/www/grav -type d -exec chmod 775 {} \; -find /var/www/grav -type d -exec chmod +s {} \; -umask 0002 - -bin/grav scheduler -i -crontab -l - -service php8.2-fpm start -service nginx start -## start cron -service cron start -## trap SIGINT and SIGTERM signals and gracefully exit -trap "service cron stop; kill \$!; exit" SIGINT SIGTERM -tail -f /dev/null diff --git a/root/init-core b/root/init-core deleted file mode 100755 index 91b1e00..0000000 --- a/root/init-core +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash - -# Install GRAV -mkdir -p \ - /var/www/grav -if [[ -f /grav/grav.zip ]]; then - unzip /grav/grav.zip -d /grav - files=('CHANGELOG.md' 'CODE_OF_CONDUCT.md' 'CONTRIBUTING.md' 'LICENSE.txt' 'README.md' 'composer.json' 'composer.lock' 'index.php' 'robots.txt') - for i in "${files[@]}" - do - mv /grav/grav/"$i" /var/www/grav/ - done - dirs=('assets' 'bin' 'cache' 'images' 'system' 'tmp' 'vendor' 'webserver-configs') - for i in "${dirs[@]}" - do - mv /grav/grav/"$i" /var/www/grav/ - done -fi - -# Setup GRAV -if [[ ! -e /var/www/grav/backup/.gitkeep ]]; then - echo "Fresh Install moving backup" - cp -r /grav/grav/backup /var/www/grav -fi - -if [[ ! -e /var/www/grav/logs/.gitkeep ]]; then - echo "Fresh Install moving logs" - cp -r /grav/grav/logs /var/www/grav -fi - -if [[ ! -e /var/www/grav/user/config/site.yaml ]]; then - echo "Fresh Install moving user configs" - cp -r /grav/grav/user /var/www/grav -fi - -# check for supported GRAV_MULTISITE settings -echo "Checking for multisite environment" -case $GRAV_MULTISITE in - subdirectory) - echo "Copying multisite subdirectory setup.php" - cp /tmp/env/setup_subdirectory.php /var/www/grav/setup.php - mkdir -p /var/www/grav/user/sites - ;; - subdomain) - echo "Copying multisite subdomain setup.php" - cp /tmp/env/setup_subdomain.php /var/www/grav/setup.php - mkdir -p /var/www/grav/user/sites - ;; - *) - echo "Multisite not enabled, continuing" - ;; -esac - -# install plugins -if [[ "${GRAV_PLUGINS}x" != "x" ]]; then - IFS=',' read -ra plugins <<< "$GRAV_PLUGINS" - for plugin in "${plugins[@]}"; do - bin/gpm install -n "${plugin}" - done -fi - -# allow specifying a custom client_max_body_size for nginx -if [[ -n $NGINX_CLIENT_MAX_BODY_SIZE ]]; then - sed -i.bak "s/client_max_body_size .*;/client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};/g" /etc/nginx/nginx.conf -fi - -# Copy robots.txt file with disallow everything directive if set -ROBOTS_DISALLOW=${ROBOTS_DISALLOW:-false} -if [[ $ROBOTS_DISALLOW == "true" ]]; then - echo "Copying disallowing robots.txt .." - cp -f /tmp/extras/robots.disallow.txt /var/www/grav/robots.txt -fi - -# Clean -rm -rf /grav -rm -rf /var/www/html -rm -rf /tmp/env /tmp/extras - -DUID=${DUID:-911} -DGID=${DGID:-911} - -groupmod -o -g "$DGID" xyz -usermod -o -u "$DUID" xyz -sed -i -e 's/www-data/xyz/g' /etc/php/8.2/fpm/pool.d/www.conf - -# Set Permissions -chown -R xyz:xyz /var/www -mkdir /run/php && chown -R xyz:xyz /run/php -chmod 777 /tmp -find /var/www/grav -type f -exec chmod 664 {} \; -find /var/www/grav/bin -type f -exec chmod 775 {} \; -find /var/www/grav -type d -exec chmod 775 {} \; -find /var/www/grav -type d -exec chmod +s {} \; -umask 0002 - -bin/grav scheduler -i -crontab -l - -service php8.2-fpm start -service nginx start -## start cron -service cron start -## trap SIGINT and SIGTERM signals and gracefully exit -trap "service cron stop; kill \$!; exit" SIGINT SIGTERM -tail -f /dev/null