You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2025/07/15 11:47:06 UTC

(nifi-minifi-cpp) branch MINIFICPP-2584-apache updated (bcd8f7549 -> a2a26b18c)

This is an automated email from the ASF dual-hosted git repository.

martinzink pushed a change to branch MINIFICPP-2584-apache
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


 discard bcd8f7549 Use nickname 2
 discard ff60531a2 Use nickname
 discard a3a587bad MINIFICPP-2584 Linux Filesystem Hierarchy Standard support
     new a2a26b18c MINIFICPP-2584 Linux Filesystem Hierarchy Standard support

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (bcd8f7549)
            \
             N -- N -- N   refs/heads/MINIFICPP-2584-apache (a2a26b18c)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CMakeLists.txt                                     | 13 +++---
 cmake/Extensions.cmake                             |  2 +-
 conf/CMakeLists.txt                                | 20 ++++-----
 controller/CMakeLists.txt                          |  2 +-
 .../cluster/containers/MinifiContainer.py          | 18 ++++-----
 extensions/python/CMakeLists.txt                   |  2 +-
 libminifi/CMakeLists.txt                           |  2 +-
 libminifi/include/properties/LocationsImpl.h       | 18 ++++-----
 minifi_main/CMakeLists.txt                         |  2 +-
 packaging/check_rpm_contents.sh                    | 47 ++++++++++++++++++++++
 10 files changed, 86 insertions(+), 40 deletions(-)
 create mode 100644 packaging/check_rpm_contents.sh


(nifi-minifi-cpp) 01/01: MINIFICPP-2584 Linux Filesystem Hierarchy Standard support

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

martinzink pushed a commit to branch MINIFICPP-2584-apache
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit a2a26b18cc663b96131e3a8b325be853619ba0d6
Author: Martin Zink <ma...@apache.org>
AuthorDate: Wed Jun 25 15:00:21 2025 +0200

    MINIFICPP-2584 Linux Filesystem Hierarchy Standard support
---
 .github/workflows/verify-package.yml               |  21 +-
 CMakeLists.txt                                     | 116 ++++++---
 OPS.md                                             |  26 +--
 cmake/BundledOpenSSL.cmake                         |  23 +-
 cmake/DockerConfig.cmake                           |  15 +-
 cmake/Extensions.cmake                             |  10 +-
 cmake/MiNiFiOptions.cmake                          |   1 +
 cmake/VerifyPackageWithDocker.cmake                |   4 +
 conf/CMakeLists.txt                                |  89 +++++++
 conf/{config.yml => config.yml.in}                 |   0
 ...ifi-log.properties => minifi-log.properties.in} |   2 +-
 ...ifi-uid.properties => minifi-uid.properties.in} |   0
 conf/{minifi.properties => minifi.properties.in}   |  16 +-
 controller/CMakeLists.txt                          |  24 +-
 controller/MiNiFiController.cpp                    |  16 +-
 deploy.sh                                          |   2 +-
 docker/DockerBuild.sh                              |   3 +-
 docker/DockerVerify.sh                             |   2 +-
 .../installed.Dockerfile                           |   0
 .../installed.dockerignore                         |   0
 .../rpm.Dockerfile}                                |  16 +-
 docker/rockylinux/Dockerfile                       |   4 +-
 docker/test/integration/cluster/ContainerStore.py  |   3 +
 .../test/integration/cluster/DockerTestCluster.py  |   5 +-
 docker/test/integration/cluster/ImageStore.py      |  70 +++---
 .../cluster/MinifiControllerExecutor.py            |  23 +-
 .../containers/MinifiAsPodInKubernetesCluster.py   |   2 +-
 .../cluster/containers/MinifiContainer.py          |  51 +++-
 .../features/MiNiFi_integration_test_driver.py     |   3 +
 docker/test/integration/features/couchbase.feature |  16 +-
 docker/test/integration/features/environment.py    |   3 +
 .../test/integration/features/kubernetes.feature   |   1 +
 .../test/integration/features/replace_text.feature |   2 +-
 docker/test/integration/features/steps/steps.py    |   2 +-
 .../kubernetes/minifi-conf/minifi.properties       |  10 +
 .../integration/resources/minifi/minifi.properties |   6 -
 encrypt-config/CMakeLists.txt                      |  22 +-
 encrypt-config/FlowConfigEncryptor.cpp             |   3 +-
 .../tests/ExpressionLanguageTests.cpp              |   2 +-
 extensions/python/CMakeLists.txt                   |  22 +-
 extensions/python/PythonCreator.h                  |  22 +-
 extensions/python/tests/PythonManifestTests.cpp    |   2 +-
 .../rocksdb-repos/DatabaseContentRepository.cpp    |   7 +-
 extensions/rocksdb-repos/FlowFileRepository.cpp    |   5 +-
 .../controllers/RocksDbStateStorage.cpp            |   8 +-
 .../rocksdb-repos/tests/ContentSessionTests.cpp    |   2 +-
 .../tests/DBContentRepositoryTests.cpp             |  24 +-
 extensions/rocksdb-repos/tests/EncryptionTests.cpp |   2 +-
 extensions/rocksdb-repos/tests/RepoTests.cpp       |  28 +--
 extensions/rocksdb-repos/tests/SwapTests.cpp       |   2 +-
 extensions/sftp/tests/ListSFTPTests.cpp            |   4 +-
 .../tests/unit/TailFileTests.cpp                   |   2 +-
 fips/openssl.cnf                                   |   2 +-
 libminifi/CMakeLists.txt                           |  12 +-
 libminifi/include/core/logging/LoggerProperties.h  |   8 +-
 libminifi/include/properties/Configure.h           |  12 +-
 libminifi/include/properties/LocationsImpl.h       | 103 ++++++++
 libminifi/include/properties/Properties.h          |  15 --
 libminifi/src/Configure.cpp                        |   9 +
 libminifi/src/core/extension/ExtensionManager.cpp  |  21 +-
 libminifi/src/core/logging/LoggerConfiguration.cpp |   2 +-
 .../src/core/repository/FileSystemRepository.cpp   |   2 +-
 libminifi/src/properties/Properties.cpp            |   8 +-
 libminifi/src/utils/file/AssetManager.cpp          |  12 +-
 libminifi/test/integration/AlertTests.cpp          |   4 +-
 libminifi/test/integration/C2DebugBundleTest.cpp   |   4 +-
 .../test/integration/C2DescribeManifestTest.cpp    |   2 +-
 .../test/integration/C2PropertiesUpdateTests.cpp   |   9 +-
 libminifi/test/libtest/unit/TestBase.cpp           |   6 +-
 .../test/libtest/unit/TestControllerWithFlow.cpp   |   1 -
 .../test/persistence-tests/PersistenceTests.cpp    |   4 +-
 libminifi/test/unit/DecryptorTests.cpp             |   4 +-
 libminifi/test/unit/LogMetricsPublisherTests.cpp   |   2 +-
 libminifi/test/unit/LoggerConfigurationTests.cpp   |   2 +-
 libminifi/test/unit/LoggerTests.cpp                |  20 +-
 libminifi/test/unit/ProcessSessionTests.cpp        |   2 +-
 .../performance/VolatileRepositoryPerfTests.cpp    |   2 +-
 .../include/minifi-cpp/core/ProcessContext.h       |   2 -
 .../include/minifi-cpp/properties/Configure.h      |   6 +-
 .../include/minifi-cpp/properties/Locations.h      |  37 +++
 .../include/minifi-cpp/properties/Properties.h     |   2 -
 minifi_main/CMakeLists.txt                         |  18 +-
 minifi_main/Fips.cpp                               |  51 ++--
 minifi_main/Fips.h                                 |   3 +-
 minifi_main/MainHelper.cpp                         |  18 +-
 minifi_main/MainHelper.h                           |   1 +
 minifi_main/MiNiFiMain.cpp                         |  73 +++---
 packaging/check_rpm_contents.sh                    |  47 ++++
 packaging/pre_install.sh                           |  11 +
 .../google-cloud-cpp/remove_installation.patch     | 258 +++++++++++++++++++++
 .../0003-remove_FindLZ4_installation.patch         |  22 ++
 utils/include/core/ProcessContext.h                |  15 +-
 utils/include/utils/expected.h                     |   4 +-
 utils/src/utils/crypto/EncryptionManager.cpp       |   6 +-
 94 files changed, 1190 insertions(+), 396 deletions(-)

diff --git a/.github/workflows/verify-package.yml b/.github/workflows/verify-package.yml
index 42a178f3c..73263f49a 100644
--- a/.github/workflows/verify-package.yml
+++ b/.github/workflows/verify-package.yml
@@ -24,8 +24,8 @@ jobs:
       fail-fast: false
       matrix:
         platform: [
-          { arch: "x86_64", artifact: "minifi-x86_64-tar" },
-          { arch: "aarch64", artifact: "minifi-aarch64-tar" }
+          { arch: "x86_64", tar-artifact: "minifi-x86_64-tar", rpm-artifact: "minifi-x86_64-rpm" },
+          { arch: "aarch64", tar-artifact: "minifi-aarch64-tar", rpm-artifact: "minifi-aarch64-rpm" }
         ]
 
     steps:
@@ -43,14 +43,18 @@ jobs:
 
       - uses: actions/upload-artifact@v4
         with:
-          name: ${{ matrix.platform.artifact }}
+          name: ${{ matrix.platform.tar-artifact }}
           path: build/nifi-minifi-cpp-*-bin-rockylinux.tar.gz
-          if-no-files-found: error
+
+      - uses: actions/upload-artifact@v4
+        with:
+          name: ${{ matrix.platform.rpm-artifact }}
+          path: build/nifi-minifi-cpp-*.rpm
 
   docker-tests:
     name: "${{ matrix.platform.name }} (${{ matrix.arch }})${{ inputs.enable_fips && ' (FIPS Mode)' || '' }}"
     runs-on: ${{ matrix.arch == 'x86_64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
-    timeout-minutes: 180
+    timeout-minutes: 240
     needs: build-packages
     strategy:
       fail-fast: false
@@ -59,6 +63,8 @@ jobs:
         platform: [
           { name: "Rocky Linux 8", id: "rocky8", build_cmd: "make rocky8_from_rocky_package", verify_cmd: "make docker-verify-rocky8" },
           { name: "Rocky Linux 9", id: "rocky9", build_cmd: "make rocky9_from_rocky_package", verify_cmd: "make docker-verify-rocky9" },
+          { name: "Rocky Linux 8 from RPM", id: "rocky8-rpm", build_cmd: "make rocky8_from_rpm_package", verify_cmd: "make docker-verify-rocky8-rpm" },
+          { name: "Rocky Linux 9 from RPM", id: "rocky9-rpm", build_cmd: "make rocky9_from_rpm_package", verify_cmd: "make docker-verify-rocky9-rpm" },
           { name: "Ubuntu 22.04", id: "ubuntu_jammy", build_cmd: "make jammy_from_rocky_package", verify_cmd: "make docker-verify-jammy" },
           { name: "Ubuntu 24.04", id: "ubuntu_noble", build_cmd: "make noble_from_rocky_package", verify_cmd: "make docker-verify-noble" },
           { name: "Debian 11", id: "debian_bullseye", build_cmd: "make bullseye_from_rocky_package", verify_cmd: "make docker-verify-bullseye" },
@@ -74,6 +80,11 @@ jobs:
           name: minifi-${{ matrix.arch }}-tar
           path: build
 
+      - uses: actions/download-artifact@v4
+        with:
+          name: minifi-${{ matrix.arch }}-rpm
+          path: build
+
       - id: install_deps
         run: |
           sudo apt update
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f9f94363e..a74d11b1b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,7 @@ include(CMakeDependentOption)
 include(CheckIncludeFile)
 include(FeatureSummary)
 include(ExternalProject)
+include(GNUInstallDirs)
 
 # Provide custom modules for the project
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
@@ -429,7 +430,6 @@ if(WIN32)
     set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/msi/minifi-logo-png-banner.png")
     set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/msi/bgr.png")
 
-    file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/conf/")
     file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/fips/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/fips/")
     file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
     file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/NOTICE" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
@@ -587,46 +587,68 @@ set(CPACK_SOURCE_IGNORE_FILES
     "\\\\.ropeproject"
 )
 
-# Generate binary assembly. Exclude conf for windows since we'll be doing the work in the WiX template
+add_subdirectory(conf)
 if (NOT WIN32)
-    install(FILES conf/minifi.properties conf/minifi-log.properties conf/minifi-uid.properties conf/config.yml
-        DESTINATION conf
-        COMPONENT bin)
-
-    install(FILES fips/openssl.cnf fips/README.md
-        DESTINATION fips
-        COMPONENT bin)
-
-    install(DIRECTORY extensions/python/pythonprocessors/
-        DESTINATION minifi-python
-        COMPONENT bin)
-
-    install(DIRECTORY extensions/python/pythonprocessor-examples/
-        DESTINATION minifi-python-examples
-        COMPONENT bin)
-
-    install(PROGRAMS bin/minifi.sh
-            DESTINATION bin
-            COMPONENT bin)
-
-    if (APPLE)
-        install(FILES bin/minifi.plist
-            DESTINATION bin
-            COMPONENT bin)
-    else()
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        message(STATUS "Configuring for FHS/RPM package installation.")
+        install(FILES fips/openssl.cnf fips/README.md
+                DESTINATION /${CMAKE_INSTALL_SYSCONFDIR}/${PROJECT_NAME}/fips
+                COMPONENT bin)
+        install(PROGRAMS bin/minifi.sh DESTINATION ${CMAKE_INSTALL_BINDIR})
         install(FILES bin/minifi.service
+                DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/system
+                COMPONENT bin
+        )
+        install(DIRECTORY DESTINATION /${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME} COMPONENT bin)
+        install(DIRECTORY DESTINATION /${CMAKE_INSTALL_LOCALSTATEDIR}/log/${PROJECT_NAME} COMPONENT bin)
+        install(DIRECTORY extensions/python/pythonprocessors/
+                DESTINATION /${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/minifi-python
+                COMPONENT bin)
+        install(DIRECTORY extensions/python/pythonprocessor-examples/
+                DESTINATION ${CMAKE_INSTALL_DOCDIR}/pythonprocessor-examples
+                COMPONENT bin)
+    elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+        message(STATUS "Configuring for self-contained TGZ package installation.")
+        install(PROGRAMS bin/minifi.sh DESTINATION bin)
+        install(FILES fips/openssl.cnf fips/README.md
+                DESTINATION fips
+                COMPONENT bin)
+        install(DIRECTORY extensions/python/pythonprocessors/
+                DESTINATION minifi-python
+                COMPONENT bin)
+        install(DIRECTORY extensions/python/pythonprocessor-examples/
+                DESTINATION minifi-python-examples
+                COMPONENT bin)
+        install(PROGRAMS bin/minifi.sh
                 DESTINATION bin
                 COMPONENT bin)
+        if (APPLE)
+            install(FILES bin/minifi.plist
+                    DESTINATION bin
+                    COMPONENT bin)
+        else()
+            install(FILES bin/minifi.service
+                    DESTINATION bin
+                    COMPONENT bin)
+        endif()
+    else()
+        message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
     endif()
 endif()
 
-install(FILES LICENSE NOTICE
-    DESTINATION .
-    COMPONENT bin)
 file(GLOB markdown_docs "*.md")
-install(FILES ${markdown_docs}
-    DESTINATION .
-    COMPONENT bin)
+if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+    install(FILES LICENSE NOTICE ${markdown_docs}
+            DESTINATION ${CMAKE_INSTALL_DOCDIR}
+            COMPONENT bin)
+elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+    install(FILES LICENSE NOTICE ${markdown_docs}
+            DESTINATION .
+            COMPONENT bin)
+else()
+    message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+endif()
+
 
 include(CPackComponent)
 
@@ -634,10 +656,32 @@ if (WIN32)
     set(CPACK_GENERATOR "WIX")
     set(CPACK_WIX_UPGRADE_GUID "FE29F801-3486-4E9E-AFF9-838C1A5C8D59")
     set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/msi/minifi-logo-ico.ico")
-else()
+elseif(APPLE)
     set(CPACK_GENERATOR "TGZ")
+else()
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        set(CPACK_GENERATOR "RPM")
+        set(CPACK_BINARY_RPM, "ON")
+        set(CPACK_RPM_PACKAGE_NAME "apache-nifi-minifi-cpp")
+        set(CPACK_RPM_PACKAGE_AUTOREQ OFF)
+        set(CPACK_RPM_PACKAGE_REQUIRES "")
+        set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 0)
+        set(CPACK_RPM_SPEC_MORE_DEFINE "%define _build_id_links none")
+        set(CPACK_RPM_COMPONENT_INSTALL ON)
+        set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}")
+        set(CPACK_RPM_DEFAULT_USER "minificpp")
+        set(CPACK_RPM_DEFAULT_GROUP "minificpp")
+        set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/packaging/pre_install.sh")
+        list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/var")
+        list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/var/lib")
+        list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/var/log")
+    elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+        set(CPACK_GENERATOR "TGZ")
+        set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 1)
+    else()
+        message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+    endif()
 endif()
-set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 1)
 set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache NiFi MiNiFi C++ version ${VERSION}")
 set(CPACK_PACKAGE_VENDOR "Apache NiFi")
 # set version information
@@ -649,8 +693,6 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" "${CMAKE_CURRENT_BINARY_DIR
 set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt")
 if(NOT WIN32)
     set(CPACK_PACKAGE_FILE_NAME "${ASSEMBLY_BASE_NAME}")
-    set(CPACK_GENERATOR "TGZ")
-    set(CPACK_BINARY_TGZ, "ON")
 else()
     set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}")
 endif()
