Compare commits

...

6 Commits

Author SHA1 Message Date
il ba8b312bf2 feat(btrfs): update btrfs scrub service and timer on app vm 2026-05-06 08:15:53 +09:00
il 6fcedd9162 feat(collabora): release collabora
deployment note:
- link to nextcloud
- document opening is verified (including korean fonts)
2026-05-05 21:20:31 +09:00
il 6ca4f61d50 docs(nextcloud): update security warning decisions and background job annotation
update notes:
- trusted_proxies warning
- HSTS option warning
- background job mode annotation
2026-05-05 20:09:00 +09:00
il 15c09cb899 docs(nextcloud): update how to disable auto generated contacts from nextcloud account 2026-05-03 12:05:11 +09:00
il 880857a70a fix(crowdsec): update parser 'crowdsecurity/nextcloud-whitelist'
update note:
- deprecate custom whitelist expression
- apply 'crowdsecurity/nextcloud-whitelist' parser
2026-05-03 07:19:59 +09:00
il 70bf539546 docs(issues): fix crowdsec whitelist regex to whitelist expressions 2026-05-02 20:40:10 +09:00
20 changed files with 202 additions and 20 deletions
+8
View File
@@ -156,6 +156,13 @@ services:
http: "8002"
redis: "6382"
subuid: "100032"
collabora:
domain:
public: "collabora"
internal: "collabora.app"
ports:
http: "9980"
subuid: "101000"
version:
packages:
@@ -193,3 +200,4 @@ version:
manticore: "25.0.0"
affine: "0.26.3"
nextcloud: "33.0.3"
collabora: "25.04.9.4.1"
+7
View File
@@ -233,6 +233,13 @@
tags: ["site", "nextcloud"]
tags: ["site", "nextcloud"]
- name: Set collabora
ansible.builtin.include_role:
name: "app"
tasks_from: "services/set_collabora"
apply:
tags: ["site", "collabora"]
tags: ["site", "collabora"]
- name: Flush handlers right now
ansible.builtin.meta: "flush_handlers"
+11
View File
@@ -111,3 +111,14 @@
changed_when: false
listen: "notification_restart_nextcloud"
ignore_errors: true # noqa: ignore-errors
- name: Restart collabora
ansible.builtin.systemd:
name: "collabora.service"
state: "restarted"
enabled: true
scope: "user"
daemon_reload: true
changed_when: false
listen: "notification_restart_collabora"
ignore_errors: true # noqa: ignore-errors
@@ -68,3 +68,23 @@
group: "svadmins"
mode: "0770"
become: true
- name: Deploy btrfs scrub service and timer
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/app/btrfs/{{ item }}.j2"
dest: "/etc/systemd/system/{{ item }}"
owner: "root"
group: "root"
mode: "0644"
loop:
- "btrfs-scrub.service"
- "btrfs-scrub.timer"
become: true
- name: Enable auto btrfs scrub
ansible.builtin.systemd:
name: "btrfs-scrub.timer"
state: "started"
enabled: true
daemon_reload: true
become: true
@@ -0,0 +1,17 @@
---
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/collabora/collabora.container.j2"
dest: "{{ node['home_path'] }}/.config/containers/systemd/collabora.container"
owner: "{{ ansible_user }}"
group: "svadmins"
mode: "0644"
notify: "notification_restart_collabora"
- name: Enable collabora.service
ansible.builtin.systemd:
name: "collabora.service"
state: "started"
enabled: true
daemon_reload: true
scope: "user"
@@ -36,10 +36,15 @@
ansible.builtin.set_fact:
acquisd_list:
fw:
collection: "crowdsecurity/suricata"
collection:
- "crowdsecurity/suricata"
parser: []
config: "suricata.yaml"
auth:
collection: "crowdsecurity/caddy"
collection:
- "crowdsecurity/caddy"
parser:
- "crowdsecurity/nextcloud-whitelist"
config: "caddy.yaml"
- name: Deploy crowdsec-update service files
@@ -181,7 +186,8 @@
block:
- name: Install crowdsec collection
ansible.builtin.command:
cmd: "cscli collections install {{ acquisd_list[node['name']]['collection'] }}"
cmd: "cscli collections install {{ item }}"
loop: "{{ acquisd_list[node['name']]['collection'] }}"
become: true
changed_when: "'overwrite' not in is_collection_installed.stderr"
failed_when:
@@ -189,6 +195,17 @@
- "'already installed' not in is_collection_installed.stderr"
register: "is_collection_installed"
- name: Install crowdsec parser
ansible.builtin.command:
cmd: "cscli parsers install {{ item }}"
loop: "{{ acquisd_list[node['name']]['parser'] }}"
become: true
changed_when: "'overwrite' not in is_parser_installed.stderr"
failed_when:
- is_parser_installed.rc != 0
- "'already installed' not in is_parser_installed.stderr"
register: "is_parser_installed"
- name: Create crowdsec acquis.d directory
ansible.builtin.file:
path: "/etc/crowdsec/acquis.d"
@@ -0,0 +1,25 @@
[Quadlet]
DefaultDependencies=false
[Unit]
Description=Collabora Online
[Container]
Image=docker.io/collabora/code:{{ version['containers']['collabora'] }}
ContainerName=collabora
HostName=collabora
PublishPort={{ services['collabora']['ports']['http'] }}:9980/tcp
Environment="TZ=Asia/Seoul"
Environment="aliasgroup1=https://{{ services['nextcloud']['domain']['public'] }}.{{ domain['public'] }}"
# Environment="aliasgroup2=other_server_FQDN"
Environment="extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:server_name={{ services['collabora']['domain']['public'] }}.{{ domain['public'] }} --o:admin_console.enable=false"
[Service]
Restart=always
RestartSec=10s
TimeoutStopSec=120
[Install]
WantedBy=default.target
@@ -1,4 +1,5 @@
<?php
$CONFIG = [
// Background jobs mode is auto-detected as 'cron' when nextcloud-cron.timer runs cron.php via CLI. No explicit config required.
'maintenance_window_start' => 18,
];
@@ -83,3 +83,9 @@
header_up Host {http.request.header.X-Forwarded-Host}
}
}
{{ services['collabora']['domain']['internal'] }}.{{ domain['internal'] }} {
import private_tls
reverse_proxy host.containers.internal:{{ services['collabora']['ports']['http'] }} {
header_up Host {http.request.header.X-Forwarded-Host}
}
}
@@ -145,6 +145,15 @@
}
}
}
{{ services['collabora']['domain']['public'] }}.{{ domain['public'] }} {
import crowdsec_log
route {
crowdsec
reverse_proxy https://{{services['collabora']['domain']['internal'] }}.{{ domain['internal'] }} {
header_up Host {http.reverse_proxy.upstream.host}
}
}
}
# Internal domain
{{ node['name'] }}.{{ domain['internal'] }} {
@@ -0,0 +1,10 @@
[Unit]
Description=BTRFS auto scrub
ConditionPathIsMountPoint={{ node['home_path'] }}/data
RequiresMountsFor={{ node['home_path'] }}/data
[Service]
Type=oneshot
ExecStart=/usr/bin/btrfs scrub start -Bd {{ node['home_path'] }}/data
Nice=19
IOSchedulingClass=idle
@@ -0,0 +1,10 @@
[Unit]
Description=Monthly BTRFS auto scrub
[Timer]
OnCalendar=*-*-01 04:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
@@ -18,9 +18,4 @@ whitelist:
- "evt.Meta.target_fqdn == '{{ services['immich']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/api/assets/' && evt.Meta.http_path contains '/thumbnail'"
# opencloud chunk request false positive
- "evt.Meta.target_fqdn == '{{ services['opencloud']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/js/chunks/'"
# nextcloud chunk request false positive (crowdsecurity/http-crawl-non_statics)
- "evt.Meta.target_fqdn == '{{ services['nextcloud']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/apps/viewer/js/'"
- "evt.Meta.target_fqdn == '{{ services['nextcloud']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/dist/'"
# nextcloud upload directory request 404 error false positive (crowdsecurity/http-probing)
- "evt.Meta.target_fqdn == '{{ services['nextcloud']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/remote.php/dav/files/'"
{% endif %}
+1 -1
View File
@@ -26,7 +26,7 @@
- Access to fw
- Check the ban list with `sudo cscli alerts list`
- Read the ban case with `sudo cscli alerts inspect $NUMBER`
- Add regex on whitelist
- Add expressions on whitelist
- evt.Meta.target_fqdn == '{{ services['actualbudget']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/data/migrations/'
- Delete false positive decision
- Check false positive decision with `sudo cscli decision list`
+2 -2
View File
@@ -25,8 +25,8 @@
- Access to fw
- Check the ban list with `sudo cscli alerts list`
- Read the ban case with `sudo cscli alerts inspect $NUMBER`
- Add regex on whitelist
- evt.Meta.target_fqdn == 'Immich.ilnmors.com' && evt.Meta.http_path contains '/api/assets/' && evt.Meta.http_path contains '/thumbnail'
- Add expressions on whitelist
- evt.Meta.target_fqdn == '{{ services['immich']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/api/assets/' && evt.Meta.http_path contains '/thumbnail'
- Delete false positive decision
- Check false positive decision with `sudo cscli decision list`
- Delete false positive decision with `sudo cscli decision delete --id $ID`
+1 -1
View File
@@ -25,7 +25,7 @@
- Access to fw
- Check the ban list with `sudo cscli alerts list`
- Read the ban case with `sudo cscli alerts inspect $NUMBER`
- Add regex on whitelist
- Add expressions on whitelist
- evt.Meta.target_fqdn == '{{ services['opencloud']['domain']['public'] }}.{{ domain['public'] }}' && evt.Meta.http_path contains '/js/chunks/'
- Delete false positive decision
- Check false positive decision with `sudo cscli decision list`
+6 -6
View File
@@ -14,18 +14,18 @@
- fw ban users' IP address.
## Reason
- Nextcloud uses chunks for actions, and uploading and downloading
- chunks on '/apps/viewer/js', '/dist/'
- `crowdsecurity/http-crawl-non_statics`
- Nextcloud keeps checking directory which is uploading
- upload directory '/remote.php/dav/files/'
- `crowdsecurity/http-probing`
- Nextcloud has a lot of workflows which can be caught from crowdsec
## Timeline
- 2026-05-02: Release nextcloud
- 2026-05-02: Find the false positive case, and add whitelist
- 2026-05-03: Install crowdsecurity/nextcloud-whitelist parser
- 2026-05-03: Make previous expressions annotation
## Solution
- Install crowdsecurity/nextcloud-whitelist on auth node
### Deprecated solution
- Access to fw
- Check the ban list with `sudo cscli alerts list`
- Read the ban case with `sudo cscli alerts inspect $NUMBER`
+28
View File
@@ -0,0 +1,28 @@
# Collabora office
## Prerequisite
- Nothing
## Configuration
- Admin page is disabled by Environment options
- `admin_console.enable=false`
### Link to nextcloud
- https://nextcloud.ilnmors.com
- login with admin account
- Profile: Apps: Nextcloud Office
- Check installation and enable
- Profile: Administration Settings: Nextcloud Office: Your own server
- http://host.containers.internal:9980 (collabora container port)
- Public FQDN is set automatically
- save
- Files
- Verify document opening (verified)
- The basic font `Noto Sans KR` exists
- Korean is presented very well
+19 -1
View File
@@ -61,7 +61,7 @@ ALTER DATABASE nextcloud_db OWNER TO nextcloud;
- Mail
- Nextcloud Office
### Configuration
### OIDC and DB Configuration
```bash
podman exec -u www-data nextcloud php occ user_oidc:provider Authelia \
@@ -86,3 +86,21 @@ podman exec -u www-data nextcloud php occ db:add-missing-primary-keys
- Profile: Accounts:
- allocate admin group for admin users
#### Disable System addressbook expose
- Profile: Administration Settings: Groupware: System Address Book
- Disable `Enable system address book` option
## Security warning in Nextcloud (ignored)
### trusted_proxies option
- Nextcloud wants admin to set `trusted_proxies` via forwarded ip header.
- In current system, app vm explicitly prevents access the nextcloud container outside of vm.
- trusted_proxy ip address will be definitely 169.254.1.2 (caddy's APIPA address which is used in PASTA network), so it is not distinguished from other containers.
- Therefore, it doesn't need to be set.
### HSTS option
- This system is already main - sidecar reverse proxy system, and main proxy automatically changes http requests to https request (Caddyfile listens https).
- main - sidecar communication is also on https via internal certificate.
- Therefore, it doesn't need to be set.
+1 -1
View File
@@ -123,7 +123,7 @@
- [x] OpenCloud
- [x] affine \(Notion substitution\)
- [x] Nextcloud \(Use nextcloud as CalDAV and CardDav, kanban and todo\)
- [ ] Collabora office
- [x] Collabora office \(Link to Nextcloud, it works well\)
- WriteFreely
- MediaCMS
- Funkwhale