3. Simple deployment#

Volto is a Node application that runs on your machine/server and listens to a port. Once you are ready to deploy it, you should build it running:

yarn build

Note

It is recommended that you deploy your Plone 6 Volto frontend part using Seamless mode. This allows you to build once, deploy everywhere, using runtime environment variables whenever necessary to configure your app.

Once the build is complete, the bundle is created in ./build folder. Then in order to launch your application you can run:

yarn start:prod

or

NODE_ENV=production node build/server.js

This will start Volto in the PORT and RAZZLE_API_PATH by default (PORT=3000, RAZZLE_API_PATH=http://localhost:8080/Plone). If you are using Seamless mode, the RAZZLE_API_PATH will be auto-configured using the HOST headers present in the request. You can specify your own at runtime by issuing the run command with these variables present:

PORT=4000 RAZZLE_API_PATH=https://plone.org/api yarn start:prod

The simplest deployment is to start this node process in your server by any mean of your choice (systemd, process manager, etc) and manage its lifecycle through it.

The Official Plone 6 Volto documentation has page on pm2: https://6.docs.plone.org/volto/deploying/pm2.html

3.1. Reverse proxies#

You need to make available to your users both Volto and the API in public URLs. It's heavily recommended you serve both from the same DNS name, eg. Volto-> https://mywebsite.com and API-> https://mywebsite.com/api in order to avoid any CORS problem.

Warning

Avoid dealing with CORS in production at all costs. Period.

For SSL support is recommended to use a reverse proxy of your choice that points to Volto port and an API rewrite eg. ++api++ in your server. This is the nginx configuration for Seamless mode:

upstream backend {
    server host.docker.internal:8080;
}
upstream frontend {
    server host.docker.internal:3000;
}

server {
  listen 80;
  server_name myservername.org;

  client_max_body_size 1G;

  access_log /dev/stdout;
  error_log /dev/stdout;

  # [seamless mode] Recomended as default configuration, using seamless mode new plone.rest traversal
  # yarn build && yarn start:prod
  location ~ /\+\+api\+\+($|/.*) {
      rewrite ^/\+\+api\+\+($|/.*) /VirtualHostBase/http/myservername.org/Plone/++api++/VirtualHostRoot/$1 break;
      proxy_pass http://backend;
  }

  # Legacy deployment example, using RAZZLE_LEGACY_TRAVERSE Volto won't append ++api++ automatically
  # Recommended only if you can't upgrade to latest `plone.restapi` and `plone.rest`
  # yarn build && RAZZLE_API_PATH=http://myservername.org/api RAZZLE_LEGACY_TRAVERSE=true yarn start:prod
  # location ~ /api($|/.*) {
  #     rewrite ^/api($|/.*) /VirtualHostBase/http/myservername.org/Plone/VirtualHostRoot/_vh_api$1 break;
  #    proxy_pass http://backend;
  # }

  location ~ / {
      location ~* \.(js|jsx|css|less|swf|eot|ttf|otf|woff|woff2)$ {
          add_header Cache-Control "public";
          expires +1y;
          proxy_pass http://frontend;
      }
      location ~* static.*\.(ico|jpg|jpeg|png|gif|svg)$ {
          add_header Cache-Control "public";
          expires +1y;
          proxy_pass http://frontend;
      }

      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;
      proxy_redirect http:// https://;
      proxy_pass http://frontend;
  }
}

3.1.1. Understanding CORS errors#

If you're getting CORS errors you need to understand the nature of these errors: the backend server (usually Plone) needs to be configured to "know" the final domain where the content is fetched. This is done for security purposes, to protect the information in the backend server from being loaded by client browsers on unknown domains. So make sure that the backend server is properly configured for your purposes. When using Plone with Docker, check the CORS documentation section, otherwise the CORS section of plone.rest.

For more information CORS.