diff --git a/OPS.md b/OPS.md
index 07ccc3bb0..3bc2431eb 100644
--- a/OPS.md
+++ b/OPS.md
@@ -37,10 +37,10 @@ it is meant to provide testing and minimal operational capabilities by example.
 The MiNiFi controller is an executable in the bin directory that can be used to control the MiNiFi C++ agent while it runs -- utilizing the [Command and Control Protocol](https://cwiki.apache.org/confluence/display/MINIFI/C2+Design). Currently the controller will let you stop subcomponents within a running instance, clear queues, get the status of queues, and update the flow for a warm re-deploy. It also provides an option to retrieve the agent manifest json.
 
 This functionality has to enabled in the minifi.properties file with the controller.socket.enable property.
-The minificontroller can track a single MiNiFi C++ agent through the use of three options. Port is required.
+The minifi-controller can track a single MiNiFi C++ agent through the use of three options. Port is required.
 The hostname is not and will default to localhost. Additionally, controller.socket.local.any.interface allows
 you to bind to any address when using localhost. Otherwise, we will bind only to the loopback adapter so only
-minificontroller on the local host can control the agent:
+minifi-controller on the local host can control the agent:
 
     $ controller.socket.enable=true
     $ controller.socket.host=localhost
@@ -50,7 +50,7 @@ minificontroller on the local host can control the agent:
 These are defined by default to the above values. If the port option is left undefined, the MiNiFi controller
 will be disabled in your deployment.
 
-The executable is stored in the bin directory and is titled minificontroller. Available commands are listed below.
+The executable is stored in the bin directory and is titled minifi-controller. Available commands are listed below.
 
 ### SSL
 
@@ -71,41 +71,41 @@ Otherwise if you prefer to retrieve the SSL configuration properties from the mi
 ### Commands
 
 #### Specifying connecting information
-    ./minificontroller --host "host name" --port "port"
+    ./minifi-controller --host "host name" --port "port"
 
 By default these options use those defined in minifi.properties and are not required
 
 #### Start Command
-    ./minificontroller --start "component name"
+    ./minifi-controller --start "component name"
 
 #### Stop command
-    ./minificontroller --stop "component name"
+    ./minifi-controller --stop "component name"
 
 #### List connections command
-    ./minificontroller --list connections
+    ./minifi-controller --list connections
 
 #### List components command
-    ./minificontroller --list components
+    ./minifi-controller --list components
 
 #### Clear connection command
-    ./minificontroller --clear "connection name"
+    ./minifi-controller --clear "connection name"
 
 #### GetSize command
-    ./minificontroller --getsize "connection name"
+    ./minifi-controller --getsize "connection name"
 
 Returns the size of the connection. The current size along with the max will be reported
 
 #### Update flow
-    ./minificontroller --updateflow "config yml"
+    ./minifi-controller --updateflow "config yml"
 
 Updates the flow file reference and performs a warm re-deploy.
 
 #### Get full connection command
-    ./minificontroller --getfull
+    ./minifi-controller --getfull
 
 Provides a list of full connections, if any.
 
 #### Get manifest command
-    ./minificontroller --manifest
+    ./minifi-controller --manifest
 
 Writes the agent manifest json to standard output
diff --git a/cmake/BundledOpenSSL.cmake b/cmake/BundledOpenSSL.cmake
index d2e882985..ea7e71c6b 100644
--- a/cmake/BundledOpenSSL.cmake
+++ b/cmake/BundledOpenSSL.cmake
@@ -188,9 +188,26 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
         LIST(APPEND OPENSSL_FIPS_FILE_LIST "${OPENSSL_FIPS_BIN_DIR}/${BYPRODUCT}")
     ENDFOREACH(BYPRODUCT)
 
-    install(FILES ${OPENSSL_FIPS_FILE_LIST} DESTINATION fips COMPONENT bin)
-    install(FILES "${OPENSSL_BIN_DIR}/bin/openssl${EXECUTABLE_SUFFIX}" DESTINATION fips COMPONENT bin
-            PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE)
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        install(FILES ${OPENSSL_FIPS_FILE_LIST}
+                DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/fips
+                COMPONENT bin)
+
+        install(FILES "${OPENSSL_BIN_DIR}/bin/openssl${EXECUTABLE_SUFFIX}"
+                DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/fips
+                COMPONENT bin
+                PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE)
+
+    elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+        install(FILES ${OPENSSL_FIPS_FILE_LIST}
+                DESTINATION fips
+                COMPONENT bin)
+
+        install(FILES "${OPENSSL_BIN_DIR}/bin/openssl${EXECUTABLE_SUFFIX}"
+                DESTINATION fips
+                COMPONENT bin
+                PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE)
+    endif()
 
     set(OPENSSL_FIPS_EXTRA_FLAGS
             no-tests            # Disable tests
diff --git a/cmake/DockerConfig.cmake b/cmake/DockerConfig.cmake
index d1d88d65e..bb3697963 100644
--- a/cmake/DockerConfig.cmake
+++ b/cmake/DockerConfig.cmake
@@ -168,7 +168,20 @@ function(CREATE_DOCKER_TARGET_FROM_ROCKY_PACKAGE BASE_IMAGE TAG_PREFIX INSTALL_P
             --build-arg ARCHIVE_LOCATION=nifi-minifi-cpp-${MINIFI_VERSION_STR}-bin-rockylinux.tar.gz
             --build-arg INSTALL_PACKAGE_CMD=${INSTALL_PACKAGE_CMD}
             -t apacheminificpp:${TAG_PREFIX}-${MINIFI_VERSION_STR}
-            -f ${CMAKE_SOURCE_DIR}/docker/python-verify/installed.Dockerfile
+            -f ${CMAKE_SOURCE_DIR}/docker/installed/installed.Dockerfile
+            ${CMAKE_BINARY_DIR})
+endfunction()
+
+function(CREATE_DOCKER_TARGET_FROM_RPM_PACKAGE BASE_IMAGE TAG_PREFIX INSTALL_PACKAGE_CMD)
+    add_custom_target(
+            ${TAG_PREFIX}_from_rpm_package
+            COMMAND DOCKER_BUILDKIT=1 docker build
+            --build-arg MINIFI_VERSION=${MINIFI_VERSION_STR}
+            --build-arg BASE_IMAGE=${BASE_IMAGE}
+            --build-arg ARCHIVE_LOCATION=nifi-minifi-cpp-${MINIFI_VERSION_STR}-bin-rockylinux.rpm
+            --build-arg INSTALL_PACKAGE_CMD=${INSTALL_PACKAGE_CMD}
+            -t apacheminificpp:${TAG_PREFIX}-rpm-${MINIFI_VERSION_STR}
+            -f ${CMAKE_SOURCE_DIR}/docker/installed/rpm.Dockerfile
             ${CMAKE_BINARY_DIR})
 endfunction()
 
diff --git a/cmake/Extensions.cmake b/cmake/Extensions.cmake
index c497ec525..ecf3bc6aa 100644
--- a/cmake/Extensions.cmake
+++ b/cmake/Extensions.cmake
@@ -78,7 +78,15 @@ macro(register_extension extension-name extension-display-name extension-guard d
             else()
                 set_target_properties(${extension-name} PROPERTIES INSTALL_RPATH "$ORIGIN")
             endif()
-            install(TARGETS ${extension-name} LIBRARY DESTINATION extensions COMPONENT ${component-name})
+            if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+                install(TARGETS ${extension-name}
+                        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/extensions/
+                        COMPONENT ${component-name})
+            elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+                install(TARGETS ${extension-name} LIBRARY DESTINATION extensions COMPONENT ${component-name})
+            else()
+                message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+            endif()
         endif()
     endif()
 
diff --git a/cmake/MiNiFiOptions.cmake b/cmake/MiNiFiOptions.cmake
index 8fb152b33..7de185e54 100644
--- a/cmake/MiNiFiOptions.cmake
+++ b/cmake/MiNiFiOptions.cmake
@@ -138,6 +138,7 @@ set_property(CACHE STRICT_GSL_CHECKS PROPERTY STRINGS ${STRICT_GSL_CHECKS_Values
 # BUILD: Fetch and build from source using CMake FetchContent or ExternalProject
 # SYSTEM: Use find_package to use the system version
 # CONAN: Use Conan packages
+add_minifi_multi_option(MINIFI_PACKAGING_TYPE "Selects the packaging format for the final artifact." "TGZ;RPM" "TGZ")
 add_minifi_multi_option(MINIFI_LIBCURL_SOURCE "Retrieves LibCURL from provided source" "BUILD;SYSTEM;CONAN" "BUILD")
 add_minifi_multi_option(MINIFI_OPENSSL_SOURCE "Retrieves OpenSSL from provided source" "BUILD;SYSTEM;CONAN" "BUILD")
 add_minifi_multi_option(MINIFI_ZLIB_SOURCE "Retrieves ZLib from provided source" "BUILD;SYSTEM;CONAN" "BUILD")
diff --git a/cmake/VerifyPackageWithDocker.cmake b/cmake/VerifyPackageWithDocker.cmake
index 32e0abb79..97ff6ad44 100644
--- a/cmake/VerifyPackageWithDocker.cmake
+++ b/cmake/VerifyPackageWithDocker.cmake
@@ -45,6 +45,8 @@ CREATE_DOCKER_TARGET_FROM_ROCKY_PACKAGE(ubuntu:jammy jammy "apt update \\&\\& ap
 CREATE_DOCKER_TARGET_FROM_ROCKY_PACKAGE(ubuntu:noble noble "apt update \\&\\& apt install -y wget python3-dev python3-venv python3-pip")
 CREATE_DOCKER_TARGET_FROM_ROCKY_PACKAGE(debian:bookworm bookworm "apt update \\&\\& apt install -y wget python3-dev python3-venv python3-pip")
 CREATE_DOCKER_TARGET_FROM_ROCKY_PACKAGE(debian:bullseye bullseye "apt update \\&\\& apt install -y wget python3-dev python3-venv python3-pip")
+CREATE_DOCKER_TARGET_FROM_RPM_PACKAGE(rockylinux:8 rocky8 "dnf install -y wget python3.12-devel python3.12-pip gcc gcc-c++")
+CREATE_DOCKER_TARGET_FROM_RPM_PACKAGE(rockylinux:9 rocky9 "dnf install -y wget python3-devel python3-pip gcc gcc-c++")
 
 if (EXISTS ${CMAKE_SOURCE_DIR}/docker/test/integration/features)
     ADD_PACKAGE_VERIFY(rocky8)
@@ -53,4 +55,6 @@ if (EXISTS ${CMAKE_SOURCE_DIR}/docker/test/integration/features)
     ADD_PACKAGE_VERIFY(noble)
     ADD_PACKAGE_VERIFY(bookworm)
     ADD_PACKAGE_VERIFY(bullseye)
+    ADD_PACKAGE_VERIFY(rocky8-rpm)
+    ADD_PACKAGE_VERIFY(rocky9-rpm)
 endif()
diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt
new file mode 100644
index 000000000..39012d6fe
--- /dev/null
+++ b/conf/CMakeLists.txt
@@ -0,0 +1,89 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+#
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Exclude conf for windows since we'll be doing the work in the WiX template
+
+if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+    set(MINIFI_PATH_FLOW_CONFIG "/${CMAKE_INSTALL_SYSCONFDIR}/${PROJECT_NAME}/config.yml")
+    set(MINIFI_PATH_EXTENSIONS "/usr/${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/extensions/*")
+    set(MINIFI_PATH_PROVENANCE_REPO "/${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/provenance_repository")
+    set(MINIFI_PATH_FLOWFILE_REPO "/${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/flowfile_repository")
+    set(MINIFI_PATH_CONTENT_REPO "/${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/content_repository")
+    set(MINIFI_PATH_ASSET_DIR "/${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/asset")
+    set(MINIFI_PATH_PYTHON_PROCESSORS "/${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/minifi-python")
+    set(MINIFI_PATH_PYTHON_VENV "/${CMAKE_INSTALL_LOCALSTATEDIR}/lib/${PROJECT_NAME}/minifi-python-env")
+    set(MINIFI_PATH_APPENDER_ROLLING_DIR "/${CMAKE_INSTALL_LOCALSTATEDIR}/log/${PROJECT_NAME}/")
+elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+    set(MINIFI_PATH_FLOW_CONFIG "./conf/config.yml")
+    set(MINIFI_PATH_EXTENSIONS "../extensions/*")
+    set(MINIFI_PATH_PROVENANCE_REPO "\${MINIFI_HOME}/provenance_repository")
+    set(MINIFI_PATH_FLOWFILE_REPO "\${MINIFI_HOME}/flowfile_repository")
+    set(MINIFI_PATH_CONTENT_REPO "\${MINIFI_HOME}/content_repository")
+    set(MINIFI_PATH_ASSET_DIR "\${MINIFI_HOME}/asset")
+    set(MINIFI_PATH_PYTHON_PROCESSORS "\${MINIFI_HOME}/minifi-python/")
+    set(MINIFI_PATH_PYTHON_VENV "\${MINIFI_HOME}/minifi-python-env")
+    set(MINIFI_PATH_APPENDER_ROLLING_DIR "\${MINIFI_HOME}/logs")
+else()
+    message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+endif()
+
+configure_file(
+        config.yml.in
+        ${CMAKE_BINARY_DIR}/conf/config.yml
+        @ONLY
+)
+
+configure_file(
+        minifi.properties.in
+        ${CMAKE_BINARY_DIR}/conf/minifi.properties
+        @ONLY
+)
+
+configure_file(
+        minifi-log.properties.in
+        ${CMAKE_BINARY_DIR}/conf/minifi-log.properties
+        @ONLY
+)
+
+configure_file(
+        minifi-uid.properties.in
+        ${CMAKE_BINARY_DIR}/conf/minifi-uid.properties
+        @ONLY
+)
+
+
+if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+    install(FILES
+            ${CMAKE_BINARY_DIR}/conf/minifi.properties
+            ${CMAKE_BINARY_DIR}/conf/minifi-log.properties
+            ${CMAKE_BINARY_DIR}/conf/minifi-uid.properties
+            ${CMAKE_BINARY_DIR}/conf/config.yml
+            DESTINATION /${CMAKE_INSTALL_SYSCONFDIR}/${PROJECT_NAME}
+            COMPONENT bin)
+elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+    install(FILES
+            ${CMAKE_BINARY_DIR}/conf/minifi.properties
+            ${CMAKE_BINARY_DIR}/conf/minifi-log.properties
+            ${CMAKE_BINARY_DIR}/conf/minifi-uid.properties
+            ${CMAKE_BINARY_DIR}/conf/config.yml
+            DESTINATION conf
+            COMPONENT bin)
+else()
+    message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+endif()
\ No newline at end of file
diff --git a/conf/config.yml b/conf/config.yml.in
similarity index 100%
rename from conf/config.yml
rename to conf/config.yml.in
diff --git a/conf/minifi-log.properties b/conf/minifi-log.properties.in
similarity index 97%
rename from conf/minifi-log.properties
rename to conf/minifi-log.properties.in
index 04b32e5ed..b291b6463 100644
--- a/conf/minifi-log.properties
+++ b/conf/minifi-log.properties.in
@@ -26,7 +26,7 @@ spdlog.pattern=[%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
 #spdlog.pattern=[%D %H:%M:%S.%e] [%L] %v
 
 appender.rolling=rollingappender
-#appender.rolling.directory=${MINIFI_HOME}/logs
+#appender.rolling.directory=@MINIFI_PATH_APPENDER_ROLLING_DIR@
 appender.rolling.file_name=minifi-app.log
 appender.rolling.max_files=1
 appender.rolling.max_file_size=20 MB
diff --git a/conf/minifi-uid.properties b/conf/minifi-uid.properties.in
similarity index 100%
rename from conf/minifi-uid.properties
rename to conf/minifi-uid.properties.in
diff --git a/conf/minifi.properties b/conf/minifi.properties.in
similarity index 93%
rename from conf/minifi.properties
rename to conf/minifi.properties.in
index ef5704fcd..f1f94c40a 100644
--- a/conf/minifi.properties
+++ b/conf/minifi.properties.in
@@ -14,23 +14,23 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./conf/config.yml
+nifi.flow.configuration.file=@MINIFI_PATH_FLOW_CONFIG@
 nifi.administrative.yield.duration=30 sec
 # If a component has no work to do (is "bored"), how long should we wait before checking again for work?
 nifi.bored.yield.duration=100 millis
 #nifi.flow.engine.threads=5
 
 # Comma separated path for the extension libraries. Relative path is relative to the minifi executable.
-nifi.extension.path=../extensions/*
+nifi.extension.path=@MINIFI_PATH_EXTENSIONS@
 
 # Provenance Repository #
-nifi.provenance.repository.directory.default=${MINIFI_HOME}/provenance_repository
+nifi.provenance.repository.directory.default=@MINIFI_PATH_PROVENANCE_REPO@
 nifi.provenance.repository.max.storage.time=1 MIN
 nifi.provenance.repository.max.storage.size=1 MB
-nifi.flowfile.repository.directory.default=${MINIFI_HOME}/flowfile_repository
+nifi.flowfile.repository.directory.default=@MINIFI_PATH_FLOWFILE_REPO@
 # nifi.flowfile.repository.rocksdb.compression=auto
 # nifi.flowfile.repository.check.health=true
-nifi.database.content.repository.directory.default=${MINIFI_HOME}/content_repository
+nifi.database.content.repository.directory.default=@MINIFI_PATH_CONTENT_REPO@
 nifi.provenance.repository.class.name=NoOpRepository
 nifi.content.repository.class.name=DatabaseContentRepository
 # nifi.content.repository.rocksdb.compression=auto
@@ -132,7 +132,7 @@ nifi.c2.full.heartbeat=false
 #controller.ssl.context.service=SSLContextService
 
 ## specify the destination of c2 directed assets
-#nifi.asset.directory=${MINIFI_HOME}/asset
+#nifi.asset.directory=@MINIFI_PATH_ASSET_DIR@
 
 ## You probably don't need to touch this, but you can if you want to
 # nifi.default.internal.buffer.size=4096
@@ -144,8 +144,8 @@ nifi.c2.full.heartbeat=false
 # nifi.metrics.publisher.metrics=QueueMetrics,RepositoryMetrics,GetFileMetrics,DeviceInfoNode,FlowInformation
 
 # Python processor properties
-nifi.python.processor.dir=${MINIFI_HOME}/minifi-python/
-nifi.python.virtualenv.directory=${MINIFI_HOME}/minifi-python-env
+nifi.python.processor.dir=@MINIFI_PATH_PYTHON_PROCESSORS@
+nifi.python.virtualenv.directory=@MINIFI_PATH_PYTHON_VENV@
 nifi.python.install.packages.automatically=true
 # nifi.python.env.setup.binary=python3
 
diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt
index bea1c7eea..b06cf4ef8 100644
--- a/controller/CMakeLists.txt
+++ b/controller/CMakeLists.txt
@@ -33,29 +33,33 @@ set_cpp_version()
 
 set(MINIFI_CONTROLLER_SOURCES MiNiFiController.cpp Controller.cpp ../minifi_main/MainHelper.cpp)
 if (WIN32)
-    set(EXECUTABLE_FILE_NAME "minificontroller.exe")
+    set(EXECUTABLE_FILE_NAME "minifi-controller.exe")
     set(EXECUTABLE_FILE_DESCRIPTION "${PRODUCT_NAME} controller")
     configure_file(${CMAKE_SOURCE_DIR}/versioninfo.rc.in ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc @ONLY)
     list(APPEND MINIFI_CONTROLLER_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc")
 endif()
 
-add_minifi_executable(minificontroller ${MINIFI_CONTROLLER_SOURCES})
+add_minifi_executable(minifi-controller ${MINIFI_CONTROLLER_SOURCES})
 include(ArgParse)
-target_link_libraries(minificontroller ${LIBMINIFI} argparse Threads::Threads)
+target_link_libraries(minifi-controller ${LIBMINIFI} argparse Threads::Threads)
 
-set_target_properties(minificontroller PROPERTIES
-    OUTPUT_NAME minificontroller
+set_target_properties(minifi-controller PROPERTIES
+    OUTPUT_NAME minifi-controller
     RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 
 if (NOT WIN32)
     if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT APPLE)
-        target_link_options(minificontroller PRIVATE "-Wl,--disable-new-dtags")
+        target_link_options(minifi-controller PRIVATE "-Wl,--disable-new-dtags")
     endif()
-    if (APPLE)
-        set_target_properties(minificontroller PROPERTIES INSTALL_RPATH "@loader_path")
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        set_target_properties(minifi-controller PROPERTIES INSTALL_RPATH "/usr/${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}")
     else()
-        set_target_properties(minificontroller PROPERTIES INSTALL_RPATH "$ORIGIN")
+        if (APPLE)
+            set_target_properties(minifi-controller PROPERTIES INSTALL_RPATH "@loader_path")
+        else()
+            set_target_properties(minifi-controller PROPERTIES INSTALL_RPATH "$ORIGIN")
+        endif()
     endif()
 endif()
 
-install(TARGETS minificontroller RUNTIME DESTINATION bin COMPONENT bin)
+install(TARGETS minifi-controller RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin)
diff --git a/controller/MiNiFiController.cpp b/controller/MiNiFiController.cpp
index 33be0ed71..643ec6951 100644
--- a/controller/MiNiFiController.cpp
+++ b/controller/MiNiFiController.cpp
@@ -90,19 +90,19 @@ std::shared_ptr<minifi::controllers::SSLContextService> getSSLContextService(con
 int main(int argc, char **argv) {
   const auto logger = minifi::core::logging::LoggerConfiguration::getConfiguration().getLogger("controller");
 
-  const auto minifi_home = determineMinifiHome(logger);
-  if (minifi_home.empty()) {
-    // determineMinifiHome already logged everything we need
+  const auto locations = determineLocations(logger);
+  if (!locations) {
+    // determineLocations already logged everything we need
     return -1;
   }
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(minifi_home);
-  configuration->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);
+  configuration->setLocations(locations);
+  configuration->loadConfigureFile(locations->getPropertiesPath());
+
+  const auto log_properties = std::make_shared<minifi::core::logging::LoggerProperties>(locations->getLogsDirs());
+  log_properties->loadConfigureFile(locations->getLogPropertiesPath(), "nifi.log.");
 
-  const auto log_properties = std::make_shared<minifi::core::logging::LoggerProperties>();
-  log_properties->setHome(minifi_home);
-  log_properties->loadConfigureFile(DEFAULT_LOG_PROPERTIES_FILE);
   minifi::core::logging::LoggerConfiguration::getConfiguration().initialize(log_properties);
 
   minifi::utils::net::SocketData socket_data;
diff --git a/deploy.sh b/deploy.sh
index 2eeadb5ba..f1df2ffc2 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -24,5 +24,5 @@ echo "${build_identifier}" > build_identifier
 ./bootstrap.sh -d -p --build_identifier="${build_identifier}"
 
 pushd build || exit 1
-./controller/minificontroller --manifest >> build_output
+./controller/minifi-controller --manifest >> build_output
 popd || exit 2
diff --git a/docker/DockerBuild.sh b/docker/DockerBuild.sh
index 12a9a2982..ad03bd000 100755
--- a/docker/DockerBuild.sh
+++ b/docker/DockerBuild.sh
@@ -230,6 +230,7 @@ fi
 
 if [ -n "${DUMP_LOCATION}" ]; then
   container_id=$(docker create "${TAG}")
-  docker cp "${container_id}:/opt/minifi/build/nifi-minifi-cpp-${MINIFI_VERSION}.tar.gz" "${DUMP_LOCATION}/nifi-minifi-cpp-${MINIFI_VERSION}-${TARGZ_TAG}.tar.gz"
+  docker cp "${container_id}:/opt/minifi/build/nifi-minifi-cpp-${MINIFI_VERSION}.tar.gz" "${DUMP_LOCATION}/nifi-minifi-cpp-${MINIFI_VERSION}-${TARGZ_TAG}.tar.gz" || true
+  docker cp "${container_id}:/opt/minifi/build/nifi-minifi-cpp-${MINIFI_VERSION}.rpm" "${DUMP_LOCATION}/nifi-minifi-cpp-${MINIFI_VERSION}-${TARGZ_TAG}.rpm" || true
   docker rm -f "${container_id}"
 fi
diff --git a/docker/DockerVerify.sh b/docker/DockerVerify.sh
index 501cab174..515f205d7 100755
--- a/docker/DockerVerify.sh
+++ b/docker/DockerVerify.sh
@@ -177,7 +177,7 @@ TEST_DIRECTORY="${docker_dir}/test/integration"
 export TEST_DIRECTORY
 
 # Add --no-logcapture to see logs interleaved with the test output
-BEHAVE_OPTS=(--logging-level INFO --parallel-processes "${_arg_parallel_processes}" --parallel-scheme feature -o "${PWD}/behavex_output" -t "${_arg_tags_to_run}")
+BEHAVE_OPTS=(--show-progress-bar --logging-level INFO --parallel-processes "${_arg_parallel_processes}" --parallel-scheme feature -o "${PWD}/behavex_output" -t "${_arg_tags_to_run}")
 if ! test -z "${_arg_tags_to_exclude}"
 then
   IFS=','
diff --git a/docker/python-verify/installed.Dockerfile b/docker/installed/installed.Dockerfile
similarity index 100%
copy from docker/python-verify/installed.Dockerfile
copy to docker/installed/installed.Dockerfile
diff --git a/docker/python-verify/installed.dockerignore b/docker/installed/installed.dockerignore
similarity index 100%
rename from docker/python-verify/installed.dockerignore
rename to docker/installed/installed.dockerignore
diff --git a/docker/python-verify/installed.Dockerfile b/docker/installed/rpm.Dockerfile
similarity index 66%
rename from docker/python-verify/installed.Dockerfile
rename to docker/installed/rpm.Dockerfile
index 2b177976f..374aebcf5 100644
--- a/docker/python-verify/installed.Dockerfile
+++ b/docker/installed/rpm.Dockerfile
@@ -27,20 +27,14 @@ ARG UID=1001
 ARG GID=1001
 
 ENV USER minificpp
-ENV MINIFI_BASE_DIR /opt/minifi
-ENV MINIFI_HOME ${MINIFI_BASE_DIR}/minifi-current
-ENV MINIFI_VERSIONED_HOME ${MINIFI_BASE_DIR}/nifi-minifi-cpp-${MINIFI_VERSION}
+ENV MINIFI_HOME="FHS"
 
 
-RUN groupadd -g ${GID} ${USER} && useradd -m -g ${GID} ${USER} && \
-    install -d -o ${USER} -g ${USER} ${MINIFI_BASE_DIR} && ln -s ${MINIFI_VERSIONED_HOME} ${MINIFI_HOME}
-
-ADD ${ARCHIVE_LOCATION} ${MINIFI_BASE_DIR}
-RUN chown -R ${USER}:${USER} /opt/minifi  \
-    && /bin/bash -c "${INSTALL_PACKAGE_CMD}"
+COPY ${ARCHIVE_LOCATION} /tmp/minifi.rpm
+RUN /bin/bash -c "${INSTALL_PACKAGE_CMD}" \
+    && rpm -i /tmp/minifi.rpm
 
 USER ${USER}
-WORKDIR ${MINIFI_HOME}
 
 # Start MiNiFi CPP in the foreground
-CMD ["./bin/minifi.sh", "run"]
+CMD ["/usr/bin/minifi"]
diff --git a/docker/rockylinux/Dockerfile b/docker/rockylinux/Dockerfile
index a46953d9b..f122e8b62 100644
--- a/docker/rockylinux/Dockerfile
+++ b/docker/rockylinux/Dockerfile
@@ -40,7 +40,7 @@ COPY . ${MINIFI_BASE_DIR}
 
 # Install the system dependencies needed for a build
 # ccache is in EPEL
-RUN dnf -y install epel-release && dnf -y install gcc-toolset-12 sudo git which make libarchive ccache ca-certificates perl patch bison flex libtool cmake && \
+RUN dnf -y install epel-release && dnf -y install gcc-toolset-12 sudo git which make libarchive ccache ca-certificates perl patch bison flex libtool cmake rpmdevtools && \
     if echo "$MINIFI_OPTIONS" | grep -q "ENABLE_ALL=ON"; then dnf -y --enablerepo=devel install python3-devel; fi && \
     if echo "$MINIFI_OPTIONS" | grep -q "ENABLE_PYTHON_SCRIPTING=ON"; then dnf -y install python3-devel; fi && \
     if echo "$MINIFI_OPTIONS" | grep -q "ENABLE_SFTP=ON" && [ "${DOCKER_SKIP_TESTS}" == "OFF" ]; then dnf -y install java-1.8.0-openjdk maven; fi
@@ -65,4 +65,6 @@ RUN cd $MINIFI_BASE_DIR && \
     export PATH=/usr/lib64/ccache${PATH:+:${PATH}} && \
     export CCACHE_DIR=${MINIFI_BASE_DIR}/.ccache && \
     cmake -DSTATIC_BUILD= -DSKIP_TESTS=${DOCKER_SKIP_TESTS} ${MINIFI_OPTIONS} -DAWS_ENABLE_UNITY_BUILD=OFF -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" .. && \
+    make -j "$(nproc)" ${DOCKER_MAKE_TARGET} && \
+    cmake -DMINIFI_PACKAGING_TYPE=RPM .. && \
     make -j "$(nproc)" ${DOCKER_MAKE_TARGET}
diff --git a/docker/test/integration/cluster/ContainerStore.py b/docker/test/integration/cluster/ContainerStore.py
index 733e03b6a..9b5cba6b3 100644
--- a/docker/test/integration/cluster/ContainerStore.py
+++ b/docker/test/integration/cluster/ContainerStore.py
@@ -313,6 +313,9 @@ class ContainerStore:
         else:
             raise Exception('invalid flow engine: \'%s\'' % engine)
 
+    def acquire_transient_minifi(self, context, container_name: str, engine='minifi-cpp'):
+        self.acquire_container(context=context, container_name=container_name, engine=engine, command=["/bin/sh", "-c", "timeout 10s {run_minifi} && sleep 100".format(run_minifi=MinifiContainer.MINIFI_LOCATIONS.run_minifi_cmd)])
+
     def deploy_container(self, container_name: str):
         container_name = self.get_container_name_with_postfix(container_name)
         if container_name is None or container_name not in self.containers:
diff --git a/docker/test/integration/cluster/DockerTestCluster.py b/docker/test/integration/cluster/DockerTestCluster.py
index 150c5e7fe..2894f28aa 100644
--- a/docker/test/integration/cluster/DockerTestCluster.py
+++ b/docker/test/integration/cluster/DockerTestCluster.py
@@ -68,6 +68,9 @@ class DockerTestCluster:
     def acquire_container(self, context, name: str, engine: str = 'minifi-cpp', command=None):
         return self.container_store.acquire_container(context=context, container_name=name, engine=engine, command=command)
 
+    def acquire_transient_minifi(self, context, name: str, engine: str = 'minifi-cpp'):
+        return self.container_store.acquire_transient_minifi(context=context, container_name=name, engine=engine)
+
     def deploy_container(self, name):
         self.container_store.deploy_container(name)
 
@@ -329,7 +332,7 @@ class DockerTestCluster:
 
     def wait_for_container_startup_to_finish(self, container_name):
         container_name = self.container_store.get_container_name_with_postfix(container_name)
-        startup_success = self.wait_for_startup_log(container_name, 300)
+        startup_success = self.wait_for_startup_log(container_name, 120)
         if not startup_success:
             logging.error("Cluster startup failed for %s", container_name)
             return False
diff --git a/docker/test/integration/cluster/ImageStore.py b/docker/test/integration/cluster/ImageStore.py
index 723591e4a..108dc7d0f 100644
--- a/docker/test/integration/cluster/ImageStore.py
+++ b/docker/test/integration/cluster/ImageStore.py
@@ -130,8 +130,10 @@ class ImageStore:
     def __build_minifi_cpp_image_with_example_minifi_python_processors(self):
         dockerfile = dedent("""\
                 FROM {base_image}
-                RUN cp -r /opt/minifi/minifi-current/minifi-python-examples /opt/minifi/minifi-current/minifi-python/examples
-                """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION))
+                RUN cp -r {minifi_python_examples_dir} {minifi_python_dir}/examples
+                """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION,
+                           minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path,
+                           minifi_python_examples_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_examples))
 
         return self.__build_image(dockerfile)
 
@@ -145,18 +147,18 @@ class ImageStore:
         # /class ProcessorDetails:/,/^$/: Do the following between 'class ProcessorDetails:' and the first empty line (so we don't modify other PropertyDescriptor blocks below)
         # /^\s*dependencies\s*=/,/\]\s*$/: Do the following between 'dependencies =' at the start of a line, and ']' at the end of a line
         # d: Delete line
-        parse_document_sed_cmd = 'sed -i "/class ProcessorDetails:/,/^$/{/^\\s*dependencies\\s*=/,/\\]\\s*$/d}" /opt/minifi/minifi-current/minifi-python/nifi_python_processors/ParseDocument.py && \\'
-        chunk_document_sed_cmd = 'sed -i "/class ProcessorDetails:/,/^$/{/^\\s*dependencies\\s*=/,/\\]\\s*$/d}" /opt/minifi/minifi-current/minifi-python/nifi_python_processors/ChunkDocument.py && \\'
+        parse_document_sed_cmd = 'sed -i "/class ProcessorDetails:/,/^$/{{/^\\s*dependencies\\s*=/,/\\]\\s*$/d}}" {minifi_python_dir}/nifi_python_processors/ParseDocument.py && \\'.format(minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path)
+        chunk_document_sed_cmd = 'sed -i "/class ProcessorDetails:/,/^$/{{/^\\s*dependencies\\s*=/,/\\]\\s*$/d}}" {minifi_python_dir}/nifi_python_processors/ChunkDocument.py && \\'.format(minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path)
         if python_option == PythonWithDependenciesOptions.SYSTEM_INSTALLED_PACKAGES:
             if not MinifiContainer.MINIFI_TAG_PREFIX or "bookworm" in MinifiContainer.MINIFI_TAG_PREFIX or "noble" in MinifiContainer.MINIFI_TAG_PREFIX:
                 additional_cmd = "RUN pip3 install --break-system-packages 'langchain<=0.17.0'"
             else:
                 additional_cmd = "RUN pip3 install 'langchain<=0.17.0'"
         elif python_option == PythonWithDependenciesOptions.REQUIREMENTS_FILE:
-            requirements_install_command = "echo 'langchain<=0.17.0' > /opt/minifi/minifi-current/minifi-python/nifi_python_processors/requirements.txt && \\"
+            requirements_install_command = "echo 'langchain<=0.17.0' > {minifi_python_dir}/nifi_python_processors/requirements.txt && \\".format(minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path)
         elif python_option == PythonWithDependenciesOptions.INLINE_DEFINED_PACKAGES:
-            parse_document_sed_cmd = parse_document_sed_cmd[:-2] + ' sed -i "s/langchain==[0-9.]\\+/langchain<=0.17.0/" /opt/minifi/minifi-current/minifi-python/nifi_python_processors/ParseDocument.py && \\'
-            chunk_document_sed_cmd = 'sed -i "s/\\[\\\'langchain\\\'\\]/\\[\\\'langchain<=0.17.0\\\'\\]/" /opt/minifi/minifi-current/minifi-python/nifi_python_processors/ChunkDocument.py && \\'
+            parse_document_sed_cmd = parse_document_sed_cmd[:-2] + ' sed -i "s/langchain==[0-9.]\\+/langchain<=0.17.0/" {minifi_python_dir}/nifi_python_processors/ParseDocument.py && \\'.format(minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path)
+            chunk_document_sed_cmd = 'sed -i "s/\\[\\\'langchain\\\'\\]/\\[\\\'langchain<=0.17.0\\\'\\]/" {minifi_python_dir}/nifi_python_processors/ChunkDocument.py && \\'.format(minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path)
         if not MinifiContainer.MINIFI_TAG_PREFIX:
             pip3_install_command = "RUN apk --update --no-cache add py3-pip"
         dockerfile = dedent("""\
@@ -165,15 +167,15 @@ class ImageStore:
                 {pip3_install_command}
                 {additional_cmd}
                 USER minificpp
-                RUN wget {parse_document_url} --directory-prefix=/opt/minifi/minifi-current/minifi-python/nifi_python_processors && \\
-                    wget {chunk_document_url} --directory-prefix=/opt/minifi/minifi-current/minifi-python/nifi_python_processors && \\
-                    echo 'langchain<=0.17.0' > /opt/minifi/minifi-current/minifi-python/nifi_python_processors/requirements.txt && \\
+                RUN wget {parse_document_url} --directory-prefix={minifi_python_dir}/nifi_python_processors && \\
+                    wget {chunk_document_url} --directory-prefix={minifi_python_dir}/nifi_python_processors && \\
+                    echo 'langchain<=0.17.0' > {minifi_python_dir}/nifi_python_processors/requirements.txt && \\
                     {requirements_install_command}
                     {parse_document_sed_cmd}
                     {chunk_document_sed_cmd}
-                    python3 -m venv /opt/minifi/minifi-current/venv && \\
-                    python3 -m venv /opt/minifi/minifi-current/venv-with-langchain && \\
-                    . /opt/minifi/minifi-current/venv-with-langchain/bin/activate && python3 -m pip install --no-cache-dir "langchain<=0.17.0" && \\
+                    python3 -m venv {minifi_python_venv_parent}/venv && \\
+                    python3 -m venv {minifi_python_venv_parent}/venv-with-langchain && \\
+                    . {minifi_python_venv_parent}/venv-with-langchain/bin/activate && python3 -m pip install --no-cache-dir "langchain<=0.17.0" && \\
                     deactivate
                 """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION,
                            pip3_install_command=pip3_install_command,
@@ -182,7 +184,9 @@ class ImageStore:
                            additional_cmd=additional_cmd,
                            requirements_install_command=requirements_install_command,
                            parse_document_sed_cmd=parse_document_sed_cmd,
-                           chunk_document_sed_cmd=chunk_document_sed_cmd))
+                           chunk_document_sed_cmd=chunk_document_sed_cmd,
+                           minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path,
+                           minifi_python_venv_parent=MinifiContainer.MINIFI_LOCATIONS.minifi_python_venv_parent))
         return self.__build_image(dockerfile)
 
     def __build_minifi_cpp_image_with_nifi_python_processors(self):
@@ -194,21 +198,24 @@ class ImageStore:
                 USER root
                 {pip3_install_command}
                 USER minificpp
-                COPY RotatingForwarder.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/RotatingForwarder.py
-                COPY SpecialPropertyTypeChecker.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/SpecialPropertyTypeChecker.py
-                COPY ProcessContextInterfaceChecker.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/ProcessContextInterfaceChecker.py
-                COPY CreateFlowFile.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/CreateFlowFile.py
-                COPY FailureWithAttributes.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/FailureWithAttributes.py
-                COPY subtractutils.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/compute/subtractutils.py
-                COPY RelativeImporterProcessor.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/compute/processors/RelativeImporterProcessor.py
-                COPY multiplierutils.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/compute/processors/multiplierutils.py
-                COPY CreateNothing.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/CreateNothing.py
-                COPY FailureWithContent.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/FailureWithContent.py
-                COPY TransferToOriginal.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/TransferToOriginal.py
-                COPY SetRecordField.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/SetRecordField.py
-                COPY TestStateManager.py /opt/minifi/minifi-current/minifi-python/nifi_python_processors/TestStateManager.py
-                RUN python3 -m venv /opt/minifi/minifi-current/venv
-                """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION, pip3_install_command=pip3_install_command))
+                COPY RotatingForwarder.py {minifi_python_dir}/nifi_python_processors/RotatingForwarder.py
+                COPY SpecialPropertyTypeChecker.py {minifi_python_dir}/nifi_python_processors/SpecialPropertyTypeChecker.py
+                COPY ProcessContextInterfaceChecker.py {minifi_python_dir}/nifi_python_processors/ProcessContextInterfaceChecker.py
+                COPY CreateFlowFile.py {minifi_python_dir}/nifi_python_processors/CreateFlowFile.py
+                COPY FailureWithAttributes.py {minifi_python_dir}/nifi_python_processors/FailureWithAttributes.py
+                COPY subtractutils.py {minifi_python_dir}/nifi_python_processors/compute/subtractutils.py
+                COPY RelativeImporterProcessor.py {minifi_python_dir}/nifi_python_processors/compute/processors/RelativeImporterProcessor.py
+                COPY multiplierutils.py {minifi_python_dir}/nifi_python_processors/compute/processors/multiplierutils.py
+                COPY CreateNothing.py {minifi_python_dir}/nifi_python_processors/CreateNothing.py
+                COPY FailureWithContent.py {minifi_python_dir}/nifi_python_processors/FailureWithContent.py
+                COPY TransferToOriginal.py {minifi_python_dir}/nifi_python_processors/TransferToOriginal.py
+                COPY SetRecordField.py {minifi_python_dir}/nifi_python_processors/SetRecordField.py
+                COPY TestStateManager.py {minifi_python_dir}/nifi_python_processors/TestStateManager.py
+                RUN python3 -m venv {minifi_python_venv_parent}/venv
+                """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION,
+                           pip3_install_command=pip3_install_command,
+                           minifi_python_dir=MinifiContainer.MINIFI_LOCATIONS.minifi_python_dir_path,
+                           minifi_python_venv_parent=MinifiContainer.MINIFI_LOCATIONS.minifi_python_venv_parent))
 
         def build_full_python_resource_path(resource):
             return os.path.join(self.test_dir, "resources", "python", resource)
@@ -232,8 +239,9 @@ class ImageStore:
     def __build_minifi_cpp_image_with_llamacpp_model(self):
         dockerfile = dedent("""\
                 FROM {base_image}
-                RUN mkdir /opt/minifi/minifi-current/models && wget https://huggingface.co/bartowski/Qwen2-0.5B-Instruct-GGUF/resolve/main/Qwen2-0.5B-Instruct-IQ3_M.gguf --directory-prefix=/opt/minifi/minifi-current/models
-                """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION))
+                RUN mkdir {models_path} && wget https://huggingface.co/bartowski/Qwen2-0.5B-Instruct-GGUF/resolve/main/Qwen2-0.5B-Instruct-IQ3_M.gguf --directory-prefix={models_path}
+                """.format(base_image='apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION,
+                           models_path=MinifiContainer.MINIFI_LOCATIONS.models_path))
 
         return self.__build_image(dockerfile)
 
diff --git a/docker/test/integration/cluster/MinifiControllerExecutor.py b/docker/test/integration/cluster/MinifiControllerExecutor.py
index 8da19835c..880e43e74 100644
--- a/docker/test/integration/cluster/MinifiControllerExecutor.py
+++ b/docker/test/integration/cluster/MinifiControllerExecutor.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 import logging
 from .DockerCommunicator import DockerCommunicator
+from .containers.MinifiContainer import MinifiContainer
 
 
 class MinifiControllerExecutor:
@@ -21,24 +22,24 @@ class MinifiControllerExecutor:
         self.container_communicator = container_communicator
 
     def update_flow(self, container_name: str):
-        self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--updateflow", "/tmp/resources/minifi-controller/config.yml"])
+        self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--updateflow", "/tmp/resources/minifi-controller/config.yml"])
 
     def updated_config_is_persisted(self, container_name: str) -> bool:
-        (code, output) = self.container_communicator.execute_command(container_name, ["cat", "/opt/minifi/minifi-current/conf/config.yml"])
+        (code, output) = self.container_communicator.execute_command(container_name, ["cat", MinifiContainer.MINIFI_LOCATIONS.config_path])
         return code == 0 and "2f2a3b47-f5ba-49f6-82b5-bc1c86b96f38" in output
 
     def stop_component(self, component: str, container_name: str):
-        self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--stop", component])
+        self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--stop", component])
 
     def start_component(self, component: str, container_name: str):
-        self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--start", component])
+        self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--start", component])
 
     def is_component_running(self, component: str, container_name: str) -> bool:
-        (code, output) = self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--list", "components"])
+        (code, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--list", "components"])
         return code == 0 and component + ", running: true" in output
 
     def get_connections(self, container_name: str):
-        (_, output) = self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--list", "connections"])
+        (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--list", "connections"])
         connections = []
         for line in output.split('\n'):
             if not line.startswith('[') and not line.startswith('Connection Names'):
@@ -46,14 +47,14 @@ class MinifiControllerExecutor:
         return connections
 
     def get_full_connection_count(self, container_name: str) -> int:
-        (_, output) = self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--getfull"])
+        (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--getfull"])
         for line in output.split('\n'):
             if "are full" in line:
                 return int(line.split(' ')[0])
         return -1
 
     def get_connection_size(self, connection: str, container_name: str):
-        (_, output) = self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--getsize", connection])
+        (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--getsize", connection])
         for line in output.split('\n'):
             if "Size/Max of " + connection in line:
                 size_and_max = line.split(connection)[1].split('/')
@@ -61,7 +62,7 @@ class MinifiControllerExecutor:
         return (-1, -1)
 
     def get_manifest(self, container_name: str) -> str:
-        (_, output) = self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--manifest"])
+        (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--manifest"])
         manifest = ""
         for line in output.split('\n'):
             if not line.startswith('['):
@@ -69,9 +70,9 @@ class MinifiControllerExecutor:
         return manifest
 
     def get_debug_bundle(self, container_name: str, dest: str) -> bool:
-        (code, _) = self.container_communicator.execute_command(container_name, ["/opt/minifi/minifi-current/bin/minificontroller", "--debug", "/opt/minifi/minifi-current/"])
+        (code, _) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--debug", "/tmp"])
         if code != 0:
             logging.error("Minifi controller debug command failed with code: %d", code)
             return False
 
-        return self.container_communicator.copy_file_from_container(container_name, "/opt/minifi/minifi-current/debug.tar.gz", dest)
+        return self.container_communicator.copy_file_from_container(container_name, "/tmp/debug.tar.gz", dest)
diff --git a/docker/test/integration/cluster/containers/MinifiAsPodInKubernetesCluster.py b/docker/test/integration/cluster/containers/MinifiAsPodInKubernetesCluster.py
index 59488cc2f..4a660906c 100644
--- a/docker/test/integration/cluster/containers/MinifiAsPodInKubernetesCluster.py
+++ b/docker/test/integration/cluster/containers/MinifiAsPodInKubernetesCluster.py
@@ -29,7 +29,7 @@ class MinifiAsPodInKubernetesCluster(MinifiContainer):
 
     def __init__(self, feature_context, kubernetes_proxy, config_dir, minifi_options, name, vols, network, image_store, command=None):
         test_dir = os.environ['TEST_DIRECTORY']
-        shutil.copy(os.path.join(test_dir, os.pardir, os.pardir, os.pardir, 'conf', 'minifi.properties'), config_dir)
+        shutil.copy(os.path.join(test_dir, 'resources', 'kubernetes', 'minifi-conf', 'minifi.properties'), config_dir)
         shutil.copy(os.path.join(test_dir, 'resources', 'kubernetes', 'minifi-conf', 'minifi-log.properties'), config_dir)
         super().__init__(feature_context=feature_context,
                          config_dir=config_dir,
diff --git a/docker/test/integration/cluster/containers/MinifiContainer.py b/docker/test/integration/cluster/containers/MinifiContainer.py
index e6b3cf68a..dbbdc2143 100644
--- a/docker/test/integration/cluster/containers/MinifiContainer.py
+++ b/docker/test/integration/cluster/containers/MinifiContainer.py
@@ -51,10 +51,41 @@ class MinifiOptions:
         self.download_llama_model = False
 
 
+class MinifiLocations:
+    MINIFI_TAG_PREFIX = os.environ['MINIFI_TAG_PREFIX']
+    MINIFI_VERSION = os.environ['MINIFI_VERSION']
+
+    def __init__(self):
+        if "rpm" in MinifiLocations.MINIFI_TAG_PREFIX:
+            self.run_minifi_cmd = '/usr/bin/minifi'
+            self.config_path = '/etc/nifi-minifi-cpp/config.yml'
+            self.properties_path = '/etc/nifi-minifi-cpp/minifi.properties'
+            self.log_properties_path = '/etc/nifi-minifi-cpp/minifi-log.properties'
+            self.uid_properties_path = '/etc/nifi-minifi-cpp/minifi-uid.properties'
+            self.minifi_python_dir_path = '/var/lib/nifi-minifi-cpp/minifi-python'
+            self.minifi_python_venv_parent = '/var/lib/nifi-minifi-cpp'
+            self.minifi_python_examples = '/usr/share/doc/nifi-minifi-cpp/pythonprocessor-examples'
+            self.models_path = '/var/lib/nifi-minifi-cpp/models'
+            self.minifi_controller_path = '/usr/bin/minifi-controller'
+            self.minifi_home = '/var/lib/nifi-minifi-cpp'
+        else:
+            self.run_minifi_cmd = '/opt/minifi/minifi-current/bin/minifi.sh run'
+            self.config_path = '/opt/minifi/minifi-current/conf/config.yml'
+            self.properties_path = '/opt/minifi/minifi-current/conf/minifi.properties'
+            self.log_properties_path = '/opt/minifi/minifi-current/conf/minifi-log.properties'
+            self.uid_properties_path = '/opt/minifi/minifi-current/conf/minifi-uid.properties'
+            self.minifi_python_dir_path = '/opt/minifi/minifi-current/minifi-python'
+            self.minifi_python_examples = '/opt/minifi/minifi-current/minifi-python-examples'
+            self.minifi_python_venv_parent = '/opt/minifi/minifi-current'
+            self.models_path = '/opt/minifi/minifi-current/models'
+            self.minifi_controller_path = '/opt/minifi/minifi-current/bin/minifi-controller'
+            self.minifi_home = '/opt/minifi/minifi-current'
+
+
 class MinifiContainer(FlowContainer):
     MINIFI_TAG_PREFIX = os.environ['MINIFI_TAG_PREFIX']
     MINIFI_VERSION = os.environ['MINIFI_VERSION']
-    MINIFI_ROOT = '/opt/minifi/nifi-minifi-cpp-' + MINIFI_VERSION
+    MINIFI_LOCATIONS = MinifiLocations()
 
     def __init__(self, feature_context, config_dir, options, name, vols, network, image_store, command=None):
         self.options = options
@@ -99,6 +130,12 @@ class MinifiContainer(FlowContainer):
     def _create_properties(self):
         properties_file_path = os.path.join(self.container_specific_config_dir, 'minifi.properties')
         with open(properties_file_path, 'a') as f:
+            f.write("nifi.flow.configuration.file={conf_path}\n".format(conf_path=MinifiContainer.MINIFI_LOCATIONS.config_path))
+            f.write("nifi.provenance.repository.directory.default={minifi_home}/provenance_repository\n".format(minifi_home=MinifiContainer.MINIFI_LOCATIONS.minifi_home))
+            f.write("nifi.flowfile.repository.directory.default={minifi_home}/flowfile_repository\n".format(minifi_home=MinifiContainer.MINIFI_LOCATIONS.minifi_home))
+            f.write("nifi.database.content.repository.directory.default={minifi_home}/content_repository\n".format(minifi_home=MinifiContainer.MINIFI_LOCATIONS.minifi_home))
+            f.write("nifi.python.processor.dir={minifi_home}/minifi-python\n".format(minifi_home=MinifiContainer.MINIFI_LOCATIONS.minifi_home))
+
             if self.options.enable_c2:
                 f.write("nifi.c2.enable=true\n")
                 f.write(f"nifi.c2.rest.url=http://minifi-c2-server-{self.feature_context.id}:10090/c2/config/heartbeat\n")
@@ -157,9 +194,9 @@ class MinifiContainer(FlowContainer):
                 f.write("controller.socket.local.any.interface=false\n")
 
             if self.options.use_nifi_python_processors_with_virtualenv or self.options.remove_python_requirements_txt or self.options.use_nifi_python_processors_without_dependencies:
-                f.write("nifi.python.virtualenv.directory=/opt/minifi/minifi-current/venv\n")
+                f.write("nifi.python.virtualenv.directory={minifi_python_venv_parent}/venv\n".format(minifi_python_venv_parent=MinifiContainer.MINIFI_LOCATIONS.minifi_python_venv_parent))
             elif self.options.use_nifi_python_processors_with_virtualenv_packages_installed:
-                f.write("nifi.python.virtualenv.directory=/opt/minifi/minifi-current/venv-with-langchain\n")
+                f.write("nifi.python.virtualenv.directory={minifi_python_venv_parent}/venv-with-langchain\n".format(minifi_python_venv_parent=MinifiContainer.MINIFI_LOCATIONS.minifi_python_venv_parent))
 
             if self.options.use_nifi_python_processors_with_virtualenv or self.options.remove_python_requirements_txt:
                 f.write("nifi.python.install.packages.automatically=true\n")
@@ -173,10 +210,10 @@ class MinifiContainer(FlowContainer):
         self._create_properties()
         if not self.options.use_flow_config_from_url:
             self._create_config()
-            self.vols[os.path.join(self.container_specific_config_dir, 'config.yml')] = {"bind": os.path.join(MinifiContainer.MINIFI_ROOT, 'conf', 'config.yml'), "mode": "rw"}
+            self.vols[os.path.join(self.container_specific_config_dir, 'config.yml')] = {"bind": MinifiContainer.MINIFI_LOCATIONS.config_path, "mode": "rw"}
 
-        self.vols[os.path.join(self.container_specific_config_dir, 'minifi.properties')] = {"bind": os.path.join(MinifiContainer.MINIFI_ROOT, 'conf', 'minifi.properties'), "mode": "rw"}
-        self.vols[os.path.join(self.container_specific_config_dir, 'minifi-log.properties')] = {"bind": os.path.join(MinifiContainer.MINIFI_ROOT, 'conf', 'minifi-log.properties'), "mode": "rw"}
+        self.vols[os.path.join(self.container_specific_config_dir, 'minifi.properties')] = {"bind": MinifiContainer.MINIFI_LOCATIONS.properties_path, "mode": "rw"}
+        self.vols[os.path.join(self.container_specific_config_dir, 'minifi-log.properties')] = {"bind": MinifiContainer.MINIFI_LOCATIONS.log_properties_path, "mode": "rw"}
 
     def deploy(self):
         if not self.set_deployed():
@@ -203,7 +240,7 @@ class MinifiContainer(FlowContainer):
             image = 'apacheminificpp:' + MinifiContainer.MINIFI_TAG_PREFIX + MinifiContainer.MINIFI_VERSION
 
         if self.options.use_flow_config_from_url:
-            self.command = ["/bin/sh", "-c", "rm " + MinifiContainer.MINIFI_ROOT + "/conf/config.yml && ./bin/minifi.sh run"]
+            self.command = ["/bin/sh", "-c", "rm " + MinifiContainer.MINIFI_LOCATIONS.config_path + " && " + MinifiContainer.MINIFI_LOCATIONS.run_minifi_cmd]
 
         ports = {}
         if self.options.enable_prometheus or self.options.enable_prometheus_with_ssl:
diff --git a/docker/test/integration/features/MiNiFi_integration_test_driver.py b/docker/test/integration/features/MiNiFi_integration_test_driver.py
index bfe9e6739..27316150f 100644
--- a/docker/test/integration/features/MiNiFi_integration_test_driver.py
+++ b/docker/test/integration/features/MiNiFi_integration_test_driver.py
@@ -60,6 +60,9 @@ class MiNiFi_integration_test:
     def acquire_container(self, context, name, engine='minifi-cpp', command=None):
         return self.cluster.acquire_container(context=context, name=name, engine=engine, command=command)
 
+    def acquire_transient_minifi(self, context, name, engine='minifi-cpp'):
+        return self.cluster.acquire_transient_minifi(context=context, name=name, engine=engine)
+
     def start_kafka_broker(self, context):
         self.cluster.acquire_container(context=context, name='kafka-broker', engine='kafka-broker')
         self.cluster.deploy_container(name='kafka-broker')
diff --git a/docker/test/integration/features/couchbase.feature b/docker/test/integration/features/couchbase.feature
index 88c75020f..ecf4ce8a1 100644
--- a/docker/test/integration/features/couchbase.feature
+++ b/docker/test/integration/features/couchbase.feature
@@ -36,7 +36,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 60 seconds
+    Then the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.sequence.number value:[1-9][0-9]*" in less than 1 seconds
@@ -62,7 +62,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 60 seconds
+    Then the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.sequence.number value:[1-9][0-9]*" in less than 1 seconds
@@ -93,7 +93,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 60 seconds
+    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 10 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
@@ -124,7 +124,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 60 seconds
+    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 10 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
@@ -156,7 +156,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 60 seconds
+    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 10 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
@@ -184,7 +184,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then the Minifi logs contain the following message: "Failed to get content for document 'test_doc_id' from collection 'test_bucket._default._default' with the following exception: 'raw_binary_transcoder expects document to have BINARY common flags" in less than 60 seconds
+    Then the Minifi logs contain the following message: "Failed to get content for document 'test_doc_id' from collection 'test_bucket._default._default' with the following exception: 'raw_binary_transcoder expects document to have BINARY common flags" in less than 100 seconds
 
   Scenario: A MiNiFi instance can get data from test bucket with GetCouchbaseKey processor using SSL connection
     Given a GetFile processor with the "Input Directory" property set to "/tmp/input"
@@ -211,7 +211,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 60 seconds
+    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 10 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
@@ -241,7 +241,7 @@ Feature: Executing Couchbase operations from MiNiFi-C++
     When a Couchbase server is started
     And all instances start up
 
-    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 60 seconds
+    Then a flowfile with the JSON content '{"field1": "value1", "field2": "value2"}' is placed in the monitored directory in less than 100 seconds
     And the Minifi logs contain the following message: "key:couchbase.bucket value:test_bucket" in less than 10 seconds
     And the Minifi logs contain the following message: "key:couchbase.doc.id value:test_doc_id" in less than 1 seconds
     And the Minifi logs match the following regex: "key:couchbase.doc.cas value:[1-9][0-9]*" in less than 1 seconds
diff --git a/docker/test/integration/features/environment.py b/docker/test/integration/features/environment.py
index d98d2f3f5..c6422a34c 100644
--- a/docker/test/integration/features/environment.py
+++ b/docker/test/integration/features/environment.py
@@ -81,6 +81,9 @@ def before_feature(context, feature):
         if not is_x86:
             feature.skip("This feature is only x86/x64 compatible")
 
+    if "SKIP_RPM" in feature.tags and "rpm" in os.environ['MINIFI_TAG_PREFIX']:
+        feature.skip("This feature is not yet supported on RPM installed images")
+
     feature_id = shortuuid.uuid()
     context.feature_id = feature_id
     context.directory_bindings = DockerTestDirectoryBindings(feature_id)
diff --git a/docker/test/integration/features/kubernetes.feature b/docker/test/integration/features/kubernetes.feature
index 3b5c58737..a88dd417d 100644
--- a/docker/test/integration/features/kubernetes.feature
+++ b/docker/test/integration/features/kubernetes.feature
@@ -15,6 +15,7 @@
 
 @requires.kubernetes.cluster
 @ENABLE_KUBERNETES
+@SKIP_RPM
 Feature: TailFile can collect logs from Kubernetes pods
 
   Background:
diff --git a/docker/test/integration/features/replace_text.feature b/docker/test/integration/features/replace_text.feature
index 8b37a563e..e283bcf35 100644
--- a/docker/test/integration/features/replace_text.feature
+++ b/docker/test/integration/features/replace_text.feature
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-@WIP
+@CORE
 Feature: Changing flowfile contents using the ReplaceText processor
   Background:
     Given the content of "/tmp/output" is monitored
diff --git a/docker/test/integration/features/steps/steps.py b/docker/test/integration/features/steps/steps.py
index 29e526f91..b624ecfcf 100644
--- a/docker/test/integration/features/steps/steps.py
+++ b/docker/test/integration/features/steps/steps.py
@@ -321,7 +321,7 @@ def step_impl(context):
 
 @given("a transient MiNiFi flow with the name \"{flow_name}\" is set up")
 def step_impl(context, flow_name):
-    context.test.acquire_container(context=context, name=flow_name, command=["/bin/sh", "-c", "timeout 10s ./bin/minifi.sh run && sleep 100"])
+    context.test.acquire_transient_minifi(context=context, name=flow_name)
 
 
 @given("the provenance repository is enabled in MiNiFi")
diff --git a/docker/test/integration/resources/kubernetes/minifi-conf/minifi.properties b/docker/test/integration/resources/kubernetes/minifi-conf/minifi.properties
new file mode 100644
index 000000000..0fdb377b1
--- /dev/null
+++ b/docker/test/integration/resources/kubernetes/minifi-conf/minifi.properties
@@ -0,0 +1,10 @@
+nifi.administrative.yield.duration=30 sec
+nifi.bored.yield.duration=100 millis
+
+nifi.provenance.repository.max.storage.time=1 MIN
+nifi.provenance.repository.max.storage.size=1 MB
+nifi.provenance.repository.class.name=NoOpRepository
+nifi.content.repository.class.name=DatabaseContentRepository
+
+nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation
+nifi.c2.full.heartbeat=false
diff --git a/docker/test/integration/resources/minifi/minifi.properties b/docker/test/integration/resources/minifi/minifi.properties
index 69322f739..68dbec03c 100644
--- a/docker/test/integration/resources/minifi/minifi.properties
+++ b/docker/test/integration/resources/minifi/minifi.properties
@@ -1,13 +1,7 @@
-nifi.flow.configuration.file=./conf/config.yml
 nifi.administrative.yield.duration=30 sec
 nifi.bored.yield.duration=100 millis
-nifi.extension.path=../extensions/*
-nifi.provenance.repository.directory.default=${MINIFI_HOME}/provenance_repository
 nifi.provenance.repository.max.storage.time=1 MIN
 nifi.provenance.repository.max.storage.size=1 MB
-nifi.flowfile.repository.directory.default=${MINIFI_HOME}/flowfile_repository
 nifi.database.content.repository.directory.default=${MINIFI_HOME}/content_repository
 nifi.content.repository.class.name=DatabaseContentRepository
-
-nifi.python.processor.dir=${MINIFI_HOME}/minifi-python/
 nifi.flow.engine.threads=5
diff --git a/encrypt-config/CMakeLists.txt b/encrypt-config/CMakeLists.txt
index 05146bdb7..a6f728133 100644
--- a/encrypt-config/CMakeLists.txt
+++ b/encrypt-config/CMakeLists.txt
@@ -18,26 +18,26 @@
 
 file(GLOB ENCRYPT_CONFIG_FILES  "*.cpp")
 if (WIN32)
-    set(EXECUTABLE_FILE_NAME "encrypt-config.exe")
-    set(EXECUTABLE_FILE_DESCRIPTION "${PRODUCT_NAME} encrypt-config tool")
+    set(EXECUTABLE_FILE_NAME "minifi-encrypt-config.exe")
+    set(EXECUTABLE_FILE_DESCRIPTION "${PRODUCT_NAME} minifi-encrypt-config tool")
     configure_file(${CMAKE_SOURCE_DIR}/versioninfo.rc.in ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc @ONLY)
     list(APPEND ENCRYPT_CONFIG_FILES "${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc")
 endif()
-add_minifi_executable(encrypt-config "${ENCRYPT_CONFIG_FILES}")
-target_include_directories(encrypt-config PRIVATE ../libminifi/include)
+add_minifi_executable(minifi-encrypt-config "${ENCRYPT_CONFIG_FILES}")
+target_include_directories(minifi-encrypt-config PRIVATE ../libminifi/include)
 include(ArgParse)
-target_link_libraries(encrypt-config libsodium argparse core-minifi)
-set_target_properties(encrypt-config PROPERTIES OUTPUT_NAME encrypt-config)
-set_target_properties(encrypt-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+target_link_libraries(minifi-encrypt-config libsodium argparse core-minifi)
+set_target_properties(minifi-encrypt-config PROPERTIES OUTPUT_NAME minifi-encrypt-config)
+set_target_properties(minifi-encrypt-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 
 if (NOT WIN32)
     if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT APPLE)
-        target_link_options(encrypt-config PRIVATE "-Wl,--disable-new-dtags")
+        target_link_options(minifi-encrypt-config PRIVATE "-Wl,--disable-new-dtags")
     endif()
     if (APPLE)
-        set_target_properties(encrypt-config PROPERTIES INSTALL_RPATH "@loader_path")
+        set_target_properties(minifi-encrypt-config PROPERTIES INSTALL_RPATH "@loader_path")
     else()
-        set_target_properties(encrypt-config PROPERTIES INSTALL_RPATH "$ORIGIN")
+        set_target_properties(minifi-encrypt-config PROPERTIES INSTALL_RPATH "$ORIGIN")
     endif()
 endif()
-install(TARGETS encrypt-config RUNTIME DESTINATION bin COMPONENT bin)
+install(TARGETS minifi-encrypt-config RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin)
diff --git a/encrypt-config/FlowConfigEncryptor.cpp b/encrypt-config/FlowConfigEncryptor.cpp
index fa14954ae..7826112a4 100644
--- a/encrypt-config/FlowConfigEncryptor.cpp
+++ b/encrypt-config/FlowConfigEncryptor.cpp
@@ -180,8 +180,7 @@ void encryptSensitiveValuesInFlowConfig(const EncryptionKeys& keys, const std::f
   }
 
   const auto configure = std::make_shared<ConfigureImpl>();
-  configure->setHome(minifi_home);
-  configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);
+  configure->loadConfigureFile(minifi_home / DEFAULT_NIFI_PROPERTIES_FILE);
 
   bool encrypt_whole_flow_config_file = (configure->get(Configure::nifi_flow_configuration_encrypt) | utils::andThen(utils::string::toBool)).value_or(false);
   auto whole_file_encryptor = encrypt_whole_flow_config_file ? utils::crypto::EncryptionProvider::create(minifi_home) : std::nullopt;
diff --git a/extensions/expression-language/tests/ExpressionLanguageTests.cpp b/extensions/expression-language/tests/ExpressionLanguageTests.cpp
index 2488e8c41..007f23134 100644
--- a/extensions/expression-language/tests/ExpressionLanguageTests.cpp
+++ b/extensions/expression-language/tests/ExpressionLanguageTests.cpp
@@ -193,7 +193,7 @@ TEST_CASE("GetFile PutFile dynamic attribute", "[expressionLanguageTestGetFilePu
   LogTestController::getInstance().setTrace<minifi::processors::UpdateAttribute>();
 
   auto conf = std::make_shared<minifi::ConfigureImpl>();
-  conf->setHome(testController.createTempDirectory());
+  conf->setLocations(minifi::LocationsImpl::createFromMinifiHome(testController.createTempDirectory()));
 
   conf->set("nifi.my.own.property", "custom_value");
 
diff --git a/extensions/python/CMakeLists.txt b/extensions/python/CMakeLists.txt
index 6eb2b0003..656c324cc 100644
--- a/extensions/python/CMakeLists.txt
+++ b/extensions/python/CMakeLists.txt
@@ -84,11 +84,23 @@ else()
         COMMENT "Creating symlink for minifi-python-script-extension"
     )
 
-    install(
-        FILES "${CMAKE_BINARY_DIR}/bin/minifi_native.so"
-        DESTINATION extensions
-        COMPONENT minifi_python_native_module
-    )
+
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        install(
+                FILES "${CMAKE_BINARY_DIR}/bin/minifi_native.so"
+                DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/extensions/
+                COMPONENT minifi_python_native_module
+        )
+    elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+        install(
+                FILES "${CMAKE_BINARY_DIR}/bin/minifi_native.so"
+                DESTINATION extensions
+                COMPONENT minifi_python_native_module
+        )
+    else()
+        message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+    endif()
+
 endif()
 
 if (NOT WIN32)
diff --git a/extensions/python/PythonCreator.h b/extensions/python/PythonCreator.h
index e86ddc526..a6a38e7ea 100644
--- a/extensions/python/PythonCreator.h
+++ b/extensions/python/PythonCreator.h
@@ -162,15 +162,21 @@ class PythonCreator : public minifi::core::CoreComponentImpl {
   }
 
   std::filesystem::path getPythonLibPath(const std::shared_ptr<Configure>& configuration) {
-    constexpr const char* DEFAULT_EXTENSION_PATH = "../extensions/*";
-    std::string pattern = [&] {
-      auto opt_pattern = configuration->get(minifi::Configuration::nifi_extension_path);
-      if (!opt_pattern) {
-        logger_->log_warn("No extension path is provided, using default: '{}'", DEFAULT_EXTENSION_PATH);
-      }
-      return opt_pattern.value_or(DEFAULT_EXTENSION_PATH);
+    constexpr std::string_view DEFAULT_EXTENSION_PATH = "../extensions/*";
+    const std::string pattern = [&] {
+      if (const auto opt_pattern = configuration->get(minifi::Configuration::nifi_extension_path)) {
+        return *opt_pattern;
+      };
+
+      if (const auto locations = configuration->getLocations()) {
+        logger_->log_warn("No extension path is provided in properties, using default : '{}'", locations->getDefaultExtensionsPattern());
+        return std::string(locations->getDefaultExtensionsPattern());
+      };
+
+      logger_->log_error("No extension path is provided in properties and locations is empty, using hard-coded default: '{}'", DEFAULT_EXTENSION_PATH);
+      return std::string(DEFAULT_EXTENSION_PATH);
     }();
-    auto candidates = utils::file::match(utils::file::FilePattern(pattern, [&] (std::string_view subpattern, std::string_view error_msg) {
+    const auto candidates = utils::file::match(utils::file::FilePattern(pattern, [&] (std::string_view subpattern, std::string_view error_msg) {
       logger_->log_error("Error in subpattern '{}': {}", subpattern, error_msg);
     }));
 
diff --git a/extensions/python/tests/PythonManifestTests.cpp b/extensions/python/tests/PythonManifestTests.cpp
index 3b4f90612..7c68bdabc 100644
--- a/extensions/python/tests/PythonManifestTests.cpp
+++ b/extensions/python/tests/PythonManifestTests.cpp
@@ -54,7 +54,7 @@ ValueNode getNthAllowableValue(const SerializedResponseNode& node, size_t n) {
 TEST_CASE("Python processor's description is part of the manifest") {
   TestControllerWithFlow controller(empty_flow, false /* DEFER FLOW SETUP */);
 
-  auto python_dir = controller.configuration_->getHome() / "minifi-python";
+  auto python_dir = controller.createTempDirectory() / "minifi-python";
   utils::file::create_dir(python_dir);
   std::ofstream{python_dir / "MyPyProc.py"} <<
     "def describe(proc):\n"
diff --git a/extensions/rocksdb-repos/DatabaseContentRepository.cpp b/extensions/rocksdb-repos/DatabaseContentRepository.cpp
index 5c0f826de..5829601ab 100644
--- a/extensions/rocksdb-repos/DatabaseContentRepository.cpp
+++ b/extensions/rocksdb-repos/DatabaseContentRepository.cpp
@@ -35,11 +35,14 @@
 namespace org::apache::nifi::minifi::core::repository {
 
 bool DatabaseContentRepository::initialize(const std::shared_ptr<minifi::Configure> &configuration) {
+  const auto locations = configuration->getLocations();
+  const auto working_dir = locations ? locations->getWorkingDir() : std::filesystem::current_path();  // TODO(mzink)
+
   std::string value;
   if (configuration->get(Configure::nifi_dbcontent_repository_directory_default, value) && !value.empty()) {
     directory_ = value;
   } else {
-    directory_ = (configuration->getHome() / "dbcontentrepository").string();
+    directory_ = (working_dir / "dbcontentrepository").string();
   }
   auto purge_period_str = utils::string::trim(configuration->get(Configure::nifi_dbcontent_repository_purge_period).value_or("1 s"));
   if (purge_period_str == "0") {
@@ -50,7 +53,7 @@ bool DatabaseContentRepository::initialize(const std::shared_ptr<minifi::Configu
     logger_->log_error("Malformed delete period value, expected time format: '{}'", purge_period_str);
     purge_period_ = std::chrono::seconds{1};
   }
-  const auto encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{configuration->getHome()}, DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME});
+  const auto encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{working_dir}, DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME});
   logger_->log_info("Using {} DatabaseContentRepository", encrypted_env ? "encrypted" : "plaintext");
 
   setCompactionPeriod(configuration);
diff --git a/extensions/rocksdb-repos/FlowFileRepository.cpp b/extensions/rocksdb-repos/FlowFileRepository.cpp
index 82ea380c9..346a512d6 100644
--- a/extensions/rocksdb-repos/FlowFileRepository.cpp
+++ b/extensions/rocksdb-repos/FlowFileRepository.cpp
@@ -210,7 +210,10 @@ bool FlowFileRepository::initialize(const std::shared_ptr<Configure> &configure)
 
   setCompactionPeriod(configure);
 
-  const auto encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{configure->getHome()}, DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME});
+  const auto locations = configure->getLocations();
+  const auto working_dir = locations ? locations->getWorkingDir() : std::filesystem::current_path();  // TODO(mzink)
+
+  const auto encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{working_dir}, DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME});
   logger_->log_info("Using {} FlowFileRepository", encrypted_env ? "encrypted" : "plaintext");
 
   verify_checksums_in_rocksdb_reads_ = (configure->get(Configure::nifi_flowfile_repository_rocksdb_read_verify_checksums) | utils::andThen(&utils::string::toBool)).value_or(false);
diff --git a/extensions/rocksdb-repos/controllers/RocksDbStateStorage.cpp b/extensions/rocksdb-repos/controllers/RocksDbStateStorage.cpp
index 5f5097fb7..58496ef50 100644
--- a/extensions/rocksdb-repos/controllers/RocksDbStateStorage.cpp
+++ b/extensions/rocksdb-repos/controllers/RocksDbStateStorage.cpp
@@ -60,9 +60,13 @@ void RocksDbStateStorage::onEnable() {
   auto_persistor_.start(always_persist, auto_persistence_interval, [this] { return persistNonVirtual(); });
   db_.reset();
 
-  auto encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{configuration_->getHome()}, core::repository::DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME});
+
+  const auto locations = configuration_->getLocations();
+  const auto working_dir = locations ? locations->getWorkingDir() : std::filesystem::current_path();  // TODO(mzink)
+
+  auto encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{working_dir}, core::repository::DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME});
   if (!encrypted_env) {
-    encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{configuration_->getHome()}, core::repository::DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME_OLD});
+    encrypted_env = createEncryptingEnv(utils::crypto::EncryptionManager{working_dir}, core::repository::DbEncryptionOptions{directory_, ENCRYPTION_KEY_NAME_OLD});
   }
   logger_->log_info("Using {} RocksDbStateStorage", encrypted_env ? "encrypted" : "plaintext");
 
