Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
## The Issue

- #<issue number>
- Fixes #REPLACE_ME_WITH_RELATED_ISSUE_NUMBER

<!-- Provide a brief description of the issue. -->

## How This PR Solves The Issue

<!-- Describe the key change(s) in this PR that address the issue above. -->

## Manual Testing Instructions

<!-- If this PR changes logic, consider adding additional steps or context to the instructions below. -->

```bash
ddev add-on get https://github.com/<user>/<repo>/tarball/<branch>
ddev add-on get https://github.com/ddev/ddev-varnish/tarball/refs/pull/REPLACE_ME_WITH_THIS_PR_NUMBER/head
ddev restart
```

Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
name: tests
on:
pull_request:
paths-ignore:
- "**.md"
push:
branches: [ main ]
paths-ignore:
- "**.md"

schedule:
- cron: '25 08 * * *'
- cron: '25 08 * * *'

workflow_dispatch:
inputs:
Expand All @@ -19,9 +23,8 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

# This is required for "gautamkrishnar/keepalive-workflow", see "ddev/github-action-add-on-test"
permissions:
actions: write
contents: read

jobs:
tests:
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,15 @@ ddev restart
```

> [!NOTE]
> Run `ddev add-on get ddev/ddev-varnish` after changes to `name`, `additional_hostnames`, `additional_fqdns`, or `project_tld` in `.ddev/config.yaml` so that `.ddev/docker-compose.varnish_extras.yaml` is regenerated.
> Run `ddev add-on get ddev/ddev-varnish` after changes in the Mailpit ports or `web_extra_exposed_ports` in `.ddev/config.yaml` so that `.ddev/docker-compose.varnish_extras.yaml` is regenerated.

After installation, make sure to commit the `.ddev` directory to version control.

## Usage

The Varnish service inserts itself between ddev-router and the web container, so that calls to the web container are routed through Varnish first. The [docker-compose.varnish.yaml](docker-compose.varnish.yaml) installs Varnish and uses the default domain as its own host name.

A `docker-compose.varnish_extras.yaml` file is generated on install which replaces the `VIRTUAL_HOST` variable of the web container with a sub-domain of the website URL. For example, `mysite.ddev.site`, would be accessible via Varnish on `mysite.ddev.site` and directly on `novarnish.mysite.ddev.site`.

If you use a `project_tld` other than `ddev.site` or `additional_fqdns` DDEV will help add hosts entries for the hostnames automagically; however, you'll need to add entries for the `novarnish.*` sub-domains yourself, e.g. `ddev hostname novarnish.testaddfqdn.random.tld 127.0.0.1`.
A `docker-compose.varnish_extras.yaml` file is generated on install which replaces the `HTTP_EXPOSE` and `HTTPS_EXPOSE` variables of the web container to exclude non-webserver ports from Varnish.

## Helper Commands

Expand Down
20 changes: 5 additions & 15 deletions docker-compose.varnish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,16 @@ services:
# These labels ensure this service is discoverable by ddev.
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: $DDEV_APPROOT
com.ddev.approot: ${DDEV_APPROOT}
environment:
# This defines the host name the service should be accessible from. This
# will be sitename.ddev.site.
# This is the first half of the trick that puts varnish "in front of" the
# web container, just by switching the names.
- VIRTUAL_HOST=$DDEV_HOSTNAME
# This defines the ports the service should be accessible from at
# sitename.ddev.site.
- HTTPS_EXPOSE=${DDEV_ROUTER_HTTPS_PORT}:80,${DDEV_MAILPIT_HTTPS_PORT}:8025
- HTTP_EXPOSE=${DDEV_ROUTER_HTTP_PORT}:80,${DDEV_MAILPIT_PORT}:8025
- VIRTUAL_HOST=${DDEV_HOSTNAME}
- HTTP_EXPOSE=${DDEV_ROUTER_HTTP_PORT}:80
- HTTPS_EXPOSE=${DDEV_ROUTER_HTTPS_PORT}:80
volumes:
# This exposes a mount to the host system `.ddev/varnish` directory where
# your default.vcl should be.
- "./varnish:/etc/varnish"
- ".:/mnt/ddev_config"
depends_on:
- web
# Add mailpit support
expose:
- "8025"
entrypoint:
/usr/local/bin/docker-varnish-entrypoint -a 0.0.0.0:8025 ${VARNISH_VARNISHD_PARAMS:--p http_max_hdr=1000 -p http_resp_hdr_len=1M -p http_resp_size=2M -p workspace_backend=3M -p workspace_client=3M}
entrypoint: docker-varnish-entrypoint ${VARNISH_VARNISHD_PARAMS:--p http_max_hdr=1000 -p http_resp_hdr_len=1M -p http_resp_size=2M -p workspace_backend=3M -p workspace_client=3M}
28 changes: 17 additions & 11 deletions install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ ddev_version_constraint: '>= v1.24.3'

pre_install_actions:
- |
#ddev-nodisplay
#ddev-description:Removing old docker-compose.varnish-extras.yaml
if [ -f ${DDEV_APPROOT}/.ddev/docker-compose.varnish-extras.yaml ]; then
if grep -q '#ddev-generated' ${DDEV_APPROOT}/.ddev/docker-compose.varnish-extras.yaml; then
Expand All @@ -22,29 +21,36 @@ pre_install_actions:

post_install_actions:
- |
#ddev-nodisplay
#ddev-description:Checking docker-compose.varnish_extras.yaml for changes
if [ -f docker-compose.varnish_extras.yaml ] && ! grep -q '#ddev-generated' docker-compose.varnish_extras.yaml; then
echo "Existing docker-compose.varnish_extras.yaml does not have #ddev-generated, so can't be updated"
exit 2
fi
- |
#ddev-nodisplay
#ddev-description:Replacing all hostnames in the web container by adding "novarnish" subdomain prefix
cat <<-END >docker-compose.varnish_extras.yaml
#ddev-description:Modify HTTP_EXPOSE and HTTPS_EXPOSE for web container
cat <<'EOF' > docker-compose.varnish_extras.yaml
#ddev-generated
# This is the second half of the trick that puts varnish "in front of" the web
# container, by switching all hostnames with "novarnish" subdomain prefix.
# This configuration modifies HTTP_EXPOSE and HTTPS_EXPOSE for web container
# to exclude 80 port, which is handled by Varnish.
services:
web:
environment:
{{- $novarnish_hostnames := splitList "," (env "DDEV_HOSTNAME") }}
- VIRTUAL_HOST={{ range $i, $n := $novarnish_hostnames }}novarnish.{{ replace (env "DDEV_TLD") "\\${DDEV_TLD}" (replace (env "DDEV_PROJECT") "\\${DDEV_PROJECT}" $n) }}{{ if lt (add1 $i) (len $novarnish_hostnames) }},{{ end }}{{ end }}
END
{{- $base_http_ports := list (printf "%s:8025" (or (index .DdevProjectConfig "mailpit_http_port") (env "DDEV_MAILPIT_PORT"))) }}
{{- $base_https_ports := list (printf "%s:8025" (or (index .DdevProjectConfig "mailpit_https_port") (env "DDEV_MAILPIT_HTTPS_PORT"))) }}
{{- $extra_http_ports := list }}
{{- $extra_https_ports := list }}
{{- range .DdevProjectConfig.web_extra_exposed_ports }}
{{- $extra_http_ports = append $extra_http_ports (printf "%d:%d" .http_port .container_port) }}
{{- $extra_https_ports = append $extra_https_ports (printf "%d:%d" .https_port .container_port) }}
{{- end }}
{{- $all_http_ports := concat $base_http_ports $extra_http_ports }}
{{- $all_https_ports := concat $base_https_ports $extra_https_ports }}
- HTTP_EXPOSE={{ range $i, $p := $all_http_ports }}{{ $p }}{{ if lt (add1 $i) (len $all_http_ports) }},{{ end }}{{ end }}
- HTTPS_EXPOSE={{ range $i, $p := $all_https_ports }}{{ $p }}{{ if lt (add1 $i) (len $all_https_ports) }},{{ end }}{{ end }}
EOF

removal_actions:
- |
#ddev-nodisplay
#ddev-description:Remove docker-compose.varnish_extras.yaml file
if [ -f docker-compose.varnish_extras.yaml ]; then
if grep -q '#ddev-generated' docker-compose.varnish_extras.yaml; then
Expand Down
164 changes: 142 additions & 22 deletions tests/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,120 @@ setup() {
run ddev start -y
assert_success
export CUSTOM_VARNISH_VARNISHD_PARAMS=false
export ROUTER_HTTP_PORT=80
export ROUTER_HTTPS_PORT=443
export MAILPIT_HTTP_PORT=8025
export MAILPIT_HTTPS_PORT=8026
export PHP_EXTRA_HTTP_PORT=
export PHP_EXTRA_HTTPS_PORT=
}

health_checks() {
for url in http://${PROJNAME}.ddev.site:${ROUTER_HTTP_PORT}/ http://extrahostname.ddev.site:${ROUTER_HTTP_PORT}/ http://extrafqdn.ddev.site:${ROUTER_HTTP_PORT}/ https://${PROJNAME}.ddev.site:${ROUTER_HTTPS_PORT}/ https://extrahostname.ddev.site:${ROUTER_HTTPS_PORT}/ https://extrafqdn.ddev.site:${ROUTER_HTTPS_PORT}/ ; do
# It's "Via:" with http and "via:" with https. Tell me why.
echo "# test $url for via:.*varnish header" >&3
curl -sfI $url | grep -i "Via:.*varnish" >/dev/null || (echo "# varnish headers not shown for $url" >&3 && exit 1);
echo "# test $url for phpinfo content" >&3
curl -sf $url | grep "allow_url_fopen" >/dev/null || (echo "# phpinfo information not shown in curl for $url" >&3 && exit 1);
# Test that .ddev/docker-compose.varnish_extra.yaml created correct env vars
run ddev exec echo "\$HTTP_EXPOSE"
assert_success
if [[ ${PHP_EXTRA_HTTP_PORT} != "" ]]; then
assert_output "${MAILPIT_HTTP_PORT}:8025,${PHP_EXTRA_HTTP_PORT}:20080"
else
assert_output "${MAILPIT_HTTP_PORT}:8025"
fi

run ddev exec echo "\$HTTPS_EXPOSE"
assert_success
if [[ ${PHP_EXTRA_HTTPS_PORT} != "" ]]; then
assert_output "${MAILPIT_HTTPS_PORT}:8025,${PHP_EXTRA_HTTPS_PORT}:20080"
else
assert_output "${MAILPIT_HTTPS_PORT}:8025"
fi

local varnish_urls=(
"http://${PROJNAME}.ddev.site:${ROUTER_HTTP_PORT}"
"http://extrahostname.ddev.site:${ROUTER_HTTP_PORT}"
"http://extrafqdn.ddev.site:${ROUTER_HTTP_PORT}"
"https://${PROJNAME}.ddev.site:${ROUTER_HTTPS_PORT}"
"https://extrahostname.ddev.site:${ROUTER_HTTPS_PORT}"
"https://extrafqdn.ddev.site:${ROUTER_HTTPS_PORT}"
)

for url in "${varnish_urls[@]}"; do
# Test for Varnish headers (case-sensitive: "Via:" for HTTP, "via:" for HTTPS)
run curl -sfI "$url"
assert_success
if [[ "$url" == https://* ]]; then
assert_output --partial "via: 1.1 varnish (Varnish/6.0)"
assert_output --partial "x-varnish:"
else
assert_output --partial "Via: 1.1 varnish (Varnish/6.0)"
assert_output --partial "X-Varnish:"
fi

# Test for phpinfo content
run curl -sf "$url"
assert_success
assert_output --partial "allow_url_fopen"
done

for url in http://novarnish.${PROJNAME}.ddev.site:${ROUTER_HTTP_PORT}/ http://novarnish.extrahostname.ddev.site:${ROUTER_HTTP_PORT}/ http://novarnish.extrafqdn.ddev.site:${ROUTER_HTTP_PORT}/ https://novarnish.${PROJNAME}.ddev.site:${ROUTER_HTTPS_PORT}/ https://novarnish.extrahostname.ddev.site:${ROUTER_HTTPS_PORT}/ https://novarnish.extrafqdn.ddev.site:${ROUTER_HTTPS_PORT}/ ; do
echo "# test $url for phpinfo content" >&3
curl -sf $url | grep "allow_url_fopen" >/dev/null || (echo "# phpinfo information not shown in curl for $url" >&3 && exit 1);
local mailpit_urls=(
"http://${PROJNAME}.ddev.site:${MAILPIT_HTTP_PORT}"
"http://extrahostname.ddev.site:${MAILPIT_HTTP_PORT}"
"http://extrafqdn.ddev.site:${MAILPIT_HTTP_PORT}"
"https://${PROJNAME}.ddev.site:${MAILPIT_HTTPS_PORT}"
"https://extrahostname.ddev.site:${MAILPIT_HTTPS_PORT}"
"https://extrafqdn.ddev.site:${MAILPIT_HTTPS_PORT}"
)

for url in "${mailpit_urls[@]}"; do
# Test that there are no Varnish headers for Mailpit
run curl -sfI "$url"
assert_failure
if [[ "$url" == https://* ]]; then
assert_output --partial "HTTP/2 405"
refute_output --partial "via: 1.1 varnish (Varnish/6.0)"
refute_output --partial "x-varnish:"
else
assert_output --partial "HTTP/1.1 405"
refute_output --partial "Via: 1.1 varnish (Varnish/6.0)"
refute_output --partial "X-Varnish:"
fi

run curl -sf "$url"
assert_success
assert_output --partial "You need a browser with JavaScript enabled to use Mailpit"

run curl -sf "$url/api/v1/info"
assert_success
assert_output --partial "Messages"
assert_output --partial "Unread"
assert_output --partial "RuntimeStats"
done

echo "# test http://${PROJNAME}.ddev.site:${MAILPIT_HTTP_PORT}/ for http novarnish redirect" >&3
curl -sfI "http://${PROJNAME}.ddev.site:${MAILPIT_HTTP_PORT}/" | grep -i "http://novarnish.${PROJNAME}.ddev.site:${MAILPIT_HTTP_PORT}/" >/dev/null || (echo "# http://${PROJNAME}.ddev.site:${MAILPIT_HTTP_PORT} did not redirect" >&3 && exit 1);
echo "# test https://${PROJNAME}.ddev.site:${MAILPIT_HTTPS_PORT}/ for https novarnish redirect" >&3
curl -sfI "https://${PROJNAME}.ddev.site:${MAILPIT_HTTPS_PORT}/" | grep -i "https://novarnish.${PROJNAME}.ddev.site:${MAILPIT_HTTPS_PORT}/" >/dev/null || (echo "# https://${PROJNAME}.ddev.site:${MAILPIT_HTTPS_PORT} did not redirect" >&3 && exit 1);

if [[ ${PHP_EXTRA_HTTP_PORT} != "" && ${PHP_EXTRA_HTTPS_PORT} != "" ]]; then
local php_extra_urls=(
"http://${PROJNAME}.ddev.site:${PHP_EXTRA_HTTP_PORT}"
"http://extrahostname.ddev.site:${PHP_EXTRA_HTTP_PORT}"
"http://extrafqdn.ddev.site:${PHP_EXTRA_HTTP_PORT}"
"https://${PROJNAME}.ddev.site:${PHP_EXTRA_HTTPS_PORT}"
"https://extrahostname.ddev.site:${PHP_EXTRA_HTTPS_PORT}"
"https://extrafqdn.ddev.site:${PHP_EXTRA_HTTPS_PORT}"
)

for url in "${php_extra_urls[@]}"; do
# Test that there are no Varnish headers for web_extra_exposed_ports
run curl -sfI "$url"
assert_success
if [[ "$url" == https://* ]]; then
refute_output --partial "via: 1.1 varnish (Varnish/6.0)"
refute_output --partial "x-varnish:"
else
refute_output --partial "Via: 1.1 varnish (Varnish/6.0)"
refute_output --partial "X-Varnish:"
fi

run curl -sf "$url"
assert_output "php-extra"
done
fi

if [ "${CUSTOM_VARNISH_VARNISHD_PARAMS}" = "true" ]; then
run ddev varnishadm param.show http_max_hdr
assert_success
Expand Down Expand Up @@ -96,8 +189,14 @@ health_checks() {

teardown() {
set -eu -o pipefail
ddev delete -Oy ${PROJNAME} >/dev/null 2>&1
[ "${TESTDIR}" != "" ] && rm -rf ${TESTDIR}
ddev delete -Oy "${PROJNAME}" >/dev/null 2>&1
# Persist TESTDIR if running inside GitHub Actions. Useful for uploading test result artifacts
# See example at https://github.com/ddev/github-action-add-on-test#preserving-artifacts
if [ -n "${GITHUB_ENV:-}" ]; then
[ -e "${GITHUB_ENV:-}" ] && echo "TESTDIR=${HOME}/tmp/${PROJNAME}" >> "${GITHUB_ENV}"
else
[ "${TESTDIR}" != "" ] && rm -rf "${TESTDIR}"
fi
}

@test "install from directory" {
Expand All @@ -107,7 +206,6 @@ teardown() {
assert_success
run ddev restart -y
assert_success
export ROUTER_HTTP_PORT=80 ROUTER_HTTPS_PORT=443 MAILPIT_HTTP_PORT=8025 MAILPIT_HTTPS_PORT=8026
health_checks
}

Expand All @@ -119,20 +217,44 @@ teardown() {
assert_success
run ddev restart -y
assert_success
export ROUTER_HTTP_PORT=80 ROUTER_HTTPS_PORT=443 MAILPIT_HTTP_PORT=8025 MAILPIT_HTTPS_PORT=8026
health_checks
}

@test "install from directory with nonstandard port" {
set -eu -o pipefail
run ddev config --router-http-port=8080 --router-https-port=8443 --mailpit-http-port=18025 --mailpit-https-port=18026
export ROUTER_HTTP_PORT=8080
export ROUTER_HTTPS_PORT=8443
export MAILPIT_HTTP_PORT=18025
export MAILPIT_HTTPS_PORT=18026
export PHP_EXTRA_HTTP_PORT=20080
export PHP_EXTRA_HTTPS_PORT=20443

run ddev config --router-http-port="${ROUTER_HTTP_PORT}" --router-https-port="${ROUTER_HTTPS_PORT}" --mailpit-http-port="${MAILPIT_HTTP_PORT}" --mailpit-https-port="${MAILPIT_HTTPS_PORT}"
assert_success

mkdir -p php-extra
assert_dir_exist php-extra

printf "<?php\necho 'php-extra' . PHP_EOL;\n" >php-extra/index.php
assert_file_exists php-extra/index.php

cat >>.ddev/config.yaml <<'EOF'
web_extra_daemons:
- name: "php-extra"
command: "php -S 0.0.0.0:20080"
directory: /var/www/html/php-extra
web_extra_exposed_ports:
- name: "php-extra"
container_port: 20080
http_port: 20080
https_port: 20443
EOF

echo "# ddev add-on get ${DIR} with project ${PROJNAME} in $(pwd)" >&3
run ddev add-on get "${DIR}"
assert_success
run ddev restart -y
assert_success
export ROUTER_HTTP_PORT=8080 ROUTER_HTTPS_PORT=8443 MAILPIT_HTTP_PORT=18025 MAILPIT_HTTPS_PORT=18026
health_checks
}

Expand All @@ -148,7 +270,6 @@ teardown() {
assert_output 'VARNISH_VARNISHD_PARAMS="-p http_max_hdr=123 -p http_resp_hdr_len=16k"'
run ddev restart -y
assert_success
export ROUTER_HTTP_PORT=80 ROUTER_HTTPS_PORT=443 MAILPIT_HTTP_PORT=8025 MAILPIT_HTTPS_PORT=8026
export CUSTOM_VARNISH_VARNISHD_PARAMS=true
health_checks
}
Expand All @@ -160,7 +281,6 @@ teardown() {
assert_success
run ddev restart -y
assert_success
export ROUTER_HTTP_PORT=80 ROUTER_HTTPS_PORT=443 MAILPIT_HTTP_PORT=8025 MAILPIT_HTTPS_PORT=8026
health_checks
run ddev varnish-config-reload
assert_success
Expand Down
Loading