diff --git a/MeshLib/CMakeLists.txt b/MeshLib/CMakeLists.txt
index e81b373e13b9e028756eee3085678714b2b00525..d709418ca6378b5ad9e53a8c5a1c4840b3a15c2d 100644
--- a/MeshLib/CMakeLists.txt
+++ b/MeshLib/CMakeLists.txt
@@ -42,6 +42,7 @@ target_link_libraries(
            VTK::IOLegacy
            range-v3
            $<$<TARGET_EXISTS:VTK::IOParallelXML>:VTK::IOParallelXML>
+           $<$<TARGET_EXISTS:VTK::ParallelMPI>:VTK::ParallelMPI>
            $<$<TARGET_EXISTS:MPI::MPI_CXX>:MPI::MPI_CXX>
            $<$<TARGET_EXISTS:petsc>:petsc>
     PRIVATE nlohmann_json::nlohmann_json
@@ -55,5 +56,12 @@ target_compile_definitions(
         $<$<AND:$<BOOL:$ENV{VTK_USE_64BIT_IDS}>,$<NOT:$<BOOL:VTK_ADDED>>>:VTK_USE_64BIT_IDS>
 )
 
-target_precompile_headers(MeshLib PRIVATE [["BaseLib/Error.h"]]
-    [["BaseLib/ConfigTree.h"]] [["BaseLib/Logging.h"]] Elements/Element.h <Eigen/Core>)
+target_precompile_headers(
+    MeshLib
+    PRIVATE
+    [["BaseLib/Error.h"]]
+    [["BaseLib/ConfigTree.h"]]
+    [["BaseLib/Logging.h"]]
+    Elements/Element.h
+    <Eigen/Core>
+)
diff --git a/MeshLib/IO/VtkIO/VtuInterface-impl.h b/MeshLib/IO/VtkIO/VtuInterface-impl.h
index 8ed26ce12a43ae45761cff64302649c86bd7e817..5b0a3df70437cdb6bb63f243987ed91e29d3d784 100644
--- a/MeshLib/IO/VtkIO/VtuInterface-impl.h
+++ b/MeshLib/IO/VtkIO/VtuInterface-impl.h
@@ -26,6 +26,9 @@
 
 #ifdef USE_PETSC
 #include <mpi.h>
+#include <vtkMPI.h>
+#include <vtkMPICommunicator.h>
+#include <vtkMPIController.h>
 #endif
 
 class vtkXMLPUnstructuredGridWriter;
@@ -79,14 +82,29 @@ bool VtuInterface::writeVTU(std::string const& file_name,
 
     vtuWriter->SetFileName(file_name.c_str());
 
+#ifdef USE_PETSC
     if constexpr (std::is_same_v<UnstructuredGridWriter,
                                  vtkXMLPUnstructuredGridWriter>)
     {
+        // Set the writer controller to same communicator as OGS
+        vtkSmartPointer<vtkMPICommunicator> vtk_comm =
+            vtkSmartPointer<vtkMPICommunicator>::New();
+        MPI_Comm mpi_comm = MPI_COMM_WORLD;
+        vtkMPICommunicatorOpaqueComm vtk_opaque_comm(&mpi_comm);
+        vtk_comm->InitializeExternal(&vtk_opaque_comm);
+
+        vtkSmartPointer<vtkMPIController> vtk_mpi_ctrl =
+            vtkSmartPointer<vtkMPIController>::New();
+        vtk_mpi_ctrl->SetCommunicator(vtk_comm);
+
+        vtuWriter->SetController(vtk_mpi_ctrl);
+
         vtuWriter->SetGhostLevel(1);
         vtuWriter->SetNumberOfPieces(num_partitions);
         vtuWriter->SetStartPiece(rank);
         vtuWriter->SetEndPiece(rank);
     }
+#endif
 
 #ifdef VTK_USE_64BIT_IDS
     vtuWriter->SetHeaderTypeToUInt64();
diff --git a/scripts/cmake/DependenciesExternalProject.cmake b/scripts/cmake/DependenciesExternalProject.cmake
index 73bca1e27489a675e6c8913a3d25802b59be6c26..9d3f4de6d25fc8598aa605b8d4a6718550ffdb9f 100644
--- a/scripts/cmake/DependenciesExternalProject.cmake
+++ b/scripts/cmake/DependenciesExternalProject.cmake
@@ -10,6 +10,12 @@ set(OGS_EXTERNAL_DEPENDENCIES_CACHE ""
     CACHE PATH "Directory containing source archives of external dependencies."
 )
 
+if(CCACHE_EXECUTABLE)
+    set(_defaultCMakeArgs "-DCMAKE_C_COMPILER_LAUNCHER=${CCACHE_EXECUTABLE}"
+                          "-DCMAKE_CXX_COMPILER_LAUNCHER=${CCACHE_EXECUTABLE}"
+    )
+endif()
+
 if(OGS_USE_MFRONT)
     option(OGS_BUILD_TFEL
            "Build TFEL locally. Needs to be set with a clean cache!" OFF
@@ -44,13 +50,13 @@ if(OGS_USE_MFRONT)
                        "-DBUILD_SHARED_LIBS=OFF"
                        "-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
                        "-Denable-testing=OFF"
+                       ${_defaultCMakeArgs}
         )
         message(
             STATUS
                 "ExternalProject_Add(): added package TFEL@rliv-${ogs.minimum_version.tfel-rliv}"
         )
         set(TFELHOME ${PROJECT_BINARY_DIR}/_ext/TFEL CACHE PATH "" FORCE)
-        set(_EXT_LIBS ${_EXT_LIBS} TFEL CACHE INTERNAL "")
     endif()
 endif()
 
@@ -174,8 +180,8 @@ elseif(NOT OGS_BUILD_ZLIB)
 endif()
 if(NOT ZLIB_FOUND)
     BuildExternalProject(
-        ZLIB ${_zlib_source}
-        CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
+        ZLIB ${_zlib_source} CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
+                                        ${_defaultCMakeArgs}
     )
     message(
         STATUS
@@ -235,12 +241,13 @@ elseif(NOT OGS_BUILD_HDF5)
     find_package(HDF5 ${ogs.minimum_version.hdf5})
 endif()
 if(NOT HDF5_FOUND)
-    BuildExternalProject(HDF5 ${_hdf5_source} CMAKE_ARGS ${_hdf5_options})
+    BuildExternalProject(
+        HDF5 ${_hdf5_source} CMAKE_ARGS ${_hdf5_options} ${_defaultCMakeArgs}
+    )
     message(
         STATUS
             "ExternalProject_Add(): added package HDF5@${ogs.tested_version.hdf5}"
     )
-    set(_EXT_LIBS ${_EXT_LIBS} HDF5 CACHE INTERNAL "")
     BuildExternalProject_find_package(HDF5)
 endif()
 
@@ -269,9 +276,8 @@ foreach(option_index ${ogs.libraries.vtk.options})
 endforeach()
 list(REMOVE_DUPLICATES VTK_OPTIONS)
 
-# Setting shared libs on PETSc, otherwise pvtu files only contain one
-# <Piece>-element (one subdomain).
-list(APPEND VTK_OPTIONS "-DBUILD_SHARED_LIBS=${OGS_USE_PETSC}"
+# Setting static libs for easier packaging.
+list(APPEND VTK_OPTIONS "-DBUILD_SHARED_LIBS=OFF"
      "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
 )
 message(STATUS "VTK_OPTIONS: ${VTK_OPTIONS}")
@@ -313,13 +319,13 @@ if(NOT VTK_FOUND)
         )
     endif()
     BuildExternalProject(
-        VTK ${_vtk_source} CMAKE_ARGS ${VTK_OPTIONS} ${_loguru_patch}
+        VTK ${_vtk_source} CMAKE_ARGS ${VTK_OPTIONS} ${_defaultCMakeArgs}
+                                      ${_loguru_patch}
     )
     message(
         STATUS
             "ExternalProject_Add(): added package VTK@${ogs.minimum_version.vtk}"
     )
-    set(_EXT_LIBS ${_EXT_LIBS} VTK CACHE INTERNAL "")
     BuildExternalProject_find_package(VTK)
 endif()
 
diff --git a/scripts/cmake/PythonSetup.cmake b/scripts/cmake/PythonSetup.cmake
index 8729dcbec891a5cd9944f8df892cd3d66ad10591..ee0aba93616642179b8a56c5298f42989cbce6cc 100644
--- a/scripts/cmake/PythonSetup.cmake
+++ b/scripts/cmake/PythonSetup.cmake
@@ -17,7 +17,15 @@ if(OGS_USE_PIP)
                 ${PROJECT_SOURCE_DIR}/scripts/cmake/PythonCreateVirtualEnv.cmake
             WORKING_DIRECTORY ${PROJECT_BINARY_DIR} COMMAND_ECHO STDOUT
                               ECHO_OUTPUT_VARIABLE ECHO_ERROR_VARIABLE
+            RESULT_VARIABLE _return_code
         )
+        if(NOT ${_return_code} EQUAL 0)
+            message(
+                FATAL_ERROR
+                    "Creation of Python virtual environment failed!\n"
+                    "To disable virtual environments set OGS_USE_PIP=OFF."
+            )
+        endif()
         unset(_OGS_PYTHON_PACKAGES_SHA1 CACHE)
     endif()
     set(_venv_bin_dir "bin")
diff --git a/scripts/cmake/packaging/PackagingDependencies.cmake b/scripts/cmake/packaging/PackagingDependencies.cmake
index 056e7599013ee3b8d1f797a1742d1260765a743c..ada0897b25619a0db01c1d6b2bb349d7529f0521 100644
--- a/scripts/cmake/packaging/PackagingDependencies.cmake
+++ b/scripts/cmake/packaging/PackagingDependencies.cmake
@@ -8,6 +8,7 @@ else()
     set(INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
 endif()
 list(JOIN CMAKE_INSTALL_RPATH ":" _rpath)
+install(CODE "set(CMAKE_BUILD_RPATH \"${CMAKE_BUILD_RPATH}\")")
 
 install(CODE "set(INSTALL_DIR \"${INSTALL_DIR}\")")
 install(CODE "set(CMAKE_INSTALL_LIBDIR \"${CMAKE_INSTALL_LIBDIR}\")")
@@ -27,7 +28,10 @@ install(
         $<$<TARGET_EXISTS:DataExplorer>:$<TARGET_FILE:DataExplorer>>
         $<$<TARGET_EXISTS:testrunner>:$<TARGET_FILE:testrunner>>
         $<$<TARGET_EXISTS:RemoveGhostData>:$<TARGET_FILE:RemoveGhostData>>
-    DIRECTORIES ${MKL_ROOT_DIR}/redist/intel64 ${MKL_ROOT_DIR}/../../tbb/latest/redist/intel64/vc_mt
+    DIRECTORIES
+        ${MKL_ROOT_DIR}/redist/intel64
+        ${MKL_ROOT_DIR}/../../tbb/latest/redist/intel64/vc_mt
+        ${CMAKE_BUILD_RPATH}
     RESOLVED_DEPENDENCIES_VAR _r_deps
     UNRESOLVED_DEPENDENCIES_VAR _u_deps
     PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-" ${OGS_INSTALL_DEPENDENCIES_PRE_EXCLUDES}
@@ -36,10 +40,10 @@ install(
   find_program(PATCHELF_TOOL patchelf)
   foreach(_lib ${_r_deps})
     string(REGEX MATCH "libpetsc.*" _petsc_lib ${_lib})
-    if(_petsc_lib AND EXISTS _ext/PETSc/lib/${_petsc_lib})
+    if(_petsc_lib AND EXISTS _ext/PETSc/lib/${_petsc_lib} AND NOT APPLE)
       if(PATCHELF_TOOL)
-        execute_process(COMMAND patchelf --set-rpath ${_rpath} _ext/PETSc/lib/${_petsc_lib} COMMAND_ERROR_IS_FATAL ANY)
         message(STATUS "Patching RPATH of ${_petsc_lib} -> ${_rpath}")
+        execute_process(COMMAND patchelf --set-rpath ${_rpath} _ext/PETSc/lib/${_petsc_lib} COMMAND_ERROR_IS_FATAL ANY)
       else()
           message(WARNING "patchelf tool not found: installed ogs binaries may not work (error: shared libraries not found)! "
             "Install the patchelf tool for proper runtime library search paths!")
diff --git a/web/content/docs/devguide/getting-started/build-configuration_for_MPI_PETSc/configure_for_mpi_and_petsc.md b/web/content/docs/devguide/getting-started/build-configuration_for_MPI_PETSc/configure_for_mpi_and_petsc.md
index 27c850415b9ffe2f4d6e8ece7113defe1f3dfb3c..8789a9c9af78079dd985b42404548e0dfbeef7e9 100644
--- a/web/content/docs/devguide/getting-started/build-configuration_for_MPI_PETSc/configure_for_mpi_and_petsc.md
+++ b/web/content/docs/devguide/getting-started/build-configuration_for_MPI_PETSc/configure_for_mpi_and_petsc.md
@@ -52,7 +52,7 @@ Please note that the PETSc package is preferred to build in release model regard
 
 PESTSc is recommended to use on Linux. On Windows, it only runs on
  UNIX emulator Cygwin. A detailed description about how to use PETSc on Windows
-  is available on this PETSc site: <https://petsc.org/main/install/windows/>.
+  is available on this PETSc site: <https://petsc.org/release/install/windows/>.
 
 One the frontends of EVE cluster of UFZ, your can load specified MPI, PETSc and
  other modules by command:
diff --git a/web/content/docs/userguide/parallel_computing/mpi/index.md b/web/content/docs/userguide/parallel_computing/mpi/index.md
index faa7aad1ff1b8325b4b53cd1351bdd5689f8315a..4d411f3bd0baea947840f722130198f924b654b4 100644
--- a/web/content/docs/userguide/parallel_computing/mpi/index.md
+++ b/web/content/docs/userguide/parallel_computing/mpi/index.md
@@ -93,7 +93,7 @@ The above example shows that once a prefix is given for PETSc linear solver
 above example, `-`, is replaced with `-T_` and `-H_`, respectively.
 
 A introduction and a list of PETSc KSP solvers and preconditioners can be found by
-[this link](https://petsc.org/main/docs/manual/ksp/).
+[this link](https://petsc.org/release/docs/manual/ksp/).
 
 ### 2. Launch MPI OGS