diff --git a/extensions/rocksdb-repos/tests/ContentSessionTests.cpp b/extensions/rocksdb-repos/tests/ContentSessionTests.cpp
index c1c6fdc3d..03922bbc6 100644
--- a/extensions/rocksdb-repos/tests/ContentSessionTests.cpp
+++ b/extensions/rocksdb-repos/tests/ContentSessionTests.cpp
@@ -37,7 +37,7 @@ class ContentSessionController : public TestController {
       : contentRepository(std::make_shared<ContentRepositoryClass>()) {
     auto contentRepoPath = createTempDirectory();
     auto config = std::make_shared<minifi::ConfigureImpl>();
-    config->setHome(contentRepoPath);
+    config->setLocations(minifi::LocationsImpl::createFromMinifiHome(contentRepoPath));
     config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, contentRepoPath.string());
     contentRepository->initialize(config);
   }
diff --git a/extensions/rocksdb-repos/tests/DBContentRepositoryTests.cpp b/extensions/rocksdb-repos/tests/DBContentRepositoryTests.cpp
index cfc9e4674..3a6b657be 100644
--- a/extensions/rocksdb-repos/tests/DBContentRepositoryTests.cpp
+++ b/extensions/rocksdb-repos/tests/DBContentRepositoryTests.cpp
@@ -44,7 +44,7 @@ TEST_CASE("Write Claim", "[TestDBCR1]") {
   auto content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -67,7 +67,7 @@ TEST_CASE("Write Claim", "[TestDBCR1]") {
   content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -92,7 +92,7 @@ TEST_CASE("Delete Claim", "[TestDBCR2]") {
   auto content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -112,7 +112,7 @@ TEST_CASE("Delete Claim", "[TestDBCR2]") {
   content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
 
   std::string readstr;
@@ -151,7 +151,7 @@ TEST_CASE("Append Claim", "[TestDBCR1]") {
   auto content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -193,7 +193,7 @@ TEST_CASE("Test Empty Claim", "[TestDBCR3]") {
   auto content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -212,7 +212,7 @@ TEST_CASE("Test Empty Claim", "[TestDBCR3]") {
   content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -230,7 +230,7 @@ TEST_CASE("Delete NonExistent Claim", "[TestDBCR4]") {
   auto content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -250,7 +250,7 @@ TEST_CASE("Delete NonExistent Claim", "[TestDBCR4]") {
   content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -272,7 +272,7 @@ TEST_CASE("Delete Remove Count Claim", "[TestDBCR5]") {
   auto content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -292,7 +292,7 @@ TEST_CASE("Delete Remove Count Claim", "[TestDBCR5]") {
   content_repo = std::make_shared<TestDatabaseContentRepository>();
 
   configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   REQUIRE(content_repo->initialize(configuration));
 
@@ -345,7 +345,7 @@ TEST_CASE("DBContentRepository can clear orphan entries") {
   TestController testController;
   auto dir = testController.createTempDirectory();
   auto configuration = std::make_shared<org::apache::nifi::minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, dir.string());
   {
     auto content_repo = std::make_shared<core::repository::DatabaseContentRepository>();
diff --git a/extensions/rocksdb-repos/tests/EncryptionTests.cpp b/extensions/rocksdb-repos/tests/EncryptionTests.cpp
index cf49528e7..7bb21b60d 100644
--- a/extensions/rocksdb-repos/tests/EncryptionTests.cpp
+++ b/extensions/rocksdb-repos/tests/EncryptionTests.cpp
@@ -35,7 +35,7 @@ class FFRepoFixture : public TestController {
     home_ = createTempDirectory();
     repo_dir_ = home_ / "flowfile_repo";
     config_ = std::make_shared<minifi::ConfigureImpl>();
-    config_->setHome(home_);
+    config_->setLocations(minifi::LocationsImpl::createFromMinifiHome(home_));
     container_ = std::make_unique<minifi::ConnectionImpl>(nullptr, nullptr, "container");
     content_repo_ = std::make_shared<core::repository::VolatileContentRepository>();
     content_repo_->initialize(config_);
diff --git a/extensions/rocksdb-repos/tests/RepoTests.cpp b/extensions/rocksdb-repos/tests/RepoTests.cpp
index e153cc140..1d6d5c931 100644
--- a/extensions/rocksdb-repos/tests/RepoTests.cpp
+++ b/extensions/rocksdb-repos/tests/RepoTests.cpp
@@ -76,7 +76,7 @@ TEST_CASE("Test Repo Empty Value Attribute", "[TestFFR1]") {
   const auto repository = std::make_shared<core::repository::FlowFileRepository>("ff", dir.string(), 0ms, 0, 1ms);
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   std::shared_ptr<core::ContentRepository> content_repo = std::make_shared<core::repository::VolatileContentRepository>();
@@ -98,7 +98,7 @@ TEST_CASE("Test Repo Empty Key Attribute ", "[TestFFR2]") {
   const auto repository = std::make_shared<core::repository::FlowFileRepository>("ff", dir.string(), 0ms, 0, 1ms);
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
   std::shared_ptr<core::ContentRepository> content_repo = std::make_shared<core::repository::VolatileContentRepository>();
   const auto file = std::make_shared<minifi::FlowFileRecordImpl>();
@@ -121,7 +121,7 @@ TEST_CASE("Test Repo Key Attribute Verify ", "[TestFFR3]") {
   const auto repository = std::make_shared<core::repository::FlowFileRepository>("ff", dir.string(), 0ms, 0, 1ms);
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   std::shared_ptr<core::ContentRepository> content_repo = std::make_shared<core::repository::VolatileContentRepository>();
@@ -178,7 +178,7 @@ TEST_CASE("Test Delete Content ", "[TestFFR4]") {
   std::shared_ptr<core::ContentRepository> content_repo = std::make_shared<core::repository::FileSystemRepository>();
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   repository->loadComponent(content_repo);
@@ -229,7 +229,7 @@ TEST_CASE("Test Validate Checkpoint ", "[TestFFR5]") {
   std::shared_ptr<core::ContentRepository> content_repo = std::make_shared<core::repository::FileSystemRepository>();
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   repository->loadComponent(content_repo);
@@ -281,7 +281,7 @@ TEST_CASE("Test FlowFile Restore", "[TestFFR6]") {
   auto dir = testController.createTempDirectory();
 
   auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, (dir / "content_repository").string());
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, (dir / "flowfile_repository").string());
 
@@ -382,7 +382,7 @@ TEST_CASE("Flush deleted flowfiles before shutdown", "[TestFFR7]") {
   const auto dir = testController.createTempDirectory();
 
   const auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, (dir / "flowfile_repository").string());
 
   const auto content_repo = std::make_shared<core::repository::VolatileContentRepository>();
@@ -460,7 +460,7 @@ TEST_CASE("FlowFileRepository triggers content repo orphan clear") {
   auto content_dir = testController.createTempDirectory();
 
   auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(home_dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(home_dir));
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, ff_dir.string());
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, content_dir.string());
 
@@ -495,7 +495,7 @@ TEST_CASE("FlowFileRepository synchronously pushes existing flow files") {
   const auto content_dir = testController.createTempDirectory();
 
   const auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(home_dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(home_dir));
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, ff_dir.string());
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, content_dir.string());
 
@@ -577,7 +577,7 @@ TEST_CASE("Test getting flow file repository size properties", "[TestGettingRepo
     expected_max_repo_size = 7;
   }
   auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   auto flow_file = std::make_shared<minifi::FlowFileRecordImpl>();
@@ -626,7 +626,7 @@ TEST_CASE("Test getting noop repository size properties", "[TestGettingRepositor
   const auto repository = minifi::core::createRepository("NoOpRepository", "ff");
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   const auto flow_file = std::make_shared<minifi::FlowFileRecordImpl>();
@@ -654,7 +654,7 @@ TEST_CASE("Test getting content repository size properties", "[TestGettingReposi
 
   const auto content_repo_dir = testController.createTempDirectory();
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, content_repo_dir.string());
   std::string content = "content";
   configuration->set(minifi::Configure::nifi_volatile_repository_options_content_max_bytes, std::to_string(content.size()));
@@ -747,7 +747,7 @@ TEST_CASE("Flow file repositories can be stopped", "[TestRepoIsRunning]") {
   }
 
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   repository->initialize(configuration);
 
   REQUIRE(!repository->isRunning());
@@ -810,7 +810,7 @@ TEST_CASE("FlowFileRepository can filter out too small contents") {
   const auto content_dir = testController.createTempDirectory();
 
   auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(minifi_home);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(minifi_home));
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, ff_dir.string());
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, content_dir.string());
 
diff --git a/extensions/rocksdb-repos/tests/SwapTests.cpp b/extensions/rocksdb-repos/tests/SwapTests.cpp
index 80ee61678..71eda4d6b 100644
--- a/extensions/rocksdb-repos/tests/SwapTests.cpp
+++ b/extensions/rocksdb-repos/tests/SwapTests.cpp
@@ -84,7 +84,7 @@ TEST_CASE("Connection will on-demand swap flow files") {
   auto dir = testController.createTempDirectory();
 
   auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, (dir / "content_repository").string());
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, (dir / "flowfile_repository").string());
 
diff --git a/extensions/sftp/tests/ListSFTPTests.cpp b/extensions/sftp/tests/ListSFTPTests.cpp
index 1d2bd3e9b..01f65fc29 100644
--- a/extensions/sftp/tests/ListSFTPTests.cpp
+++ b/extensions/sftp/tests/ListSFTPTests.cpp
@@ -75,7 +75,7 @@ class ListSFTPTestsFixture {
     REQUIRE(true == sftp_server->start());
 
     if (configuration) {
-      configuration->setHome(working_directory);
+      configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(working_directory));
     }
     // Build MiNiFi processing graph
     createPlan(nullptr, configuration);
@@ -96,7 +96,7 @@ class ListSFTPTestsFixture {
     plan.reset();
 
     if (configuration) {
-      configuration->setHome(working_directory);
+      configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(working_directory));
     }
     plan = testController.createPlan(configuration, state_dir);
     if (list_sftp_uuid == nullptr) {
diff --git a/extensions/standard-processors/tests/unit/TailFileTests.cpp b/extensions/standard-processors/tests/unit/TailFileTests.cpp
index 843b553e6..9cc7e9b19 100644
--- a/extensions/standard-processors/tests/unit/TailFileTests.cpp
+++ b/extensions/standard-processors/tests/unit/TailFileTests.cpp
@@ -1056,7 +1056,7 @@ TEST_CASE("TailFile finds and finishes the renamed file and continues with the n
 
   // use persistent state storage that defaults to rocksDB, not volatile
   const auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(log_dir);
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(log_dir));
   {
     auto test_plan = testController.createPlan(configuration, state_dir);
     auto tail_file = test_plan->addProcessor("TailFile", tail_file_uuid, "Tail", {success_relationship});
diff --git a/fips/openssl.cnf b/fips/openssl.cnf
index 8cc2731b3..8779438cb 100644
--- a/fips/openssl.cnf
+++ b/fips/openssl.cnf
@@ -1,6 +1,6 @@
 openssl_conf = openssl_init
 
-.include ${MINIFI_HOME}/fips/fipsmodule.cnf
+.include ${FIPS_CONF_DIR}/fipsmodule.cnf
 
 [openssl_init]
 providers = prov
diff --git a/libminifi/CMakeLists.txt b/libminifi/CMakeLists.txt
index 116a41a0c..9408b421f 100644
--- a/libminifi/CMakeLists.txt
+++ b/libminifi/CMakeLists.txt
@@ -105,5 +105,13 @@ if (WIN32)
     install(TARGETS core-minifi ARCHIVE DESTINATION bin COMPONENT bin)
     install(TARGETS core-minifi RUNTIME DESTINATION bin COMPONENT bin)
 else()
-    install(TARGETS core-minifi LIBRARY DESTINATION bin COMPONENT bin)
-endif()
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        install(TARGETS core-minifi
+                LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/nifi-minifi-cpp
+                COMPONENT bin)
+    elseif (MINIFI_PACKAGING_TYPE STREQUAL "TGZ")
+        install(TARGETS core-minifi LIBRARY DESTINATION bin COMPONENT bin)
+    else()
+        message(FATAL_ERROR "Invalid MINIFI_PACKAGING_TYPE")
+    endif()
+endif()
\ No newline at end of file
diff --git a/libminifi/include/core/logging/LoggerProperties.h b/libminifi/include/core/logging/LoggerProperties.h
index 0ac483561..90098d447 100644
--- a/libminifi/include/core/logging/LoggerProperties.h
+++ b/libminifi/include/core/logging/LoggerProperties.h
@@ -31,8 +31,9 @@ namespace org::apache::nifi::minifi::core::logging {
 
 class LoggerProperties : public PropertiesImpl {
  public:
-  LoggerProperties()
-      : PropertiesImpl("Logger properties") {
+  explicit LoggerProperties(std::filesystem::path default_log_dir)
+      : PropertiesImpl("Logger properties"),
+        default_log_dir_(std::move(default_log_dir)) {
   }
   /**
    * Gets all keys that start with the given prefix and do not have a "." after the prefix and "." separator.
@@ -52,7 +53,10 @@ class LoggerProperties : public PropertiesImpl {
     return sinks_;
   }
 
+  std::filesystem::path getDefaultLogDir() const { return default_log_dir_; }
+
  private:
+  std::filesystem::path default_log_dir_;
   std::map<std::string, std::shared_ptr<spdlog::sinks::sink>> sinks_;
 };
 
diff --git a/libminifi/include/properties/Configure.h b/libminifi/include/properties/Configure.h
index d869ad7da..249fc53b2 100644
--- a/libminifi/include/properties/Configure.h
+++ b/libminifi/include/properties/Configure.h
@@ -16,16 +16,17 @@
  */
 #pragma once
 
+#include <memory>
 #include <optional>
 #include <string>
 #include <utility>
-#include <memory>
 
-#include "properties/Configuration.h"
-#include "properties/Decryptor.h"
-#include "minifi-cpp/core/AgentIdentificationProvider.h"
+#include "LocationsImpl.h"
 #include "core/logging/LoggerProperties.h"
+#include "minifi-cpp/core/AgentIdentificationProvider.h"
 #include "minifi-cpp/properties/Configure.h"
+#include "properties/Configuration.h"
+#include "properties/Decryptor.h"
 
 struct ConfigTestAccessor;
 
@@ -53,6 +54,8 @@ class ConfigureImpl : public ConfigurationImpl, public virtual core::AgentIdenti
   void set(const std::string& key, const std::string& value, PropertyChangeLifetime lifetime) override;
   bool commitChanges() override;
 
+  [[nodiscard]] std::shared_ptr<const Locations> getLocations() const override;
+  void setLocations(std::shared_ptr<const Locations> locations) override;
 
  private:
   // WARNING! a test utility
@@ -66,6 +69,7 @@ class ConfigureImpl : public ConfigurationImpl, public virtual core::AgentIdenti
   mutable std::mutex fallback_identifier_mutex_;
   std::string fallback_identifier_;
   std::atomic_bool logger_properties_changed_{false};
+  std::shared_ptr<const Locations> locations_;
   std::shared_ptr<core::logging::LoggerProperties> logger_properties_;
 };
 
diff --git a/libminifi/include/properties/LocationsImpl.h b/libminifi/include/properties/LocationsImpl.h
new file mode 100644
index 000000000..5f602e11f
--- /dev/null
+++ b/libminifi/include/properties/LocationsImpl.h
@@ -0,0 +1,103 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "minifi-cpp/properties/Locations.h"
+#include "Defaults.h"
+#include "fmt/format.h"
+
+namespace org::apache::nifi::minifi {
+class LocationsImpl final : public Locations {
+  struct M {
+    std::filesystem::path working_dir_;
+    std::filesystem::path lock_path_;
+    std::filesystem::path log_properties_path_;
+    std::filesystem::path uid_properties_path_;
+    std::filesystem::path properties_path_;
+    std::filesystem::path logs_dir_;
+    std::filesystem::path fips_bin_path_;
+    std::filesystem::path fips_conf_path_;
+    std::string extensions_pattern_;
+  } m;
+
+  explicit LocationsImpl(M m) : m(std::move(m)) {}
+
+ public:
+  static std::shared_ptr<LocationsImpl> createFromMinifiHome(const std::filesystem::path& minifi_home) {
+    return std::shared_ptr<LocationsImpl>(new LocationsImpl(M{
+      .working_dir_ = minifi_home,
+      .lock_path_ = minifi_home / "LOCK",
+      .log_properties_path_ = minifi_home / DEFAULT_LOG_PROPERTIES_FILE,
+      .uid_properties_path_ = minifi_home / DEFAULT_UID_PROPERTIES_FILE,
+      .properties_path_ = minifi_home / DEFAULT_NIFI_PROPERTIES_FILE,
+      .logs_dir_ = minifi_home / "logs",
+      .fips_bin_path_ = minifi_home / "fips",
+      .fips_conf_path_ = minifi_home / "fips",
+      .extensions_pattern_ = "../extensions/*"
+    }));
+  }
+
+  static std::shared_ptr<LocationsImpl> createForFHS() {
+    return std::shared_ptr<LocationsImpl>(new LocationsImpl(M{
+        .working_dir_ = "/var/lib/nifi-minifi-cpp",
+        .lock_path_ = "/var/lib/nifi-minifi-cpp/LOCK",
+        .log_properties_path_ = "/etc/nifi-minifi-cpp/minifi-log.properties",
+        .uid_properties_path_ = "/etc/nifi-minifi-cpp/minifi-uid.properties",
+        .properties_path_ = "/etc/nifi-minifi-cpp/minifi.properties",
+        .logs_dir_ = "/var/log/nifi-minifi-cpp",
+        .fips_bin_path_ = "/usr/lib64/nifi-minifi-cpp/fips",
+        .fips_conf_path_ = "/etc/nifi-minifi-cpp/fips",
+        .extensions_pattern_ = "/usr/lib64/nifi-minifi-cpp/extensions/*"
+    }));
+  }
+
+  [[nodiscard]] const std::filesystem::path& getWorkingDir() const override { return m.working_dir_; }
+  [[nodiscard]] const std::filesystem::path& getLockPath() const override { return m.lock_path_; }
+  [[nodiscard]] const std::filesystem::path& getLogPropertiesPath() const override { return m.log_properties_path_; }
+  [[nodiscard]] const std::filesystem::path& getUidPropertiesPath() const override { return m.uid_properties_path_; }
+  [[nodiscard]] const std::filesystem::path& getPropertiesPath() const override { return m.properties_path_; }
+  [[nodiscard]] const std::filesystem::path& getFipsBinPath() const override { return m.fips_bin_path_; }
+  [[nodiscard]] const std::filesystem::path& getFipsConfPath() const override { return m.fips_conf_path_; }
+  [[nodiscard]] const std::filesystem::path& getLogsDirs() const override { return m.logs_dir_; }
+  [[nodiscard]] std::string_view getDefaultExtensionsPattern() const override { return m.extensions_pattern_; }
+
+  [[nodiscard]] std::string toString() const override {
+    return fmt::format(
+      R"(
+Locations {{
+  working dir: "{}",
+  lock path: "{}",
+  log properties path: "{}",
+  uid properties path: "{}",
+  properties path: "{}",
+  fips bin path: "{}",
+  fips conf path: "{}",
+  logs dir: "{}",
+  extensions pattern: "{}"
+}})",
+      getWorkingDir().string(),
+      getLockPath().string(),
+      getLogPropertiesPath().string(),
+      getUidPropertiesPath().string(),
+      getPropertiesPath().string(),
+      getFipsBinPath().string(),
+      getFipsConfPath().string(),
+      getLogsDirs().string(),
+      getDefaultExtensionsPattern());
+  }
+};
+}  // namespace org::apache::nifi::minifi
diff --git a/libminifi/include/properties/Properties.h b/libminifi/include/properties/Properties.h
index 2cab983ae..5586f827c 100644
--- a/libminifi/include/properties/Properties.h
+++ b/libminifi/include/properties/Properties.h
@@ -102,16 +102,8 @@ class PropertiesImpl : public virtual Properties {
    */
   std::optional<std::string> getString(const std::string& key) const override;
 
-  /**
-   * Load configure file
-   * @param fileName path of the configuration file RELATIVE to MINIFI_HOME set by setHome()
-   */
   void loadConfigureFile(const std::filesystem::path& configuration_file, std::string_view prefix = "") override;
 
-  // Set the determined MINIFI_HOME
-  void setHome(std::filesystem::path minifiHome) override {
-    minifi_home_ = std::move(minifiHome);
-  }
 
   std::vector<std::string> getConfiguredKeys() const override {
     std::vector<std::string> keys;
@@ -121,11 +113,6 @@ class PropertiesImpl : public virtual Properties {
     return keys;
   }
 
-  // Get the determined MINIFI_HOME
-  std::filesystem::path getHome() const override {
-    return minifi_home_;
-  }
-
   bool commitChanges() override;
 
   utils::ChecksumCalculator& getChecksumCalculator() override { return checksum_calculator_; }
@@ -146,8 +133,6 @@ class PropertiesImpl : public virtual Properties {
   // Mutex for protection
   mutable std::mutex mutex_;
   std::shared_ptr<core::logging::Logger> logger_;
-  // Home location for this executable
-  std::filesystem::path minifi_home_;
 
   std::string name_;
 };
diff --git a/libminifi/src/Configure.cpp b/libminifi/src/Configure.cpp
index 3e895735e..922a59e22 100644
--- a/libminifi/src/Configure.cpp
+++ b/libminifi/src/Configure.cpp
@@ -135,6 +135,15 @@ bool ConfigureImpl::commitChanges() {
   return success;
 }
 
+std::shared_ptr<const Locations> ConfigureImpl::getLocations() const {
+  return locations_;
+}
+
+void ConfigureImpl::setLocations(std::shared_ptr<const Locations> locations) {
+  locations_ = std::move(locations);
+}
+
+
 gsl::not_null<std::shared_ptr<Configure>> Configure::create() {
   return gsl::make_not_null<std::shared_ptr<Configure>>(std::make_shared<ConfigureImpl>());
 }
diff --git a/libminifi/src/core/extension/ExtensionManager.cpp b/libminifi/src/core/extension/ExtensionManager.cpp
index ea22de781..05e2f73ab 100644
--- a/libminifi/src/core/extension/ExtensionManager.cpp
+++ b/libminifi/src/core/extension/ExtensionManager.cpp
@@ -49,7 +49,7 @@ ExtensionManager& ExtensionManager::get() {
   return ExtensionManagerImpl::get();
 }
 
-constexpr const char* DEFAULT_EXTENSION_PATH = "../extensions/*";
+constexpr std::string_view DEFAULT_EXTENSION_PATH = "../extensions/*";
 
 bool ExtensionManagerImpl::initialize(const std::shared_ptr<Configure>& config) {
   static bool initialized = ([&] {
@@ -60,17 +60,24 @@ bool ExtensionManagerImpl::initialize(const std::shared_ptr<Configure>& config)
       logger_->log_error("Missing configuration");
       return;
     }
-    std::string pattern = [&] {
+    const std::string pattern = [&] {
       /**
        * Comma separated list of path patterns. Patterns prepended with "!" result in the exclusion
        * of the extensions matching that pattern, unless some subsequent pattern re-enables it.
        */
-      auto opt_pattern = config->get(minifi::Configuration::nifi_extension_path);
-      if (!opt_pattern) {
-        logger_->log_warn("No extension path is provided, using default: '{}'", DEFAULT_EXTENSION_PATH);
-      }
-      return opt_pattern.value_or(DEFAULT_EXTENSION_PATH);
+      if (const auto opt_pattern = config->get(minifi::Configuration::nifi_extension_path)) {
+        return *opt_pattern;
+      };
+
+      if (const auto locations = config->getLocations()) {
+        logger_->log_warn("No extension path is provided in properties, using default : '{}'", locations->getDefaultExtensionsPattern());
+        return std::string(locations->getDefaultExtensionsPattern());
+      };
+
+      logger_->log_error("No extension path is provided in properties and locations is empty, using hard-coded default: '{}'", DEFAULT_EXTENSION_PATH);
+      return std::string(DEFAULT_EXTENSION_PATH);
     }();
+
     auto candidates = utils::file::match(utils::file::FilePattern(pattern, [&] (std::string_view subpattern, std::string_view error_msg) {
       logger_->log_error("Error in subpattern '{}': {}", subpattern, error_msg);
     }));
diff --git a/libminifi/src/core/logging/LoggerConfiguration.cpp b/libminifi/src/core/logging/LoggerConfiguration.cpp
index a5f338e44..3d2fb3a61 100644
--- a/libminifi/src/core/logging/LoggerConfiguration.cpp
+++ b/libminifi/src/core/logging/LoggerConfiguration.cpp
@@ -367,7 +367,7 @@ std::shared_ptr<spdlog::sinks::rotating_file_sink_mt> LoggerConfiguration::getRo
   if (!properties->getString(appender_key + ".directory", directory_str)) {
     // The below part assumes logger_properties->getHome() is existing
     // Cause minifiHome must be set at MiNiFiMain.cpp?
-    directory_str = (properties->getHome() / "logs").string();
+    directory_str = properties->getDefaultLogDir().string();
   }
 
   auto file_name = std::filesystem::path(directory_str) / file_name_str;
diff --git a/libminifi/src/core/repository/FileSystemRepository.cpp b/libminifi/src/core/repository/FileSystemRepository.cpp
index dc2d0ae50..ad4b28c6e 100644
--- a/libminifi/src/core/repository/FileSystemRepository.cpp
+++ b/libminifi/src/core/repository/FileSystemRepository.cpp
@@ -29,7 +29,7 @@ bool FileSystemRepository::initialize(const std::shared_ptr<Configure>& configur
   if (std::string directory_str; configuration->get(Configure::nifi_dbcontent_repository_directory_default, directory_str) && !directory_str.empty()) {
     directory_ = directory_str;
   } else {
-    directory_ = configuration->getHome().string();
+    directory_ = std::filesystem::current_path().string();
   }
   utils::file::create_dir(directory_);
   return true;
diff --git a/libminifi/src/properties/Properties.cpp b/libminifi/src/properties/Properties.cpp
index 521ad9af1..b60e1499d 100644
--- a/libminifi/src/properties/Properties.cpp
+++ b/libminifi/src/properties/Properties.cpp
@@ -166,14 +166,14 @@ void PropertiesImpl::loadConfigureFile(const std::filesystem::path& configuratio
     return;
   }
 
-  if (!utils::file::exists(getHome() / configuration_file)) {
-    if (utils::file::create_dir((getHome() / configuration_file).parent_path()) == 0) {
-      std::ofstream file{getHome() / configuration_file};
+  if (!utils::file::exists(configuration_file)) {
+    if (utils::file::create_dir(configuration_file.parent_path()) == 0) {
+      std::ofstream file{configuration_file};
     }
   }
 
   std::error_code ec;
-  properties_file_ = std::filesystem::canonical(getHome() / configuration_file, ec);
+  properties_file_ = std::filesystem::canonical(configuration_file, ec);
 
   if (ec.value() != 0) {
     logger_->log_warn("Configuration file '{}' does not exist, and it could not be created", configuration_file);
diff --git a/libminifi/src/utils/file/AssetManager.cpp b/libminifi/src/utils/file/AssetManager.cpp
index 73f052de6..039078135 100644
--- a/libminifi/src/utils/file/AssetManager.cpp
+++ b/libminifi/src/utils/file/AssetManager.cpp
@@ -26,8 +26,18 @@
 
 namespace org::apache::nifi::minifi::utils::file {
 
+std::filesystem::path getRootFromConfigure(const Configure& configuration) {
+  if (auto nifi_asset_directory = configuration.get(Configure::nifi_asset_directory)) {
+    return *nifi_asset_directory;
+  }
+  if (const auto locations = configuration.getLocations()) {
+    return locations->getWorkingDir() / "asset";
+  }
+  return std::filesystem::path("") / "asset";
+}
+
 AssetManager::AssetManager(const Configure& configuration)
-    : root_(configuration.get(Configure::nifi_asset_directory).value_or((configuration.getHome() / "asset").string())),
+    : root_(getRootFromConfigure(configuration)),
       logger_(core::logging::LoggerFactory<AssetManager>::getLogger()) {
   refreshState();
 }
diff --git a/libminifi/test/integration/AlertTests.cpp b/libminifi/test/integration/AlertTests.cpp
index 57eb3b49d..8530053b4 100644
--- a/libminifi/test/integration/AlertTests.cpp
+++ b/libminifi/test/integration/AlertTests.cpp
@@ -80,9 +80,9 @@ TEST_CASE("Alert system forwards logs") {
   AlertHandler handler(agent_id);
   harness.setUrl("http://localhost:0/api/alerts", &handler);
   harness.getConfiguration()->set(minifi::Configuration::nifi_c2_agent_identifier, agent_id);
-  harness.getConfiguration()->setHome(dir.getPath());
+  harness.getConfiguration()->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir.getPath()));
 
-  auto log_props = std::make_shared<logging::LoggerProperties>();
+  auto log_props = std::make_shared<logging::LoggerProperties>(dir.getPath() / "logs");
   log_props->set("appender.alert1", "alert");
   log_props->set("appender.alert1.url", harness.getC2RestUrl());
   log_props->set("appender.alert1.filter", ".*<begin>(.*)<end>.*");
diff --git a/libminifi/test/integration/C2DebugBundleTest.cpp b/libminifi/test/integration/C2DebugBundleTest.cpp
index a6d0482d6..ab742d6d0 100644
--- a/libminifi/test/integration/C2DebugBundleTest.cpp
+++ b/libminifi/test/integration/C2DebugBundleTest.cpp
@@ -189,8 +189,8 @@ TEST_CASE("C2DebugBundleTest", "[c2test]") {
     return true;
   });
 
-  harness.getConfiguration()->setHome(home_dir.string());
-  harness.getConfiguration()->loadConfigureFile("conf/minifi.properties");
+  harness.getConfiguration()->setLocations(minifi::LocationsImpl::createFromMinifiHome(home_dir.string()));
+  harness.getConfiguration()->loadConfigureFile(home_dir / "conf/minifi.properties");
   harness.setUrl("http://localhost:0/heartbeat", &heartbeat_handler);
   harness.setUrl("http://localhost:0/acknowledge", &ack_handler);
   harness.setUrl("http://localhost:0/debug_bundle", &bundle_handler);
diff --git a/libminifi/test/integration/C2DescribeManifestTest.cpp b/libminifi/test/integration/C2DescribeManifestTest.cpp
index f14a30fe3..14a02ab6d 100644
--- a/libminifi/test/integration/C2DescribeManifestTest.cpp
+++ b/libminifi/test/integration/C2DescribeManifestTest.cpp
@@ -59,7 +59,7 @@ TEST_CASE("C2DescribeManifestTest", "[c2test]") {
   harness.setKeyDir(TEST_RESOURCES);
   DescribeManifestHandler responder(harness.getConfiguration(), verified);
 
-  auto logger_properties = std::make_shared<core::logging::LoggerProperties>();
+  auto logger_properties = std::make_shared<core::logging::LoggerProperties>("");
   ConfigTestAccessor::call_setLoggerProperties(harness.getConfiguration(), logger_properties);
 
   harness.getConfiguration()->set(minifi::Configuration::nifi_rest_api_password, encrypted_value);
diff --git a/libminifi/test/integration/C2PropertiesUpdateTests.cpp b/libminifi/test/integration/C2PropertiesUpdateTests.cpp
index 6d0b80b31..6e7076f57 100644
--- a/libminifi/test/integration/C2PropertiesUpdateTests.cpp
+++ b/libminifi/test/integration/C2PropertiesUpdateTests.cpp
@@ -136,12 +136,11 @@ TEST_CASE("C2PropertiesUpdateTests", "[c2test]") {
   C2HeartbeatHandler hb_handler{};
   C2AcknowledgeHandler ack_handler{};
 
-  auto logger_properties = std::make_shared<core::logging::LoggerProperties>();
+  auto logger_properties = std::make_shared<core::logging::LoggerProperties>(home_dir / "logs");
   // this sets the ostream logger
   auto log_test_controller = LogTestController::getInstance(logger_properties);
 
-  logger_properties->setHome(home_dir);
-  logger_properties->loadConfigureFile("conf/minifi-log.properties");
+  logger_properties->loadConfigureFile(home_dir / "conf/minifi-log.properties");
   core::logging::LoggerConfiguration::getConfiguration().initialize(logger_properties);
 
   auto logger1 = core::logging::LoggerFactory<DummyClass1>::getLogger();
@@ -213,8 +212,8 @@ TEST_CASE("C2PropertiesUpdateTests", "[c2test]") {
     }
   });
 
-  harness.getConfiguration()->setHome(home_dir.string());
-  harness.getConfiguration()->loadConfigureFile("conf/minifi.properties");
+  harness.getConfiguration()->setLocations(minifi::LocationsImpl::createFromMinifiHome(home_dir.string()));
+  harness.getConfiguration()->loadConfigureFile(home_dir / "conf/minifi.properties");
   ConfigTestAccessor::call_setLoggerProperties(harness.getConfiguration(), logger_properties);
 
   harness.setUrl("http://localhost:0/heartbeat", &hb_handler);
diff --git a/libminifi/test/libtest/unit/TestBase.cpp b/libminifi/test/libtest/unit/TestBase.cpp
index bec3fc9c0..15527c79e 100644
--- a/libminifi/test/libtest/unit/TestBase.cpp
+++ b/libminifi/test/libtest/unit/TestBase.cpp
@@ -155,7 +155,7 @@ void LogTestController::reset() {
   modified_loggers.clear();
   if (config)
     config = logging::LoggerConfiguration::newInstance();
-  my_properties_ = std::make_shared<logging::LoggerProperties>();
+  my_properties_ = std::make_shared<logging::LoggerProperties>("");
   clear();
   init(nullptr);
 }
@@ -176,7 +176,7 @@ void LogTestController::init(const std::shared_ptr<logging::LoggerProperties>& l
   my_properties_ = logger_props;
   bool initMain = false;
   if (nullptr == my_properties_) {
-    my_properties_ = std::make_shared<logging::LoggerProperties>();
+    my_properties_ = std::make_shared<logging::LoggerProperties>("");
     initMain = true;
   }
   my_properties_->set("logger.root", "ERROR,ostream");
@@ -717,7 +717,7 @@ TestController::TestController()
 std::shared_ptr<TestPlan> TestController::createPlan(PlanConfig config) {
   if (!config.configuration) {
     config.configuration = minifi::Configure::create();
-    config.configuration->setHome(createTempDirectory());
+    config.configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(createTempDirectory()));
     config.configuration->set(minifi::Configure::nifi_state_storage_local_class_name, "VolatileMapStateStorage");
     config.configuration->set(minifi::Configure::nifi_dbcontent_repository_directory_default, createTempDirectory().string());
   }
diff --git a/libminifi/test/libtest/unit/TestControllerWithFlow.cpp b/libminifi/test/libtest/unit/TestControllerWithFlow.cpp
index e475e08ab..5b090b844 100644
--- a/libminifi/test/libtest/unit/TestControllerWithFlow.cpp
+++ b/libminifi/test/libtest/unit/TestControllerWithFlow.cpp
@@ -41,7 +41,6 @@ TestControllerWithFlow::TestControllerWithFlow(const char* yamlConfigContent, bo
   std::ofstream{yaml_path_} << yamlConfigContent;
 
   configuration_ = minifi::Configure::create();
-  configuration_->setHome(home_.string());
   configuration_->set(minifi::Configure::nifi_flow_configuration_file, yaml_path_.string());
   configuration_->set(minifi::Configure::nifi_c2_enable, "true");
 
diff --git a/libminifi/test/persistence-tests/PersistenceTests.cpp b/libminifi/test/persistence-tests/PersistenceTests.cpp
index 40d9ef3bf..c96f888ca 100644
--- a/libminifi/test/persistence-tests/PersistenceTests.cpp
+++ b/libminifi/test/persistence-tests/PersistenceTests.cpp
@@ -172,7 +172,7 @@ TEST_CASE("Processors Can Store FlowFiles", "[TestP1]") {
   auto dir = testController.createTempDirectory();
 
   auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, (dir / "content_repository").string());
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, (dir / "flowfile_repository").string());
 
@@ -286,7 +286,7 @@ TEST_CASE("Persisted flowFiles are updated on modification", "[TestP1]") {
   auto dir = testController.createTempDirectory();
 
   auto config = std::make_shared<minifi::ConfigureImpl>();
-  config->setHome(dir);
+  config->setLocations(minifi::LocationsImpl::createFromMinifiHome(dir));
   config->set(minifi::Configure::nifi_dbcontent_repository_directory_default, (dir / "content_repository").string());
   config->set(minifi::Configure::nifi_flowfile_repository_directory_default, (dir / "flowfile_repository").string());
   config->set(minifi::Configure::nifi_dbcontent_repository_purge_period, "0 s");
diff --git a/libminifi/test/unit/DecryptorTests.cpp b/libminifi/test/unit/DecryptorTests.cpp
index a026dc8dc..dc1531e28 100644
--- a/libminifi/test/unit/DecryptorTests.cpp
+++ b/libminifi/test/unit/DecryptorTests.cpp
@@ -90,8 +90,8 @@ TEST_CASE("Decryptor can decrypt a configuration file", "[decryptSensitiveProper
 
   minifi::ConfigureImpl configuration{decryptor};
   std::filesystem::path resources_dir{TEST_RESOURCES};
-  configuration.setHome(resources_dir);
-  configuration.loadConfigureFile("encrypted.minifi.properties");
+  configuration.setLocations(minifi::LocationsImpl::createFromMinifiHome(resources_dir));
+  configuration.loadConfigureFile(resources_dir / "encrypted.minifi.properties");
   REQUIRE_FALSE(configuration.getConfiguredKeys().empty());
 
   const auto passphrase = configuration.get(minifi::Configure::nifi_security_client_pass_phrase);
diff --git a/libminifi/test/unit/LogMetricsPublisherTests.cpp b/libminifi/test/unit/LogMetricsPublisherTests.cpp
index d48897fa5..557595ac8 100644
--- a/libminifi/test/unit/LogMetricsPublisherTests.cpp
+++ b/libminifi/test/unit/LogMetricsPublisherTests.cpp
@@ -39,7 +39,7 @@ class LogPublisherTestFixture {
       response_node_loader_(std::make_shared<state::response::ResponseNodeLoaderImpl>(configuration_,
         std::vector<std::shared_ptr<core::RepositoryMetricsSource>>{provenance_repo_, flow_file_repo_}, nullptr)),
       publisher_("LogMetricsPublisher") {
-    configuration_->setHome(temp_directory_.getPath());
+    configuration_->setLocations(minifi::LocationsImpl::createFromMinifiHome(temp_directory_.getPath()));
     provenance_repo_->initialize(configuration_);
     flow_file_repo_->initialize(configuration_);
   }
diff --git a/libminifi/test/unit/LoggerConfigurationTests.cpp b/libminifi/test/unit/LoggerConfigurationTests.cpp
index 6583c52a1..e1589bb9d 100644
--- a/libminifi/test/unit/LoggerConfigurationTests.cpp
+++ b/libminifi/test/unit/LoggerConfigurationTests.cpp
@@ -33,7 +33,7 @@
 TEST_CASE("TestLoggerProperties::get_keys_of_type", "[test get_keys_of_type]") {
   TestController test_controller;
   LogTestController::getInstance().setDebug<logging::LoggerProperties>();
-  logging::LoggerProperties logger_properties;
+  logging::LoggerProperties logger_properties{""};
   logger_properties.set("appender.rolling", "rolling");
   logger_properties.set("notappender.notrolling", "notrolling");
   logger_properties.set("appender.stdout", "stdout");
diff --git a/libminifi/test/unit/LoggerTests.cpp b/libminifi/test/unit/LoggerTests.cpp
index 64071818b..f81651bd7 100644
--- a/libminifi/test/unit/LoggerTests.cpp
+++ b/libminifi/test/unit/LoggerTests.cpp
@@ -99,7 +99,7 @@ TEST_CASE("Logger configured with an ID prints this ID in every log line", "[log
 }
 
 TEST_CASE("Printing of the ID can be disabled in the config", "[logger][id][configuration]") {
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
 
   bool id_is_present{};
   SECTION("Property not set") {
@@ -172,7 +172,7 @@ class TestClass2 {
 
 TEST_CASE("Test ShortenNames", "[ttl8]") {
   LogTestController::getInstance().clear();
-  std::shared_ptr<logging::LoggerProperties> props = std::make_shared<logging::LoggerProperties>();
+  std::shared_ptr<logging::LoggerProperties> props = std::make_shared<logging::LoggerProperties>("");
 
   props->set("spdlog.shorten_names", "true");
 
@@ -229,7 +229,7 @@ class LoggerTestAccessor {
 
 TEST_CASE("Test Compression", "[ttl9]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   std::string className;
   SECTION("Using root logger") {
     className = "CompressionTestClassUsingRoot";
@@ -254,7 +254,7 @@ TEST_CASE("Test Compression", "[ttl9]") {
 
 TEST_CASE("Test Compression cache overflow is discarded intermittently", "[ttl10]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   properties->set(logging::internal::CompressionManager::compression_cached_log_max_size_, "10 KB");
   LoggerTestAccessor::setCompressionCacheSegmentSize(*log_config, 1_KiB);
   std::string className = "CompressionTestCacheCleaned";
@@ -273,7 +273,7 @@ TEST_CASE("Test Compression cache overflow is discarded intermittently", "[ttl10
 
 TEST_CASE("Setting either properties to 0 disables in-memory compressed logs", "[ttl11]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   bool is_empty = false;
   SECTION("Cached log size is set to 0") {
     is_empty = true;
@@ -300,7 +300,7 @@ TEST_CASE("Setting either properties to 0 disables in-memory compressed logs", "
 
 TEST_CASE("Setting max log entry length property trims long log entries", "[ttl12]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   properties->set("max.log.entry.length", "2");
   properties->set("logger.root", "INFO");
   log_config->initialize(properties);
@@ -317,7 +317,7 @@ TEST_CASE("Setting max log entry length property trims long log entries", "[ttl1
 
 TEST_CASE("Setting max log entry length property trims long formatted log entries", "[ttl13]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   properties->set("max.log.entry.length", "2");
   properties->set("logger.root", "INFO");
   log_config->initialize(properties);
@@ -334,7 +334,7 @@ TEST_CASE("Setting max log entry length property trims long formatted log entrie
 
 TEST_CASE("Setting max log entry length to a size larger than the internal buffer size", "[ttl14]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   properties->set("max.log.entry.length", "1500");
   properties->set("logger.root", "INFO");
   log_config->initialize(properties);
@@ -353,7 +353,7 @@ TEST_CASE("Setting max log entry length to a size larger than the internal buffe
 
 TEST_CASE("Setting max log entry length to unlimited results in unlimited log entry size", "[ttl15]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   std::string_view logger_name;
   SECTION("Use unlimited value") {
     properties->set("max.log.entry.length", "unlimited");
@@ -419,7 +419,7 @@ TEST_CASE("Test sending multiple segments at once", "[ttl16]") {
   auto log_config = logging::LoggerConfiguration::newInstance();
   LoggerTestAccessor::setCompressionCompressedSegmentSize(*log_config, 100);
   LoggerTestAccessor::setCompressionCacheSegmentSize(*log_config, 100);
-  auto properties = std::make_shared<logging::LoggerProperties>();
+  auto properties = std::make_shared<logging::LoggerProperties>("");
   // by default the root logger is OFF
   properties->set("logger.root", "INFO");
   log_config->initialize(properties);
diff --git a/libminifi/test/unit/ProcessSessionTests.cpp b/libminifi/test/unit/ProcessSessionTests.cpp
index 6761e5c19..212630677 100644
--- a/libminifi/test/unit/ProcessSessionTests.cpp
+++ b/libminifi/test/unit/ProcessSessionTests.cpp
@@ -146,7 +146,7 @@ class TestVolatileFlowFileRepository : public core::repository::VolatileFlowFile
 TEST_CASE("ProcessSession::commit avoids dangling ResourceClaims when using VolatileFlowFileRepository", "[incrementbefore]") {
   TempDirectory tmp_dir;
   auto configuration = std::make_shared<minifi::ConfigureImpl>();
-  configuration->setHome(tmp_dir.getPath());
+  configuration->setLocations(minifi::LocationsImpl::createFromMinifiHome(tmp_dir.getPath()));
   configuration->set(minifi::Configure::nifi_volatile_repository_options_flowfile_max_count, "2");
   auto ff_repo = std::make_shared<TestVolatileFlowFileRepository>("flowfile");
   Fixture fixture({
diff --git a/libminifi/test/unit/performance/VolatileRepositoryPerfTests.cpp b/libminifi/test/unit/performance/VolatileRepositoryPerfTests.cpp
index 44a65056d..2b25c281d 100644
--- a/libminifi/test/unit/performance/VolatileRepositoryPerfTests.cpp
+++ b/libminifi/test/unit/performance/VolatileRepositoryPerfTests.cpp
@@ -27,7 +27,7 @@
 // NOLINTBEGIN
 
 static bool initializeLogger = [] {
-  auto log_props = std::make_shared<org::apache::nifi::minifi::core::logging::LoggerProperties>();
+  auto log_props = std::make_shared<org::apache::nifi::minifi::core::logging::LoggerProperties>("");
   log_props->set("logger.root", "OFF");
   org::apache::nifi::minifi::core::logging::LoggerConfiguration::getConfiguration().initialize(log_props);
   return true;
diff --git a/minifi-api/include/minifi-cpp/core/ProcessContext.h b/minifi-api/include/minifi-cpp/core/ProcessContext.h
index 50f1518f1..b2252dc1a 100644
--- a/minifi-api/include/minifi-cpp/core/ProcessContext.h
+++ b/minifi-api/include/minifi-cpp/core/ProcessContext.h
@@ -59,8 +59,6 @@ class ProcessContext : public virtual core::VariableRegistry, public virtual uti
   virtual std::shared_ptr<core::Repository> getProvenanceRepository() = 0;
   virtual std::shared_ptr<core::ContentRepository> getContentRepository() const = 0;
   virtual std::shared_ptr<core::Repository> getFlowFileRepository() const = 0;
-  virtual void initializeContentRepository(const std::string& home) = 0;
-  virtual bool isInitialized() const = 0;
 
   virtual std::shared_ptr<core::controller::ControllerService> getControllerService(const std::string &identifier, const utils::Identifier &processor_uuid) const = 0;
   static constexpr char const* DefaultStateStorageName = "defaultstatestorage";
diff --git a/minifi-api/include/minifi-cpp/properties/Configure.h b/minifi-api/include/minifi-cpp/properties/Configure.h
index 393a91c70..945bab143 100644
--- a/minifi-api/include/minifi-cpp/properties/Configure.h
+++ b/minifi-api/include/minifi-cpp/properties/Configure.h
@@ -16,12 +16,13 @@
  */
 #pragma once
 
+#include <memory>
 #include <optional>
 #include <string>
 #include <utility>
-#include <memory>
 
 #include "Configuration.h"
+#include "Locations.h"
 #include "minifi-cpp/core/AgentIdentificationProvider.h"
 #include "utils/gsl.h"
 
@@ -29,6 +30,7 @@ struct ConfigTestAccessor;
 
 namespace org::apache::nifi::minifi {
 
+
 class Configure : public virtual Configuration, public virtual core::AgentIdentificationProvider {
   friend struct ::ConfigTestAccessor;
  public:
@@ -43,6 +45,8 @@ class Configure : public virtual Configuration, public virtual core::AgentIdenti
   using Configuration::set;
   void set(const std::string& key, const std::string& value, PropertyChangeLifetime lifetime) override = 0;
   bool commitChanges() override = 0;
+  [[nodiscard]] virtual std::shared_ptr<const Locations> getLocations() const = 0;
+  virtual void setLocations(std::shared_ptr<const Locations>) = 0;
 
   static gsl::not_null<std::shared_ptr<Configure>> create();
 };
diff --git a/minifi-api/include/minifi-cpp/properties/Locations.h b/minifi-api/include/minifi-cpp/properties/Locations.h
new file mode 100644
index 000000000..3643d36cb
--- /dev/null
+++ b/minifi-api/include/minifi-cpp/properties/Locations.h
@@ -0,0 +1,37 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <filesystem>
+
+namespace org::apache::nifi::minifi {
+class Locations {
+public:
+  virtual ~Locations() = default;
+  [[nodiscard]] virtual const std::filesystem::path& getWorkingDir() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getLockPath() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getLogPropertiesPath() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getUidPropertiesPath() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getPropertiesPath() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getFipsBinPath() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getFipsConfPath() const = 0;
+  [[nodiscard]] virtual const std::filesystem::path& getLogsDirs() const = 0;
+  [[nodiscard]] virtual std::string_view getDefaultExtensionsPattern() const = 0;
+
+  [[nodiscard]] virtual std::string toString() const = 0;
+};
+}  // namespace org::apache::nifi::minifi
diff --git a/minifi-api/include/minifi-cpp/properties/Properties.h b/minifi-api/include/minifi-cpp/properties/Properties.h
index 9f684bdcd..a9573a09a 100644
--- a/minifi-api/include/minifi-cpp/properties/Properties.h
+++ b/minifi-api/include/minifi-cpp/properties/Properties.h
@@ -55,9 +55,7 @@ class Properties {
   virtual int getInt(const std::string &key, int default_value) const = 0;
   virtual std::optional<std::string> getString(const std::string& key) const = 0;
   virtual void loadConfigureFile(const std::filesystem::path& configuration_file, std::string_view prefix = "") = 0;
-  virtual void setHome(std::filesystem::path minifiHome) = 0;
   virtual std::vector<std::string> getConfiguredKeys() const = 0;
-  virtual std::filesystem::path getHome() const = 0;
   virtual bool commitChanges() = 0;
   virtual utils::ChecksumCalculator& getChecksumCalculator() = 0;
   virtual std::filesystem::path getFilePath() const = 0;
diff --git a/minifi_main/CMakeLists.txt b/minifi_main/CMakeLists.txt
index 093eefc43..a9779a72a 100644
--- a/minifi_main/CMakeLists.txt
+++ b/minifi_main/CMakeLists.txt
@@ -81,10 +81,18 @@ if (NOT WIN32)
     if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT APPLE)
         target_link_options(minifiexe PRIVATE "-Wl,--disable-new-dtags")
     endif()
-    if (APPLE)
-        set_target_properties(minifiexe PROPERTIES INSTALL_RPATH "@loader_path")
+
+    if (MINIFI_PACKAGING_TYPE STREQUAL "RPM")
+        set_target_properties(minifiexe PROPERTIES
+                INSTALL_RPATH "/usr/${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}")
+
     else()
-        set_target_properties(minifiexe PROPERTIES INSTALL_RPATH "$ORIGIN")
+        if (APPLE)
+            set_target_properties(minifiexe PROPERTIES INSTALL_RPATH "@loader_path")
+        else()
+            set_target_properties(minifiexe PROPERTIES INSTALL_RPATH "$ORIGIN")
+        endif()
     endif()
-    install(TARGETS minifiexe RUNTIME DESTINATION bin COMPONENT bin)
-endif()
+
+    install(TARGETS minifiexe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin)
+endif()
\ No newline at end of file
diff --git a/minifi_main/Fips.cpp b/minifi_main/Fips.cpp
index 6e919e52b..084754a56 100644
--- a/minifi_main/Fips.cpp
+++ b/minifi_main/Fips.cpp
@@ -37,7 +37,7 @@ constexpr std::string_view FIPS_LIB = "fips.dylib";
 constexpr std::string_view FIPS_LIB = "fips.so";
 #endif
 
-bool replaceMinifiHomeVariable(const std::filesystem::path& file_path, const std::filesystem::path& minifi_home_path, const std::shared_ptr<core::logging::Logger>& logger) {
+bool substituteFipsDirVariable(const std::filesystem::path& file_path, const std::filesystem::path& fips_conf_dir, const std::shared_ptr<core::logging::Logger>& logger) {
   std::ifstream input_file(file_path);
   if (!input_file) {
     logger->log_error("Failed to open file: {}", file_path.string());
@@ -49,16 +49,16 @@ bool replaceMinifiHomeVariable(const std::filesystem::path& file_path, const std
   std::string content = buffer.str();
   input_file.close();
 
-  const std::string placeholder = "${MINIFI_HOME}";
+  const std::string placeholder = "${FIPS_CONF_DIR}";
   size_t pos = content.find(placeholder, 0);
   if (pos == std::string::npos) {
     return true;
   }
 
-  auto minifi_home_path_str = minifi_home_path.generic_string();
+  auto fips_dir_str = fips_conf_dir.generic_string();
   do {
-    content.replace(pos, placeholder.length(), minifi_home_path_str);
-    pos += minifi_home_path_str.length();
+    content.replace(pos, placeholder.length(), fips_dir_str);
+    pos += fips_dir_str.length();
   } while((pos = content.find(placeholder, pos)) != std::string::npos);
 
   std::ofstream output_file(file_path);
@@ -72,17 +72,18 @@ bool replaceMinifiHomeVariable(const std::filesystem::path& file_path, const std
   return true;
 }
 
-bool generateFipsModuleConfig(const std::filesystem::path& minifi_home, const std::shared_ptr<core::logging::Logger>& logger) {
-  std::filesystem::path output_file(minifi_home / "fips" / "fipsmodule.cnf");
+bool generateFipsModuleConfig(const Locations& locations, const std::shared_ptr<core::logging::Logger>& logger) {
+  const auto& fips_bin_path = locations.getFipsBinPath();
+  const auto& fips_conf_path = locations.getFipsConfPath();
+  std::filesystem::path output_file(fips_conf_path / "fipsmodule.cnf");
   logger->log_info("fipsmodule.cnf was not found, trying to run fipsinstall command to generate the file");
 
 #ifdef WIN32
-  std::string command = "\"\"" + (minifi_home / "fips" / "openssl.exe").string() + "\" fipsinstall -out \"" + output_file.string() + "\" -module \"" + (minifi_home / "fips" / FIPS_LIB).string() + "\"\"";
+  std::string command = fmt::format(R"("{}" fipsinstall -out "{}" -module "{}")", fips_bin_path / "openssl.exe", output_file, fips_bin_path / FIPS_LIB);
 #else
-  std::string command = "\"" + (minifi_home / "fips" / "openssl").string() + "\" fipsinstall -out \"" + output_file.string() + "\" -module \"" + (minifi_home / "fips" / FIPS_LIB).string() + "\"";
+  std::string command = fmt::format(R"("{}" fipsinstall -out "{}" -module "{}")", fips_bin_path / "openssl", output_file, fips_bin_path / FIPS_LIB);
 #endif
-  auto ret = std::system(command.c_str());
-  if (ret != 0) {
+  if (std::system(command.c_str()) != 0) {
     logger->log_error("Failed to generate fipsmodule.cnf file");
     return false;
   }
@@ -91,37 +92,39 @@ bool generateFipsModuleConfig(const std::filesystem::path& minifi_home, const st
 }
 }  // namespace
 
-void initializeFipsMode(const std::shared_ptr<minifi::Configure>& configure, const std::filesystem::path& minifi_home, const std::shared_ptr<core::logging::Logger>& logger) {
+void initializeFipsMode(const std::shared_ptr<minifi::Configure>& configure, const Locations& locations, const std::shared_ptr<core::logging::Logger>& logger) {
+  const auto& fips_bin_path = locations.getFipsBinPath();
+  const auto& fips_conf_path = locations.getFipsConfPath();
   if (!(configure->get(minifi::Configure::nifi_openssl_fips_support_enable) | utils::andThen(utils::string::toBool)).value_or(false)) {
     logger->log_info("FIPS mode is disabled. FIPS configs and modules will NOT be loaded.");
     return;
   }
 
-  if (!std::filesystem::exists(minifi_home / "fips" / FIPS_LIB)) {
-    logger->log_error("FIPS mode is enabled, but {} is not available in MINIFI_HOME/fips directory", FIPS_LIB);
+  if (!std::filesystem::exists(fips_bin_path / FIPS_LIB)) {
+    logger->log_error("FIPS mode is enabled, but {} is not available in {} directory", FIPS_LIB, fips_bin_path);
     std::exit(1);
   }
 
-  if (!std::filesystem::exists(minifi_home / "fips" / "fipsmodule.cnf") && !generateFipsModuleConfig(minifi_home, logger)) {
-    logger->log_error("FIPS mode is enabled, but fipsmodule.cnf is not available in $MINIFI_HOME/fips directory, and minifi couldn't generate it automatically.  "
-      "Run $MINIFI_HOME/fips/openssl fipsinstall -out fipsmodule.cnf -module $MINIFI_HOME/fips/{} command to generate the configuration file", FIPS_LIB);
+  if (!std::filesystem::exists(fips_conf_path / "fipsmodule.cnf") && !generateFipsModuleConfig(locations, logger)) {
+    logger->log_error("FIPS mode is enabled, but fipsmodule.cnf is not available in {fips_conf_dir} directory, and minifi couldn't generate it automatically.  "
+      "Run {fips_bin_dir}/openssl fipsinstall -out {fips_conf_dir}/fipsmodule.cnf -module {fips_bin_dir}/{fips_lib_name} command to generate the configuration file", fmt::arg("fips_conf_dir", fips_conf_path), fmt::arg("fips_bin_dir", fips_bin_path),  fmt::arg("fips_lib_name", FIPS_LIB));
     std::exit(1);
   }
 
-  if (!std::filesystem::exists(minifi_home / "fips" / "openssl.cnf")) {
-    logger->log_error("FIPS mode is enabled, but openssl.cnf is not available in MINIFI_HOME/fips directory");
+  if (!std::filesystem::exists(fips_conf_path / "openssl.cnf")) {
+    logger->log_error("FIPS mode is enabled, but openssl.cnf is not available in {} directory", fips_conf_path);
     std::exit(1);
   }
 
-  if (!replaceMinifiHomeVariable(minifi_home / "fips" / "openssl.cnf", minifi_home, logger)) {
-    logger->log_error("Failed to replace MINIFI_HOME variable in openssl.cnf");
+  if (!substituteFipsDirVariable(fips_conf_path / "openssl.cnf", fips_conf_path, logger)) {
+    logger->log_error("Failed to replace FIPS_CONF_DIR variable in openssl.cnf");
     std::exit(1);
   }
 
-  utils::Environment::setEnvironmentVariable("OPENSSL_CONF", (minifi_home / "fips" / "openssl.cnf").string().c_str(), true);
+  utils::Environment::setEnvironmentVariable("OPENSSL_CONF", (fips_conf_path / "openssl.cnf").string().c_str(), true);
 
-  if (!OSSL_PROVIDER_set_default_search_path(nullptr, (minifi_home / "fips").string().c_str())) {
-    logger->log_error("Failed to set FIPS module path: {}", (minifi_home / "fips").string());
+  if (!OSSL_PROVIDER_set_default_search_path(nullptr, (fips_bin_path.string()).c_str())) {
+    logger->log_error("Failed to set FIPS module path: {}", fips_bin_path.string());
     ERR_print_errors_fp(stderr);
     std::exit(1);
   }
diff --git a/minifi_main/Fips.h b/minifi_main/Fips.h
index ab3261b0e..e4a560c81 100644
--- a/minifi_main/Fips.h
+++ b/minifi_main/Fips.h
@@ -20,9 +20,10 @@
 #include <memory>
 #include "core/logging/Logger.h"
 #include "minifi-cpp/properties/Configure.h"
+#include "minifi-cpp/properties/Locations.h"
 
 namespace org::apache::nifi::minifi::fips {
 
-void initializeFipsMode(const std::shared_ptr<Configure>& configure, const std::filesystem::path& minifi_home, const std::shared_ptr<core::logging::Logger>& logger);
+void initializeFipsMode(const std::shared_ptr<Configure>& configure, const Locations& locations, const std::shared_ptr<core::logging::Logger>& logger);
 
 }  // namespace org::apache::nifi::minifi::utils::fips
diff --git a/minifi_main/MainHelper.cpp b/minifi_main/MainHelper.cpp
index 70c46b76e..1b0d4d07b 100644
--- a/minifi_main/MainHelper.cpp
+++ b/minifi_main/MainHelper.cpp
@@ -31,7 +31,7 @@ bool validHome(const std::filesystem::path& home_path) {
 }
 
 void setSyslogLogger() {
-  std::shared_ptr<logging::LoggerProperties> service_logger = std::make_shared<logging::LoggerProperties>();
+  std::shared_ptr<logging::LoggerProperties> service_logger = std::make_shared<logging::LoggerProperties>("");
   service_logger->set("appender.syslog", "syslog");
   service_logger->set("logger.root", "INFO,syslog");
   logging::LoggerConfiguration::getConfiguration().initialize(service_logger);
@@ -111,3 +111,19 @@ std::filesystem::path determineMinifiHome(const std::shared_ptr<logging::Logger>
 
   return minifi_home;
 }
+
+std::shared_ptr<minifi::Locations> determineLocations(const std::shared_ptr<logging::Logger>& logger) {
+  if (const auto minifi_home_env = utils::Environment::getEnvironmentVariable(MINIFI_HOME_ENV_KEY)) {
+    if (minifi_home_env == "FHS") {
+      return minifi::LocationsImpl::createForFHS();
+    }
+  }
+  if (const auto executable_path = utils::file::get_executable_path(); executable_path.parent_path() == "/usr/bin") {
+    return minifi::LocationsImpl::createForFHS();
+  }
+  const auto minifi_home = determineMinifiHome(logger);
+  if (minifi_home.empty()) {
+    return nullptr;
+  }
+  return minifi::LocationsImpl::createFromMinifiHome(minifi_home);
+}
diff --git a/minifi_main/MainHelper.h b/minifi_main/MainHelper.h
index 659f4a730..c584eae11 100644
--- a/minifi_main/MainHelper.h
+++ b/minifi_main/MainHelper.h
@@ -70,6 +70,7 @@ void setSyslogLogger();
  */
 std::filesystem::path determineMinifiHome(const std::shared_ptr<org::apache::nifi::minifi::core::logging::Logger>& logger);
 
+std::shared_ptr<org::apache::nifi::minifi::Locations> determineLocations(const std::shared_ptr<org::apache::nifi::minifi::core::logging::Logger>& logger);
 
 
 #endif /* MAIN_MAINHELPER_H_ */
diff --git a/minifi_main/MiNiFiMain.cpp b/minifi_main/MiNiFiMain.cpp
index 964419f12..9d19527cb 100644
--- a/minifi_main/MiNiFiMain.cpp
+++ b/minifi_main/MiNiFiMain.cpp
@@ -35,41 +35,42 @@
 #endif
 
 #include <fcntl.h>
-#include <cstdio>
 #include <semaphore.h>
-#include <csignal>
 #include <sodium.h>
 
 #include <atomic>
+#include <csignal>
+#include <cstdio>
 #include <cstdlib>
 #include <iostream>
 #include <vector>
 
+#include "AgentDocs.h"
+#include "DiskSpaceWatchdog.h"
+#include "Fips.h"
+#include "FlowController.h"
+#include "MainHelper.h"
 #include "ResourceClaim.h"
+#include "agent/JsonSchema.h"
+#include "agent/agent_version.h"
+#include "argparse/argparse.hpp"
+#include "core/BulletinStore.h"
+#include "core/ConfigurationFactory.h"
 #include "core/Core.h"
 #include "core/FlowConfiguration.h"
-#include "core/ConfigurationFactory.h"
 #include "core/RepositoryFactory.h"
 #include "core/extension/ExtensionManager.h"
 #include "core/repository/VolatileContentRepository.h"
 #include "core/repository/VolatileFlowFileRepository.h"
-#include "DiskSpaceWatchdog.h"
+#include "core/state/MetricsPublisherStore.h"
+#include "core/state/nodes/ResponseNodeLoader.h"
 #include "properties/Decryptor.h"
-#include "utils/file/PathUtils.h"
-#include "utils/file/FileUtils.h"
-#include "utils/file/AssetManager.h"
+#include "properties/LocationsImpl.h"
 #include "utils/Environment.h"
 #include "utils/FileMutex.h"
-#include "FlowController.h"
-#include "AgentDocs.h"
-#include "MainHelper.h"
-#include "agent/JsonSchema.h"
-#include "core/state/nodes/ResponseNodeLoader.h"
-#include "core/state/MetricsPublisherStore.h"
-#include "argparse/argparse.hpp"
-#include "agent/agent_version.h"
-#include "Fips.h"
-#include "core/BulletinStore.h"
+#include "utils/file/AssetManager.h"
+#include "utils/file/FileUtils.h"
+#include "utils/file/PathUtils.h"
 
 namespace minifi = org::apache::nifi::minifi;
 namespace core = minifi::core;
@@ -266,25 +267,25 @@ int main(int argc, char **argv) {
     return -1;
   }
 #endif
-  // Determine MINIFI_HOME
-  const auto minifiHome = determineMinifiHome(logger);
-  if (minifiHome.empty()) {
-    // determineMinifiHome already logged everything we need
+  const auto locations = determineLocations(logger);
+  if (!locations) {
+    // determineLocations already logged everything we need
     return -1;
   }
-  utils::FileMutex minifi_home_mtx(minifiHome / "LOCK");
+
+  utils::FileMutex minifi_home_mtx(locations->getLockPath());
   std::unique_lock minifi_home_lock(minifi_home_mtx, std::defer_lock);
   try {
     minifi_home_lock.lock();
   } catch (const std::exception& ex) {
-    logger->log_error("Could not acquire LOCK for minifi home '{}', maybe another minifi instance is running: {}", minifiHome, ex.what());
+    logger->log_error("Could not acquire LOCK '{}', maybe another minifi instance is running: {}", locations->getLockPath(), ex.what());
     std::exit(1);
   }
   // chdir to MINIFI_HOME
   std::error_code current_path_error;
-  std::filesystem::current_path(minifiHome, current_path_error);
+  std::filesystem::current_path(locations->getWorkingDir(), current_path_error);
   if (current_path_error) {
-    logger->log_error("Failed to change working directory to MINIFI_HOME ({})", minifiHome);
+    logger->log_error("Failed to change working directory to {}", locations->getWorkingDir());
     return -1;
   }
 
@@ -309,21 +310,19 @@ int main(int argc, char **argv) {
     std::string nifi_configuration_class_name = "adaptiveconfiguration";
     std::string content_repo_class = "filesystemrepository";
 
-    auto log_properties = std::make_shared<core::logging::LoggerProperties>();
-    log_properties->setHome(minifiHome);
-    log_properties->loadConfigureFile(DEFAULT_LOG_PROPERTIES_FILE, "nifi.log.");
+    auto log_properties = std::make_shared<core::logging::LoggerProperties>(locations->getLogsDirs());
+    log_properties->loadConfigureFile(locations->getLogPropertiesPath(), "nifi.log.");
 
     logger_configuration.initialize(log_properties);
 
     std::shared_ptr<minifi::Properties> uid_properties = std::make_shared<minifi::PropertiesImpl>("UID properties");
-    uid_properties->setHome(minifiHome);
-    uid_properties->loadConfigureFile(DEFAULT_UID_PROPERTIES_FILE);
+    uid_properties->loadConfigureFile(locations->getUidPropertiesPath());
     utils::IdGenerator::getIdGenerator()->initialize(uid_properties);
 
     // Make a record of minifi home in the configured log file.
-    logger->log_info("MINIFI_HOME={}", minifiHome);
+    logger->log_info("MiNiFi Locations={}", locations->toString());
 
-    auto decryptor = minifi::Decryptor::create(minifiHome);
+    auto decryptor = minifi::Decryptor::create(locations->getWorkingDir());
     if (decryptor) {
       logger->log_info("Found encryption key, will decrypt sensitive properties in the configuration");
     } else {
@@ -331,11 +330,11 @@ int main(int argc, char **argv) {
     }
 
     const std::shared_ptr<minifi::Configure> configure = std::make_shared<minifi::ConfigureImpl>(std::move(decryptor), std::move(log_properties));
-    configure->setHome(minifiHome);
-    configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);
+    configure->setLocations(locations);
+    configure->loadConfigureFile(locations->getPropertiesPath());
     overridePropertiesFromCommandLine(argument_parser, configure);
 
-    minifi::fips::initializeFipsMode(configure, minifiHome, logger);
+    minifi::fips::initializeFipsMode(configure, *locations, logger);
 
     minifi::core::extension::ExtensionManagerImpl::get().initialize(configure);
 
@@ -392,7 +391,7 @@ int main(int argc, char **argv) {
 
     auto filesystem = std::make_shared<utils::file::FileSystem>(
         should_encrypt_flow_config,
-        utils::crypto::EncryptionProvider::create(minifiHome));
+        utils::crypto::EncryptionProvider::create(locations->getWorkingDir()));
 
     auto asset_manager = std::make_unique<utils::file::AssetManager>(*configure);
     auto bulletin_store = std::make_unique<core::BulletinStore>(*configure);
@@ -404,7 +403,7 @@ int main(int argc, char **argv) {
           .configuration = configure,
           .path = configure->get(minifi::Configure::nifi_flow_configuration_file),
           .filesystem = filesystem,
-          .sensitive_values_encryptor = utils::crypto::EncryptionProvider::createSensitivePropertiesEncryptor(minifiHome),
+          .sensitive_values_encryptor = utils::crypto::EncryptionProvider::createSensitivePropertiesEncryptor(locations->getWorkingDir()),
           .asset_manager = asset_manager.get(),
           .bulletin_store = bulletin_store.get()
       }, nifi_configuration_class_name);
diff --git a/packaging/check_rpm_contents.sh b/packaging/check_rpm_contents.sh
new file mode 100644
index 000000000..2a76168f0
--- /dev/null
+++ b/packaging/check_rpm_contents.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# A script to compare the contents of an RPM package against an expected file list.
+
+# --- Usage ---
+# ./check_rpm_contents.sh <path/to/your.rpm> <path/to/expected_list.txt>
+
+if [ "$#" -ne 2 ]; then
+    echo "Usage: $0 <RPM_FILE> <EXPECTED_LIST_FILE>"
+    exit 1
+fi
+
+RPM_FILE="$1"
+EXPECTED_LIST_FILE="$2"
+
+if [ ! -f "$RPM_FILE" ]; then
+    echo "Error: RPM file not found at '$RPM_FILE'"
+    exit 1
+fi
+
+if [ ! -f "$EXPECTED_LIST_FILE" ]; then
+    echo "Error: Expected list file not found at '$EXPECTED_LIST_FILE'"
+    exit 1
+fi
+
+# Create temporary files for sorted lists
+# mktemp ensures we have a unique and secure temporary file
+ACTUAL_SORTED=$(mktemp)
+EXPECTED_SORTED=$(mktemp)
+
+trap 'rm -f "$ACTUAL_SORTED" "$EXPECTED_SORTED"' EXIT
+
+echo "--- Analyzing RPM package: $RPM_FILE ---"
+
+rpm -qlp "$RPM_FILE" | sort > "$ACTUAL_SORTED"
+sort "$EXPECTED_LIST_FILE" > "$EXPECTED_SORTED"
+
+DIFFERENCES=$(diff "$ACTUAL_SORTED" "$EXPECTED_SORTED")
+
+if [ $? -eq 0 ]; then
+    echo "✅ SUCCESS: The RPM contents match the expected list."
+    exit 0
+else
+    echo "❌ FAILURE: The RPM contents do not match the expected list."
+    echo "$DIFFERENCES"
+    exit 1
+fi
\ No newline at end of file
diff --git a/packaging/pre_install.sh b/packaging/pre_install.sh
new file mode 100644
index 000000000..f036952c4
--- /dev/null
+++ b/packaging/pre_install.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+if ! getent group minificpp >/dev/null; then
+    groupadd -r minificpp
+fi
+
+if ! getent passwd minificpp >/dev/null; then
+    useradd -r -g minificpp -s /sbin/nologin -d /var/lib/nifi-minifi-cpp -c "NiFi MiNiFi C++ Service Account" minificpp
+fi
+
+exit 0
\ No newline at end of file
diff --git a/thirdparty/google-cloud-cpp/remove_installation.patch b/thirdparty/google-cloud-cpp/remove_installation.patch
new file mode 100644
index 000000000..4984d77f7
--- /dev/null
+++ b/thirdparty/google-cloud-cpp/remove_installation.patch
@@ -0,0 +1,258 @@
+Subject: [PATCH] remove export
+---
+Index: google/cloud/google_cloud_cpp_common.cmake
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/google/cloud/google_cloud_cpp_common.cmake b/google/cloud/google_cloud_cpp_common.cmake
+--- a/google/cloud/google_cloud_cpp_common.cmake	(revision e9eb0d1d8295966e7bca38c0ddf6529299db4f2b)
++++ b/google/cloud/google_cloud_cpp_common.cmake	(date 1751639900095)
+@@ -233,24 +233,7 @@
+
+ create_bazel_config(google_cloud_cpp_common YEAR 2018)
+
+-# Export the CMake targets to make it easy to create configuration files.
+-install(
+-    EXPORT google_cloud_cpp_common-targets
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_common"
+-    COMPONENT google_cloud_cpp_development)
+-
+-# Install the libraries and headers in the locations determined by
+-# GNUInstallDirs
+-install(
+-    TARGETS google_cloud_cpp_common
+-    EXPORT google_cloud_cpp_common-targets
+-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-            NAMELINK_COMPONENT google_cloud_cpp_development
+-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_development)
++# Removed EXPORT of google_cloud_cpp_common-targets
+
+ google_cloud_cpp_install_headers(google_cloud_cpp_common include/google/cloud)
+
+@@ -277,13 +260,6 @@
+     VERSION ${PROJECT_VERSION}
+     COMPATIBILITY ExactVersion)
+
+-install(
+-    FILES
+-        "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_common-config.cmake"
+-        "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_common-config-version.cmake"
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_common"
+-    COMPONENT google_cloud_cpp_development)
+-
+ if (GOOGLE_CLOUD_CPP_WITH_MOCKS)
+     # Create a header-only library for the mocks. We use a CMake `INTERFACE`
+     # library for these, a regular library would not work on macOS (where the
+@@ -314,11 +290,7 @@
+         DESTINATION "include/google/cloud/mocks"
+         COMPONENT google_cloud_cpp_development)
+
+-    # Export the CMake targets to make it easy to create configuration files.
+-    install(
+-        EXPORT google_cloud_cpp_mocks-targets
+-        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_mocks"
+-        COMPONENT google_cloud_cpp_development)
++    # Removed EXPORT of google_cloud_cpp_mocks-targets
+
+     install(
+         TARGETS google_cloud_cpp_mocks
+@@ -337,13 +309,6 @@
+         "google_cloud_cpp_mocks-config-version.cmake"
+         VERSION ${PROJECT_VERSION}
+         COMPATIBILITY ExactVersion)
+-
+-    install(
+-        FILES
+-            "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_mocks-config.cmake"
+-            "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_mocks-config-version.cmake"
+-        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_mocks"
+-        COMPONENT google_cloud_cpp_development)
+ endif ()
+
+ if (BUILD_TESTING)
+Index: google/cloud/google_cloud_cpp_rest_internal.cmake
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/google/cloud/google_cloud_cpp_rest_internal.cmake b/google/cloud/google_cloud_cpp_rest_internal.cmake
+--- a/google/cloud/google_cloud_cpp_rest_internal.cmake	(revision e9eb0d1d8295966e7bca38c0ddf6529299db4f2b)
++++ b/google/cloud/google_cloud_cpp_rest_internal.cmake	(date 1751633114501)
+@@ -169,11 +169,7 @@
+ add_library(google-cloud-cpp::rest_internal ALIAS
+             google_cloud_cpp_rest_internal)
+
+-# Export the CMake targets to make it easy to create configuration files.
+-install(
+-    EXPORT google_cloud_cpp_rest_internal-targets
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_rest_internal"
+-    COMPONENT google_cloud_cpp_development)
++# # Removed EXPORT of google_cloud_cpp_rest_internal-targets
+
+ # Install the libraries and headers in the locations determined by
+ # GNUInstallDirs
+Index: google/cloud/google_cloud_cpp_rest_protobuf_internal.cmake
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/google/cloud/google_cloud_cpp_rest_protobuf_internal.cmake b/google/cloud/google_cloud_cpp_rest_protobuf_internal.cmake
+--- a/google/cloud/google_cloud_cpp_rest_protobuf_internal.cmake	(revision e9eb0d1d8295966e7bca38c0ddf6529299db4f2b)
++++ b/google/cloud/google_cloud_cpp_rest_protobuf_internal.cmake	(date 1751642044339)
+@@ -51,25 +51,7 @@
+
+ create_bazel_config(google_cloud_cpp_rest_protobuf_internal YEAR 2022)
+
+-# Export the CMake targets to make it easy to create configuration files.
+-install(
+-    EXPORT google_cloud_cpp_rest_protobuf_internal-targets
+-    DESTINATION
+-        "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_rest_protobuf_internal"
+-    COMPONENT google_cloud_cpp_development)
+-
+-# Install the libraries and headers in the locations determined by
+-# GNUInstallDirs
+-install(
+-    TARGETS google_cloud_cpp_rest_protobuf_internal
+-    EXPORT google_cloud_cpp_rest_protobuf_internal-targets
+-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-            NAMELINK_COMPONENT google_cloud_cpp_development
+-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_development)
++# Removed installation
+
+ google_cloud_cpp_install_headers(google_cloud_cpp_rest_protobuf_internal
+                                  include/google/cloud)
+Index: google/cloud/storage/google_cloud_cpp_storage_grpc.cmake
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake b/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake
+--- a/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake	(revision e9eb0d1d8295966e7bca38c0ddf6529299db4f2b)
++++ b/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake	(date 1751642129371)
+@@ -294,11 +294,6 @@
+     "absl_time"
+     ${EXTRA_MODULES})
+
+-install(
+-    EXPORT storage_grpc-targets
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_storage_grpc"
+-    COMPONENT google_cloud_cpp_development)
+-
+ # Create and install the CMake configuration files.
+ configure_file("config-grpc.cmake.in"
+                "google_cloud_cpp_storage_grpc-config.cmake" @ONLY)
+@@ -307,25 +302,6 @@
+     VERSION ${PROJECT_VERSION}
+     COMPATIBILITY ExactVersion)
+
+-install(
+-    FILES
+-        "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_storage_grpc-config.cmake"
+-        "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_storage_grpc-config-version.cmake"
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_storage_grpc"
+-    COMPONENT google_cloud_cpp_development)
+-
+-install(
+-    TARGETS google_cloud_cpp_storage_grpc google_cloud_cpp_storage_protos
+-            # TODO(#13857) - remove the backwards compatibility shims
+-            google_cloud_cpp_experimental_storage_grpc
+-    EXPORT storage_grpc-targets
+-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-            NAMELINK_COMPONENT google_cloud_cpp_development
+-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_development)
+
+ google_cloud_cpp_install_headers(google_cloud_cpp_storage_grpc
+                                  include/google/cloud/storage)
+Index: google/cloud/spanner/CMakeLists.txt
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/google/cloud/spanner/CMakeLists.txt b/google/cloud/spanner/CMakeLists.txt
+--- a/google/cloud/spanner/CMakeLists.txt	(revision e9eb0d1d8295966e7bca38c0ddf6529299db4f2b)
++++ b/google/cloud/spanner/CMakeLists.txt	(date 1751642142713)
+@@ -300,24 +300,7 @@
+     create_bazel_config(google_cloud_cpp_spanner_rest YEAR "2023")
+ endif ()
+
+-# Export the CMake targets to make it easy to create configuration files.
+-install(
+-    EXPORT spanner-targets
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_spanner"
+-    COMPONENT google_cloud_cpp_development)
+-
+-# Install the libraries and headers in the locations determined by
+-# GNUInstallDirs
+-install(
+-    TARGETS google_cloud_cpp_spanner google_cloud_cpp_spanner_protos
+-    EXPORT spanner-targets
+-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-            NAMELINK_COMPONENT google_cloud_cpp_development
+-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_development)
++# Remove installation
+
+ google_cloud_cpp_install_headers("google_cloud_cpp_spanner"
+                                  "include/google/cloud/spanner")
+Index: google/cloud/storage/google_cloud_cpp_storage.cmake
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/google/cloud/storage/google_cloud_cpp_storage.cmake b/google/cloud/storage/google_cloud_cpp_storage.cmake
+--- a/google/cloud/storage/google_cloud_cpp_storage.cmake	(revision e9eb0d1d8295966e7bca38c0ddf6529299db4f2b)
++++ b/google/cloud/storage/google_cloud_cpp_storage.cmake	(date 1751642105444)
+@@ -313,22 +313,7 @@
+
+ create_bazel_config(google_cloud_cpp_storage)
+
+-# Export the CMake targets to make it easy to create configuration files.
+-install(
+-    EXPORT storage-targets
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_storage"
+-    COMPONENT google_cloud_cpp_development)
+-
+-install(
+-    TARGETS google_cloud_cpp_storage
+-    EXPORT storage-targets
+-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_runtime
+-            NAMELINK_COMPONENT google_cloud_cpp_development
+-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+-            COMPONENT google_cloud_cpp_development)
++# Removed EXPORT of storage-targets
+
+ google_cloud_cpp_install_headers(google_cloud_cpp_storage
+                                  include/google/cloud/storage)
+@@ -361,12 +346,6 @@
+     VERSION ${PROJECT_VERSION}
+     COMPATIBILITY ExactVersion)
+
+-install(
+-    FILES
+-        "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_storage-config.cmake"
+-        "${CMAKE_CURRENT_BINARY_DIR}/google_cloud_cpp_storage-config-version.cmake"
+-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/google_cloud_cpp_storage"
+-    COMPONENT google_cloud_cpp_development)
+
+ install(
+     FILES testing/mock_client.h
diff --git a/thirdparty/librdkafka/0003-remove_FindLZ4_installation.patch b/thirdparty/librdkafka/0003-remove_FindLZ4_installation.patch
new file mode 100644
index 000000000..5606559f5
--- /dev/null
+++ b/thirdparty/librdkafka/0003-remove_FindLZ4_installation.patch
@@ -0,0 +1,22 @@
+Subject: [PATCH] remove FindLZ4 installation
+---
+Index: CMakeLists.txt
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+--- a/CMakeLists.txt	(revision 2af6749287b3695edf2421631ebf08d6bcb176e3)
++++ b/CMakeLists.txt	(date 1751541934552)
+@@ -262,10 +262,7 @@
+     COMPATIBILITY AnyNewerVersion
+ )
+
+-install(
+-    FILES "${project_config}" "${project_version}" "packaging/cmake/Modules/FindLZ4.cmake"
+-    DESTINATION "${config_install_dir}"
+-)
++#A KURVA ANYÁD
+
+ install(
+     EXPORT "${targets_export_name}"
diff --git a/utils/include/core/ProcessContext.h b/utils/include/core/ProcessContext.h
index 2606058b3..195b2d71e 100644
--- a/utils/include/core/ProcessContext.h
+++ b/utils/include/core/ProcessContext.h
@@ -58,8 +58,7 @@ class ProcessContextImpl : public core::VariableRegistryImpl, public virtual Pro
         flow_repo_(flow_repo),
         content_repo_(content_repo),
         processor_(processor),
-        configure_(minifi::Configure::create()),
-        initialized_(false) {}
+        configure_(minifi::Configure::create()) {}
 
   ProcessContextImpl(Processor& processor, controller::ControllerServiceProvider* controller_service_provider, const std::shared_ptr<core::Repository>& repo,
       const std::shared_ptr<core::Repository>& flow_repo, const std::shared_ptr<minifi::Configure>& configuration,
@@ -72,8 +71,7 @@ class ProcessContextImpl : public core::VariableRegistryImpl, public virtual Pro
         flow_repo_(flow_repo),
         content_repo_(content_repo),
         processor_(processor),
-        configure_(configuration ? gsl::make_not_null(configuration) : minifi::Configure::create()),
-        initialized_(false) {}
+        configure_(configuration ? gsl::make_not_null(configuration) : minifi::Configure::create()) {}
 
   // Get Processor associated with the Process Context
   Processor& getProcessor() const override { return processor_; }
@@ -117,14 +115,6 @@ class ProcessContextImpl : public core::VariableRegistryImpl, public virtual Pro
     return controller_service;
   }
 
-  void initializeContentRepository(const std::string& home) override {
-    configure_->setHome(home);
-    content_repo_->initialize(configure_);
-    initialized_ = true;
-  }
-
-  bool isInitialized() const override { return initialized_; }
-
   static constexpr char const* DefaultStateStorageName = "defaultstatestorage";
 
   StateManager* getStateManager() override {
@@ -223,7 +213,6 @@ class ProcessContextImpl : public core::VariableRegistryImpl, public virtual Pro
   std::shared_ptr<core::ContentRepository> content_repo_;
   Processor& processor_;
   gsl::not_null<std::shared_ptr<Configure>> configure_;
-  bool initialized_;
 };
 
 inline nonstd::expected<std::string, std::error_code> ProcessContextImpl::getProperty(const std::string_view name, const FlowFile* const) const {
diff --git a/utils/include/utils/expected.h b/utils/include/utils/expected.h
index aff2c0a05..3d84bd8ec 100644
--- a/utils/include/utils/expected.h
+++ b/utils/include/utils/expected.h
@@ -244,8 +244,8 @@ auto try_expression(F&& action, Args&&... args) noexcept {
 template <typename T, typename E, typename Char>
 struct fmt::formatter<nonstd::expected<T, E>, Char,
                  std::enable_if_t<(std::is_void<T>::value ||
-                                   fmt::is_formattable<T, Char>::value) &&
-                                  fmt::is_formattable<E, Char>::value>> {
+                 fmt::is_formattable<T, Char>::value) &&
+                 fmt::is_formattable<E, Char>::value>> {
   template <typename ParseContext>
   constexpr auto parse(ParseContext& ctx) -> const Char* {
     return ctx.begin();
diff --git a/utils/src/utils/crypto/EncryptionManager.cpp b/utils/src/utils/crypto/EncryptionManager.cpp
index 3cedac44c..7e20b53de 100644
--- a/utils/src/utils/crypto/EncryptionManager.cpp
+++ b/utils/src/utils/crypto/EncryptionManager.cpp
@@ -26,16 +26,14 @@ namespace org::apache::nifi::minifi::utils::crypto {
 
 std::optional<Bytes> EncryptionManager::readKey(const std::string& key_name) const {
   auto bootstrap_conf = minifi::Properties::create();
-  bootstrap_conf->setHome(key_dir_);
-  bootstrap_conf->loadConfigureFile(DEFAULT_NIFI_BOOTSTRAP_FILE);
+  bootstrap_conf->loadConfigureFile(key_dir_ / DEFAULT_NIFI_BOOTSTRAP_FILE);
   return bootstrap_conf->getString(key_name)
          | utils::transform([](const std::string &encryption_key_hex) { return utils::string::from_hex(encryption_key_hex); });
 }
 
 bool EncryptionManager::writeKey(const std::string &key_name, const Bytes& key) const {
   auto bootstrap_conf = minifi::Properties::create();
-  bootstrap_conf->setHome(key_dir_);
-  bootstrap_conf->loadConfigureFile(DEFAULT_NIFI_BOOTSTRAP_FILE);
+  bootstrap_conf->loadConfigureFile(key_dir_ / DEFAULT_NIFI_BOOTSTRAP_FILE);
   bootstrap_conf->set(key_name, utils::string::to_hex(key));
   return bootstrap_conf->commitChanges();
 }