2025-11-09 12:07:04 +00:00
|
|
|
---
|
|
|
|
|
sidebar_position: 10
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Architecture
|
|
|
|
|
|
|
|
|
|
We begin the guide with a high-level overview of the architecture of the CDR Link deployment framework.
|
|
|
|
|
|
|
|
|
|
## Introduction
|
|
|
|
|
|
|
|
|
|
We deploy each CDR Link instance on a single
|
|
|
|
|
[Red Had Enterprise Linux](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux)
|
|
|
|
|
9 (or compatible) host using
|
|
|
|
|
[rootless Podman](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md).
|
|
|
|
|
Each component of Link is a container instance with the containers managed via systemd using
|
|
|
|
|
[Podman Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html).
|
|
|
|
|
Components communicate via isolated networks that are also configured via Quadlet, and make use of the
|
|
|
|
|
[slirp4netns](https://github.com/rootless-containers/slirp4netns) user-mode networking for unprivileged
|
|
|
|
|
network namespaces.
|
|
|
|
|
|
|
|
|
|
Both
|
|
|
|
|
[discretionary access controls](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_basic_system_settings/managing-file-system-permissions_configuring-basic-system-settings)
|
2025-11-09 14:39:28 +00:00
|
|
|
and
|
|
|
|
|
[SELinux](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html-single/using_selinux/index)
|
|
|
|
|
are used to prevent lateral movement between containers should a container be compromised, with particular
|
2025-11-09 12:07:04 +00:00
|
|
|
attention given to the messaging channels WhatsApp and Signal.
|
|
|
|
|
No container runs its application as the inside "root" user, which is an unprivileged user on the host.
|
|
|
|
|
|
|
|
|
|
The `/home` mount point on the host is encrypted using
|
|
|
|
|
[LUKS](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/managing_storage_devices/encrypting-block-devices-using-luks_managing-storage-devices)
|
|
|
|
|
with a per instance key to protect all user data at rest.
|
|
|
|
|
Further, we use separate partitions for critical audit logging to ensure that a resource exhaustion attack cannot
|
|
|
|
|
prevent later investigation, and automatically shut down instances where there is no space available for audit logging.
|
|
|
|
|
|
|
|
|
|
## Components
|
|
|
|
|
|
|
|
|
|
The following diagram shows the dependency relationships between the components of CDR Link.
|
2025-11-09 14:39:28 +00:00
|
|
|
If you use our [Ansible role](./deploy.md) for deployment then these will be automatically configured.
|
2025-11-09 12:07:04 +00:00
|
|
|
The Link stack containers are
|
|
|
|
|
[OCI](https://opencontainers.org/) compliant containers and you can run these with alternatives
|
|
|
|
|
such as [Docker Compose](https://docs.docker.com/compose/) however we would not be able to provide support for this
|
|
|
|
|
setup.
|
|
|
|
|
Our former Docker Compose deployment framework has been deprecated and we intend to migrate all partners to our new
|
|
|
|
|
rootless Podman setup for the improved reliability, performance, and security.
|
|
|
|
|
|
|
|
|
|
:::info
|
|
|
|
|
While the following diagram refers to `.service` units, these are the units generated by Podman Quadlet.
|
|
|
|
|
The service definitions are in `.container` units within the Quadlet directory at `$HOME/.config/containers/systemd`.
|
|
|
|
|
:::
|
|
|
|
|
```mermaid
|
|
|
|
|
flowchart TD
|
|
|
|
|
bridge-worker.service --> bridge-postgresql.service
|
2025-11-09 14:39:28 +00:00
|
|
|
bridge-worker.service -.-> bridge-whatsapp.service
|
|
|
|
|
bridge-worker.service -.-> signal-cli-rest-api.service
|
2025-11-09 12:07:04 +00:00
|
|
|
|
|
|
|
|
link.service --> bridge-postgresql.service
|
|
|
|
|
link.service --> bridge-worker.service
|
|
|
|
|
|
|
|
|
|
opensearch-dashboards.service --> zammad-opensearch.service
|
|
|
|
|
|
|
|
|
|
zammad-nginx.service --> zammad-railsserver.service
|
|
|
|
|
zammad-nginx.service --> link.service
|
|
|
|
|
|
|
|
|
|
zammad-storage.target{zammad-storage.target}
|
|
|
|
|
zammad-storage.target --> zammad-postgresql.service
|
|
|
|
|
zammad-storage.target --> zammad-redis.service
|
|
|
|
|
zammad-storage.target --> zammad-memcached.service
|
|
|
|
|
zammad-storage.target --> zammad-opensearch.service
|
|
|
|
|
|
|
|
|
|
zammad-railsserver.service -.-> zammad-init.service
|
|
|
|
|
|
|
|
|
|
zammad-init.service --> zammad-storage.target
|
|
|
|
|
zammad-railsserver.service --> zammad-storage.target
|
|
|
|
|
zammad-scheduler.service --> zammad-storage.target
|
|
|
|
|
zammad-websocket.service --> zammad-storage.target
|
|
|
|
|
|
|
|
|
|
link.target{link.target}
|
|
|
|
|
link.target --> opensearch-dashboards.service
|
|
|
|
|
link.target --> zammad-nginx.service
|
|
|
|
|
link.target --> zammad-scheduler.service
|
|
|
|
|
link.target --> zammad-websocket.service
|
|
|
|
|
```
|