diff --git a/.gitignore b/.gitignore index 05b9b0f..412b5e8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ data/vmm_init/* *.qcow2 *.sql *.iso +*.git_bak !.gitkeep diff --git a/ansible/inventory/group_vars/all.yaml b/ansible/inventory/group_vars/all.yaml index fb3a2f0..2d5c935 100644 --- a/ansible/inventory/group_vars/all.yaml +++ b/ansible/inventory/group_vars/all.yaml @@ -68,6 +68,15 @@ services: dependency: cert: true # infra + rustfs: + domain: + internal: "rustfs" + public: "rustfs" + ports: + http: "9001" + subuid: "110000" + dependency: + web: "infra-public" postgresql: domain: internal: "postgresql" @@ -416,6 +425,7 @@ version: # common caddy: "2.11.4" # infra + rustfs: "1.0.0-rc.6" ca: "0.30.2" ## Postgresql postgresql: "18.6" @@ -437,11 +447,11 @@ version: vaultwarden: "1.37.2" gitea: "1.27.3" redis: "8.10.1" - immich: "v3.1.0" + immich: "v3.2.2" nextcloud: "34.0.3" collabora: "26.04.3.2.1" sure: "0.7.4" - outline: "1.10.0" + outline: "1.10.1" homebox: "0.26.2" homepage: "v2.0.0" snappymail: "v2.38.2" diff --git a/ansible/inventory/host_vars/fw.yaml b/ansible/inventory/host_vars/fw.yaml index b71ce53..c5b0708 100644 --- a/ansible/inventory/host_vars/fw.yaml +++ b/ansible/inventory/host_vars/fw.yaml @@ -118,6 +118,7 @@ network: server: "fd00:10::11" reverse: "1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0" alias: + - "rustfs" - "ca" - "postgresql" - "mariadb" diff --git a/ansible/playbooks/infra/site.yaml b/ansible/playbooks/infra/site.yaml index d2c8da7..31960d6 100644 --- a/ansible/playbooks/infra/site.yaml +++ b/ansible/playbooks/infra/site.yaml @@ -154,6 +154,14 @@ tags: ["site", "ca"] tags: ["site", "ca"] + - name: Set rustfs + ansible.builtin.include_role: + name: "infra" + tasks_from: "services/set_rustfs" + apply: + tags: ["site", "rustfs"] + tags: ["site", "rustfs"] + - name: Set postgresql ansible.builtin.include_role: name: "infra" diff --git a/ansible/roles/app/tasks/services/set_kaneo.yaml b/ansible/roles/app/tasks/services/set_kaneo.yaml index 76ede12..a22301b 100644 --- a/ansible/roles/app/tasks/services/set_kaneo.yaml +++ b/ansible/roles/app/tasks/services/set_kaneo.yaml @@ -36,6 +36,8 @@ value: "{{ hostvars['console']['postgresql']['password']['kaneo'] }}" - name: "KANEO_OIDC_CLIENT_SECRET" value: "{{ hostvars['console']['kaneo']['oidc']['secret'] }}" + - name: "KANEO_S3_SECRET_KEY" + value: "{{ hostvars['console']['rustfs']['password']['kaneo'] }}" notify: "notification_restart_kaneo" no_log: true diff --git a/ansible/roles/infra/handlers/main.yaml b/ansible/roles/infra/handlers/main.yaml index b024616..a5b34b6 100644 --- a/ansible/roles/infra/handlers/main.yaml +++ b/ansible/roles/infra/handlers/main.yaml @@ -1,4 +1,15 @@ --- +- name: Restart rustfs + ansible.builtin.systemd: + name: "rustfs.service" + state: "restarted" + enabled: true + daemon_reload: true + scope: "user" + changed_when: false + listen: "notification_restart_rustfs" + ignore_errors: true # noqa: ignore-errors + - name: Restart ca ansible.builtin.systemd: name: "ca.service" diff --git a/ansible/roles/infra/tasks/services/set_rustfs.yaml b/ansible/roles/infra/tasks/services/set_rustfs.yaml new file mode 100644 index 0000000..c9dff13 --- /dev/null +++ b/ansible/roles/infra/tasks/services/set_rustfs.yaml @@ -0,0 +1,65 @@ +--- +- name: Create rustfs directory + ansible.builtin.file: + path: "{{ node['home_path'] }}/{{ item }}" + state: "directory" + owner: "{{ services['rustfs']['subuid'] }}" + group: "{{ node['group'] }}" + mode: "0770" + loop: + - "data/containers/rustfs" + - "data/containers/rustfs/data" + become: true + +- name: Register secret value to podman secret + containers.podman.podman_secret: + name: "RUSTFS_SECRET_KEY" + data: "{{ hostvars['console']['rustfs']['password']['rustfs'] }}" + state: "present" + force: true + notify: "notification_restart_rustfs" + no_log: true + +- name: Pull image + containers.podman.podman_image: + name: "docker.io/rustfs/rustfs" + tag: "{{ version['containers']['rustfs'] }}" + state: "present" + pull: true + +- name: Deploy container file + ansible.builtin.template: + src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/rustfs/rustfs.container.j2" + dest: "{{ node['home_path'] }}/.config/containers/systemd/rustfs.container" + owner: "{{ ansible_user }}" + group: "{{ node['group'] }}" + mode: "0644" + notify: "notification_restart_rustfs" + +- name: Enable rustfs + ansible.builtin.systemd: + name: "rustfs.service" + state: "started" + enabled: true + daemon_reload: true + scope: "user" + +- name: Check container archive images + ansible.builtin.stat: + path: "{{ node['home_path'] }}/archives/containers/docker.io_rustfs_rustfs_{{ version['containers']['rustfs'] }}.tar" + register: container_archive_images + +- name: Save container archive images + containers.podman.podman_save: + image: + - "docker.io/rustfs/rustfs:{{ version['containers']['rustfs'] }}" + dest: "{{ node['home_path'] }}/archives/containers/docker.io_rustfs_rustfs_{{ version['containers']['rustfs'] }}.tar" + format: "oci-archive" + force: false + when: not container_archive_images.stat.exists + +- name: Fetch container archive images + ansible.builtin.fetch: + src: "{{ node['home_path'] }}/archives/containers/docker.io_rustfs_rustfs_{{ version['containers']['rustfs'] }}.tar" + dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/" + flat: true diff --git a/config/node/infra/nftables.conf.j2 b/config/node/infra/nftables.conf.j2 index b98a5aa..e339660 100644 --- a/config/node/infra/nftables.conf.j2 +++ b/config/node/infra/nftables.conf.j2 @@ -7,6 +7,8 @@ define NET4_SERVER = {{ hostvars['fw']['network']['subnet']['ipv4']['server'] }} define NET6_SERVER = {{ hostvars['fw']['network']['subnet']['ipv6']['server'] }} define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} } define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} } +define HOSTS4_AUTH = {{ hostvars['fw']['network']['auth']['ipv4']['server'] }} +define HOSTS6_AUTH = {{ hostvars['fw']['network']['auth']['ipv6']['server'] }} define PORTS_SSH = 22 define PORTS_DB = { 5432, 3306 } define PORTS_CA = {{ services['ca']['ports']['https'] }} @@ -58,10 +60,10 @@ table inet filter { ip6 saddr $NET6_SERVER tcp dport $PORTS_CA accept comment "allow ipv6 ca connection: SERVER > INFRA" ip saddr $NET4_SERVER tcp dport $PORTS_DB accept comment "allow ipv4 db connection: SERVER > INFRA" ip6 saddr $NET6_SERVER tcp dport $PORTS_DB accept comment "allow ipv6 db connection: SERVER > INFRA" - ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv4 http connection: CONSOLE > INFRA" - ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv6 http connection: CONSOLE > INFRA" - ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: CONSOLE > INFRA" - ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: CONSOLE > INFRA" + ip saddr { $HOSTS4_CONSOLE, $HOSTS4_AUTH } tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv4 http connection: CONSOLE, AUTH > APP" + ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_AUTH } tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv6 http connection: CONSOLE, AUTH > APP" + ip saddr { $HOSTS4_CONSOLE, $HOSTS4_AUTH } tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: CONSOLE, AUTH > APP" + ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_AUTH } tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: CONSOLE, AUTH > APP" ip saddr $NET4_SERVER tcp dport $PORTS_LDAPS_FORWARD ct original proto-dst $PORTS_LDAPS accept comment "allow ipv4 ldaps connection: SERVER > INFRA" ip6 saddr $NET6_SERVER tcp dport $PORTS_LDAPS_FORWARD ct original proto-dst $PORTS_LDAPS accept comment "allow ipv6 ldaps connection: SERVER > INFRA" ip saddr $NET4_SERVER tcp dport $PORTS_PROMETHEUS accept comment "allow ipv4 prometheus connection: SERVER > INFRA" diff --git a/config/secrets/secrets.yaml b/config/secrets/secrets.yaml index 187a173..50b55f2 100644 --- a/config/secrets/secrets.yaml +++ b/config/secrets/secrets.yaml @@ -117,6 +117,14 @@ blocky: #ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment] # # +#ENC[AES256_GCM,data:YRIwmRi2hfDb9s4RDy4C,iv:HkpZSROqRaWH/m4dq3Yo9p+n4QJDRbkb29Wcd7OJpXc=,tag:sjnNSWS84DdCIPkGxzFCyQ==,type:comment] +rustfs: + password: + rustfs: ENC[AES256_GCM,data:Wrhw7iW6oPdXXMRq6E/AL+PEM/smak9313eAgwtzrt6fzcSYtdCaVkwNG2Q=,iv:CM5hjpusS9qPoGd96QhHPMTAXpEzZFQEamNRJXVHwjQ=,tag:squNCCytd1BB/91jPSVnng==,type:str] + kaneo: ENC[AES256_GCM,data:15kcZRVhZwrU0znXqc8pJX2+/zEIsHWKttkEZGKlhkthNIRCjK28zi4l/Ns=,iv:3c0s9UCPlP+OqRgugGK27LGyZk8sZjigFfPtET50Hps=,tag:qQa8zVicVHGEwj5HrrXEOg==,type:str] +#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment] +# +# #ENC[AES256_GCM,data:xUxguG12uiQAzJGMXaaqdgTfCw==,iv:kh2nqSVtBXaAhEywAdDPbbG0p2ljX4mtjVKYXCNL20c=,tag:XGaBtxPBHSaLRYZa97+kmw==,type:comment] postgresql: key: ENC[AES256_GCM,data:uULX8NVo7hBS0RMMlTwBtv61brsZfKN+IQeifjCUogqgsDzNbYVFa7lartuM5u9opvJsrwgVJqTTWI71SB2cCAPTK6fVvdCAvtwHD2NwtHYu0gPsFKyxotvyWF2SNLNFF89ntz2wyPIvZhiTY4QwN6BbHpt9a/aYzZU3mQ2CFtquUPWH8caI38c2Kvj8wcRqR3+adXoF5VA5JOf+bZla78/QkGG3ty93luQz9ygXPwjYtqaHy/mpKOymX5hA/jz33ciShOxVBwe9xwxKwyV7KONTd1IudbRoqe0QC1hrMa/HJ7M=,iv:4WiN/fQgCPuve5lXOttcmRos6e04f7fLYSLYte7mfmw=,tag:3ZkhRr1MGeiGu8HZnoVXcg==,type:str] @@ -398,7 +406,7 @@ sops: k+uyWPPi+enFkVaceSwMFrA66uaWWrwAj11sXEB7yzvGFPrnAGezjQ== -----END AGE ENCRYPTED FILE----- recipient: age120wuwcmsm845ztsvsz46pswj5je53uc2n35vadklrfqudu6cxuusxetk7y - lastmodified: "2026-09-08T03:23:38Z" - mac: ENC[AES256_GCM,data:+mTAe1NwSbQHsmaVxKrtIDeRyyKbDVHSRCkji5+hAByS/GS4OzK+SwdyGYa5Ihv+g2J/7Pechf44GY8mv0lirWcOTGxqzvMDiRSXNty+aQVzOn9sXbfCvWXBUqDLNOiNISN0RfF1eVlG12D8wNfFEXFbs6lv81IMIN9ctdvTN5c=,iv:CG6Px0p/EomUafLody2kJOR8AzdmPTqe1ry1DZUhNSc=,tag:ClSWU401Jt6PzhcSCNNvbg==,type:str] + lastmodified: "2026-09-15T10:12:55Z" + mac: ENC[AES256_GCM,data:694Pf1d/O64CCv+l72zugmlk+XOiFi27UJ7nrqtIArdgOZsNbRKGwM2kcsbcHiJsqh6erLCJPEaN7pb+cZ3OEBz1pK7veZ+px4yBvDntfZB0ZuSUgiKuebChVRY2ljTMPtQWYHN8R/ij3uXWmSNIA8Kws0fKKZ9yOGTtUUCAbbU=,iv:zdlTeNrImqna2Fsv+mq2W3Mb4mpIsx8IDRIHTXWTHZU=,tag:A95RmZJwRZ06MkHfgGwtKw==,type:str] unencrypted_suffix: _unencrypted version: 3.13.2 diff --git a/config/services/containers/app/groupoffice/config/groupoffice-ca.ini.j2 b/config/services/containers/app/groupoffice/config/groupoffice-ca.ini.j2 index 095b3bb..65dbaf2 100644 --- a/config/services/containers/app/groupoffice/config/groupoffice-ca.ini.j2 +++ b/config/services/containers/app/groupoffice/config/groupoffice-ca.ini.j2 @@ -1 +1,2 @@ openssl.cafile=/etc/ssl/groupoffice/{{ root_cert_filename }} +openssl.capath=/etc/ssl/certs diff --git a/config/services/containers/app/kaneo/kaneo.container.j2 b/config/services/containers/app/kaneo/kaneo.container.j2 index 6d36e72..7356e33 100644 --- a/config/services/containers/app/kaneo/kaneo.container.j2 +++ b/config/services/containers/app/kaneo/kaneo.container.j2 @@ -14,7 +14,9 @@ PublishPort={{ services['kaneo']['ports']['http'] }}:5173/tcp Volume=%h/containers/kaneo/ssl:/etc/ssl/kaneo:ro +# General Environment="TZ={{ timezone }}" +Environment="NODE_EXTRA_CA_CERTS=/etc/ssl/kaneo/{{ root_cert_filename }}" Environment="DISABLE_PASSWORD_REGISTRATION=true" Environment="DISABLE_REGISTRATION=false" Environment="DISABLE_GUEST_ACCESS=true" @@ -27,15 +29,22 @@ Environment="POSTGRES_PORT={{ services['postgresql']['ports']['tcp'] }}" Environment="POSTGRES_DB=kaneo_db" Environment="POSTGRES_USER=kaneo" Environment="PGSSLMODE=verify-full" -Environment="NODE_EXTRA_CA_CERTS=/etc/ssl/kaneo/{{ root_cert_filename }}" Secret=KANEO_DB_PASSWORD,type=env,target=POSTGRES_PASSWORD +# OIDC Environment="CUSTOM_OAUTH_CLIENT_ID=kaneo" Environment="CUSTOM_OAUTH_DISCOVERY_URL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/.well-known/openid-configuration" Environment="CUSTOM_OAUTH_SCOPES=openid,profile,email" Environment="CUSTOM_AUTH_PKCE=true" Secret=KANEO_OIDC_CLIENT_SECRET,type=env,target=CUSTOM_OAUTH_CLIENT_SECRET +# S3 (RustFS) +Environment="S3_ENDPOINT=https://{{ services['rustfs']['domain']['public'] }}.{{ domain['public'] }}" +Environment="S3_BUCKET=kaneo" +Environment="S3_ACCESS_KEY_ID=kaneo" +Environment="S3_REGION=us-east-1" +Environment="S3_FORCE_PATH_STYLE=true" +Secret=KANEO_S3_SECRET_KEY,type=env,target=S3_SECRET_ACCESS_KEY [Service] ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }} diff --git a/config/services/containers/common/caddy/etc/Caddyfile.j2 b/config/services/containers/common/caddy/etc/Caddyfile.j2 index fbf0c04..32c4948 100644 --- a/config/services/containers/common/caddy/etc/Caddyfile.j2 +++ b/config/services/containers/common/caddy/etc/Caddyfile.j2 @@ -20,7 +20,7 @@ } } {% endif %} -{% if node['name'] == 'app' %} +{% if node['name'] in ['infra', 'app'] %} { servers { trusted_proxies static {{ hostvars['fw']['network']['auth']['ipv4']['server'] }} {{ hostvars['fw']['network']['auth']['ipv6']['server'] }} @@ -80,7 +80,13 @@ {% if service['ports']['https'] is defined %} reverse_proxy https://{{ service['domain']['internal'] }}.{{ domain['internal'] }}:{{ service['ports']['https'] }} {% else %} + {% if 'public' in web_type %} + reverse_proxy host.containers.internal:{{ service['ports']['http'] }} { + header_up Host {http.request.header.X-Forwarded-Host} + } + {% else %} reverse_proxy host.containers.internal:{{ service['ports']['http'] }} + {% endif %} {% endif %} } } diff --git a/config/services/containers/infra/rustfs/rustfs.container.j2 b/config/services/containers/infra/rustfs/rustfs.container.j2 new file mode 100644 index 0000000..3948878 --- /dev/null +++ b/config/services/containers/infra/rustfs/rustfs.container.j2 @@ -0,0 +1,33 @@ +[Quadlet] +DefaultDependencies=false + +[Unit] +Description=RustFS Object Storage +After=network-online.target +Wants=network-online.target + +[Container] +Image=docker.io/rustfs/rustfs:{{ version['containers']['rustfs'] }} +ContainerName=rustfs +HostName=rustfs + +PublishPort={{ services['rustfs']['ports']['http'] }}:9001/tcp + +Volume=%h/data/containers/rustfs/data:/data:rw + +Environment="TZ={{ timezone }}" +Environment="RUSTFS_ADDRESS=:9001" +Environment="RUSTFS_CONSOLE_ENABLE=false" +Environment="RUSTFS_ACCESS_KEY=rustfs" +Environment="RUSTFS_OBS_LOGGER_LEVEL=error" +Environment="RUSTFS_CORS_ALLOWED_ORIGINS=https://kaneo.ilnmors.com" + +Secret=RUSTFS_SECRET_KEY,type=env,target=RUSTFS_SECRET_KEY + +[Service] +Restart=always +RestartSec=10s +TimeoutStopSec=120 + +[Install] +WantedBy=default.target diff --git a/docs/archives/2026-08.tar.gz b/docs/archives/2026-08.tar.gz index af8c335..e05bd75 100644 Binary files a/docs/archives/2026-08.tar.gz and b/docs/archives/2026-08.tar.gz differ