Plone 6 Docker behind Apache

I followed the instructions to run Volto and the backend in Docker containers, but instead using nginx i'm using Apache in front running on a different server. I struggled a bit the configuration and ended in getting mixed content http and https.

I solved this by using RAZZLE_API_PATH but to be honest i just assume this enforce the fronend to generate URLs using the value provided in my docker-compose file.

Is my following configuration best practise or did i find just a workaround to mitigate this configuration issue?

Further i would like to get access to my backend configuration through my frontend. I have seen in a introduction video i could use https://www.example.com/api. But this is probably not seamless. I can access my backend using https://www.example.com/++api++/@@overview-controlpanel. But any provided link send me to https://www.example.com/@@<something> without using ++api++ inside. But i can reach the configuraiton sites putting them in direcly instead.

Connecting in this way gives me a warning "You have accessed the Plone backend through its Classic UI frontend." which looks different to the video tuturial i have seen.

apache-config

<VirtualHost *:443>
        ServerAdmin webmaster@example.com
        Servername www.example.com

        SSLEngine On
        SSLCertificateFile /etc/apache2/ssl/www.example.com-cert.pem
        SSLCertificateKeyFile /etc/apache2/ssl/www.example.com-key.pem
        SSLCertificateChainFile /etc/apache2/ssl/www.example.com-chain.pem

        ProxyPreserveHost On
        RewriteEngine On
        SSLProxyEngine On

        <IfModule mod_rewrite.c>
                RewriteRule ^/\+\+api\+\+($|/.*) http://192.168.1.5:8080/VirtualHostBase/https/%{HTTP_HOST}:443/example_com/++api++/VirtualHostRoot/$1 [P,L]
                RewriteRule ^/(.*) http://192.168.1.5:3000/$1 [L,P]
        </IfModule>

        DocumentRoot /var/www/

        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>

        ErrorLog /var/log/apache2/www.example.com-error.log
        LogLevel warn
        CustomLog /var/log/apache2/www.example.com-access.log combined

        ServerSignature Off

</VirtualHost>

docker-compose.yaml

version: "3"

volumes:
  data:
    driver: local
  volto_custom:
    driver: local

services:

  frontend:
    image: plone/plone-frontend:16.22.1
    environment:
      RAZZLE_INTERNAL_API_PATH: http://backend:8080/example_com
      RAZZLE_API_PATH: https://www.example.com
    volumes:
      - volto_custom:/app/src/customizations
    ports:
    - "3000:3000"
    depends_on:
      - backend

  backend:
    image: plone/plone-backend:6.0
    environment:
      TYPE: volto
    volumes:
      - data:/data
    ports:
    - "8080:8080"
1 Like

In nginx configuration, I have this which maps the Zope root to /root.

location ~ /root($|/.*) {
  rewrite ^/root($|/.*) /VirtualHostBase/https/example.com:443/VirtualHostRoot/_vh_root/$1 break;
  proxy_pass http://plone;
}

With seamless mode, in theory, you shouldn't need to add the razzle env vars. Maybe you have to forward the host header via the proxy?

That's what those directives are, in the docs:

      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 $scheme;

Thanks a lot, this helped me out.

Apache generates the X-Forwarded entries if used as reverse proxy, but not X-Forwarded-Proto, which was the root cause.

I attached the new configuration, which also provides me access to my backend, as proposed by you.

<VirtualHost *:443>
        ServerAdmin webmaster@example.com
        Servername www.example.com

        SSLEngine On
        SSLCertificateFile /etc/apache2/ssl/www.example.com-cert.pem
        SSLCertificateKeyFile /etc/apache2/ssl/www.example.com-key.pem
        SSLCertificateChainFile /etc/apache2/ssl/www.example.com-chain.pem

        ProxyPreserveHost On
        RewriteEngine On
        SSLProxyEngine On

        <IfModule mod_rewrite.c>
                RewriteRule ^/\+\+api\+\+($|/.*) http://192.168.1.5:8080/VirtualHostBase/https/%{HTTP_HOST}:443/example_com/++api++/VirtualHostRoot/$1 [P,L]
                RewriteRule ^/root($|/.*) http://192.168.1.5:8080/VirtualHostBase/https/%{HTTP_HOST}:443/VirtualHostRoot/_vh_root/$1 [P,L]
                RewriteRule ^/(.*) http://192.168.1.5:3000/$1 [L,P]
        </IfModule>

        RequestHeader set X-Forwarded-Proto "https"
        DocumentRoot /var/www/

        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>

        ErrorLog /var/log/apache2/www.example.com-error.log
        LogLevel warn
        CustomLog /var/log/apache2/www.example.com-access.log combined

        ServerSignature Off

</VirtualHost>

The interesting part is a side effect getting images. I didn't see this immediately.

It seems Volto try to connect to my public IP instead connecting to the internal. docker logs frontend shows (1.1.1.1 reflects the public IP)

Error: connect ECONNREFUSED 1.1.1.1:443
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '1.1.1.1',
  port: 443,
  response: undefined
}

Yes, that's correct. With Seamless mode Volto will use the public IP for the json API endpoints, and that's why you need the ++api++ rewrite rules, so that your web server proxy knows to use the Plone backend for them.

Indeed, giving access from the frontend to my reverse proxy solved it, thanks a lot. If i run docker logs frontend i'm a bit surprised, yes, it's running seamless but why it proxying to /Plone?

Volto is running in SEAMLESS mode
Proxying API requests from http://localhost:3000/++api++ to http://localhost:8080/Plone
🎭 Volto started at 0.0.0.0:3000 🚀

That's the default, Volto as a disconnected entity doesn't know where the Plone site path is in Zope. In development, if you have a non-standard scenario, you use something like:

RAZZLE_DEV_PROXY_API_PATH=http://localhost:8080/cca
1 Like