From 664cf2956d889e785bbc4b0b3d250f7eb02cafdd Mon Sep 17 00:00:00 2001 From: il Date: Mon, 6 Apr 2026 23:33:44 +0900 Subject: [PATCH] 1.9.0 Release affine --- ansible/inventory/group_vars/all.yaml | 9 + ansible/playbooks/app/site.yaml | 9 + ansible/roles/app/handlers/main.yaml | 12 ++ .../roles/app/tasks/services/set_affine.yaml | 163 ++++++++++++++++++ .../infra/tasks/services/set_postgresql.yaml | 1 + config/secrets/secrets.yaml | 16 +- .../containers/app/affine/affine.container.j2 | 49 ++++++ .../app/manticore/manticore.container.j2 | 2 +- .../auth/authelia/config/authelia.yaml.j2 | 23 ++- .../common/caddy/etc/app/Caddyfile.j2 | 6 + .../common/caddy/etc/auth/Caddyfile.j2 | 9 + docs/services/app/affine.md | 119 +++++++++++++ 12 files changed, 414 insertions(+), 4 deletions(-) create mode 100644 ansible/roles/app/tasks/services/set_affine.yaml create mode 100644 config/services/containers/app/affine/affine.container.j2 create mode 100644 docs/services/app/affine.md diff --git a/ansible/inventory/group_vars/all.yaml b/ansible/inventory/group_vars/all.yaml index e476826..e492853 100644 --- a/ansible/inventory/group_vars/all.yaml +++ b/ansible/inventory/group_vars/all.yaml @@ -140,6 +140,14 @@ services: subuid: "100999" manticore: subuid: "100998" + affine: + domain: + public: "affine" + internal: "affine.app" + ports: + http: "3010" + redis: "6381" + manticore: "9308" version: packages: @@ -175,3 +183,4 @@ version: vikunja: "2.2.2" opencloud: "4.0.4" manticore: "25.0.0" + affine: "0.26.3" diff --git a/ansible/playbooks/app/site.yaml b/ansible/playbooks/app/site.yaml index fbe75e3..2f6819f 100644 --- a/ansible/playbooks/app/site.yaml +++ b/ansible/playbooks/app/site.yaml @@ -217,6 +217,15 @@ tags: ["site", "opencloud"] tags: ["site", "opencloud"] + - name: Set affine + ansible.builtin.include_role: + name: "app" + tasks_from: "services/set_affine" + apply: + tags: ["site", "affine"] + tags: ["site", "affine"] + + - name: Flush handlers right now ansible.builtin.meta: "flush_handlers" diff --git a/ansible/roles/app/handlers/main.yaml b/ansible/roles/app/handlers/main.yaml index 34148ce..12b0a48 100644 --- a/ansible/roles/app/handlers/main.yaml +++ b/ansible/roles/app/handlers/main.yaml @@ -87,3 +87,15 @@ changed_when: false listen: "notification_restart_opencloud" ignore_errors: true # noqa: ignore-errors + +- name: Restart affine + ansible.builtin.systemd: + name: "affine.service" + state: "restarted" + enabled: true + daemon_reload: true + scope: "user" + when: is_affine_init.stat.exists + changed_when: false + listen: "notification_restart_affine" + ignore_errors: true # noqa: ignore-errors diff --git a/ansible/roles/app/tasks/services/set_affine.yaml b/ansible/roles/app/tasks/services/set_affine.yaml new file mode 100644 index 0000000..db434b0 --- /dev/null +++ b/ansible/roles/app/tasks/services/set_affine.yaml @@ -0,0 +1,163 @@ +--- +- name: Set manticore service name + ansible.builtin.set_fact: + manticore_service: "affine" + +- name: Create manticore directory + ansible.builtin.file: + path: "{{ node['home_path'] }}/{{ item }}" + state: "directory" + owner: "{{ services['manticore']['subuid'] }}" + group: "svadmins" + mode: "0770" + loop: + - "data/containers/manticore" + - "data/containers/manticore/{{ manticore_service }}" + become: true + +- name: Deploy manticore.container file + ansible.builtin.template: + src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/manticore/manticore.container.j2" + dest: "{{ node['home_path'] }}/.config/containers/systemd/manticore_{{ manticore_service }}.container" + owner: "{{ ansible_user }}" + group: "svadmins" + mode: "0644" + register: "is_manticore_containerfile" + +- name: Enable (Restart) manticore.service + ansible.builtin.systemd: + name: "manticore_{{ manticore_service }}.service" + state: "restarted" + enabled: true + daemon_reload: true + scope: "user" + when: is_manticore_containerfile.changed # noqa: no-handler + +- name: Set redis service name + ansible.builtin.set_fact: + redis_service: "affine" + +- name: Create redis_affine directory + ansible.builtin.file: + path: "{{ node['home_path'] }}/{{ item }}" + state: "directory" + owner: "{{ services['redis']['subuid'] }}" + group: "svadmins" + mode: "0770" + loop: + - "containers/redis" + - "containers/redis/{{ redis_service }}" + - "containers/redis/{{ redis_service }}/data" + become: true + +- name: Deploy redis config file + ansible.builtin.template: + src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/redis/redis.conf.j2" + dest: "{{ node['home_path'] }}/containers/redis/{{ redis_service }}/redis.conf" + owner: "{{ ansible_user }}" + group: "svadmins" + mode: "0644" + register: "is_redis_conf" + +- name: Deploy redis container file + ansible.builtin.template: + src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/redis/redis.container.j2" + dest: "{{ node['home_path'] }}/.config/containers/systemd/redis_{{ redis_service }}.container" + owner: "{{ ansible_user }}" + group: "svadmins" + mode: "0644" + register: "is_redis_containerfile" + +- name: Enable (Restart) redis service + ansible.builtin.systemd: + name: "redis_{{ redis_service }}.service" + state: "restarted" + enabled: true + daemon_reload: true + scope: "user" + when: is_redis_conf.changed or is_redis_containerfile.changed # noqa: no-handler + +- name: Create affine directory + ansible.builtin.file: + path: "{{ node['home_path'] }}/{{ item }}" + state: "directory" + owner: "{{ ansible_user }}" + group: "svadmins" + mode: "0770" + loop: + - "data/containers/affine" + - "containers/affine" + - "containers/affine/ssl" + - "containers/affine/config" + +- name: Deploy root certificate + ansible.builtin.copy: + content: | + {{ hostvars['console']['ca']['root']['crt'] }} + dest: "{{ node['home_path'] }}/containers/affine/ssl/{{ root_cert_filename }}" + owner: "{{ ansible_user }}" + group: "svadmins" + mode: "0440" + notify: "notification_restart_affine" + no_log: true + +- name: Register secret value to podman secret + containers.podman.podman_secret: + name: "{{ item.name }}" + data: "{{ item.value }}" + state: "present" + force: true + loop: + - name: "AFFINE_PRIVATE_KEY" + value: "{{ hostvars['console']['affine']['secret_key'] }}" + - name: "AFFINE_DATABASE_URL" + value: "postgresql://affine:{{ hostvars['console']['postgresql']['password']['affine'] | urlencode | replace('/', '%2F') }}\ + @{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/affine_db?sslmode=verify-full&\ + sslrootcert=/etc/ssl/affine/{{ root_cert_filename }}" + notify: "notification_restart_affine" + no_log: true + +- name: Check data directory empty + ansible.builtin.stat: + path: "{{ node['home_path'] }}/data/containers/affine/.init" + register: "is_affine_init" + +- name: Initialize affine + when: not is_affine_init.stat.exists + block: + - name: Execute init command (Including pulling image) + containers.podman.podman_container: + name: "affine_init" + image: "ghcr.io/toeverything/affine:{{ version['containers']['affine'] }}" + command: ['sh', '-c', 'node ./scripts/self-host-predeploy.js'] + state: "started" + rm: true + detach: false + secrets: + - "AFFINE_DATABASE_URL,type=env,target=DATABASE_URL" + no_log: true + + - name: Create .init file + ansible.builtin.file: + path: "{{ node['home_path'] }}/data/containers/affine/.init" + state: "touch" + mode: "0644" + owner: "{{ ansible_user }}" + group: "svadmins" + +- name: Deploy affine.container file + ansible.builtin.template: + src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/affine/affine.container.j2" + dest: "{{ node['home_path'] }}/.config/containers/systemd/affine.container" + owner: "{{ ansible_user }}" + group: "svadmins" + mode: "0644" + notify: "notification_restart_affine" + +- name: Enable affine.service + ansible.builtin.systemd: + name: "affine.service" + state: "started" + enabled: true + daemon_reload: true + scope: "user" diff --git a/ansible/roles/infra/tasks/services/set_postgresql.yaml b/ansible/roles/infra/tasks/services/set_postgresql.yaml index 541613c..52e928a 100644 --- a/ansible/roles/infra/tasks/services/set_postgresql.yaml +++ b/ansible/roles/infra/tasks/services/set_postgresql.yaml @@ -10,6 +10,7 @@ - "immich" - "paperless" - "vikunja" + - "affine" - name: Create postgresql directory ansible.builtin.file: diff --git a/config/secrets/secrets.yaml b/config/secrets/secrets.yaml index 1eb8ba6..dd7b5ae 100644 --- a/config/secrets/secrets.yaml +++ b/config/secrets/secrets.yaml @@ -118,6 +118,7 @@ postgresql: immich: ENC[AES256_GCM,data:11jvxTKA/RL0DGL6y2/X092hnDohj6yTrYGK4IVojqBd1gCOBnDvUjgmx14=,iv:oBfHxsx9nxhyKY/WOuWfybxEX2bf+lHEtsaifFRS9lg=,tag:tAfkBdgQ8ZEkLIFcDICKDw==,type:str] paperless: ENC[AES256_GCM,data:6VBrBbjVoam7SkZCSvoBTdrfkUoDghdGTiBmFLul04X/okXOHeC5zusJffY=,iv:iZumcJ3TWwZD77FzYx8THwCqC+EbnXUBrEKuPh3zgV8=,tag:u2m8SppAdxZ/duNdpuS3oQ==,type:str] vikunja: ENC[AES256_GCM,data:/+wQdoFPTBG2elI9kZbAVWrHZ0DhMaYr4dc+2z9QNdb3TcDS2PEia0JuSAg=,iv:MViZTyUD8YqMmxSTWCQpJ30f/KQdQGOzPlRHHsQ8lAw=,tag:zov3POno139dkMxFDpj2gg==,type:str] + affine: ENC[AES256_GCM,data:XPXrcszsV06YqCJZ7CDqc4rCwqqNlbtLCFYfLAQ8jamLtft8L2UVrMA4WZo=,iv:vrWdBeckxB9tmEE628j4jhU+hSpE6TXYMGt0hh1Cg84=,tag:hlWwWUGht8NqWTZREMsa1Q==,type:str] #ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment] # # @@ -243,6 +244,17 @@ opencloud: #ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment] # # +#ENC[AES256_GCM,data:k55osvepVeB1RC5hZ4IF,iv:AlhfmWwn/DiSESWc+ULJSOLUhnrKAIfWr7MeiwV8qc8=,tag:hOgptwUcY6nVxPIhu+DYgw==,type:comment] +affine: + secret_key: ENC[AES256_GCM,data:LLX78DpYnha1JWhgw0sHLzIVq/oIzvT+nB7zgli4mroGbnt7WZaXCx34zKkYRwYj/+0L4IFFVdkzKtK5DO84SgFkS2Bk2iNdCMqIx80CpyiD8IWAcyRu5d6hh82PlgyxU80T/4nbLbIn0GLubPTTeUX8GC3VxRU=,iv:DnmvbhlygSHes0jAkIm4+WXMUQLzr4R4dNa33rO67v8=,tag:+2wlh+/ekiTyShWM4XBbUw==,type:str] + il: + password: ENC[AES256_GCM,data:4zxiQAzXTR+fraRjYT657BIwSqrih3lMPFFSibQdardRMjskAbuRYIQA6mo=,iv:ub3giRG9vCFSuwRXDazYTqWbjENzQUWR36290Kruj1o=,tag:C2Ixd2eTEgzBvUNCNBtJuA==,type:str] + oidc: + secret: ENC[AES256_GCM,data:eRDBrqLZR7MFLlsUwk7Wg7FzxDov7vJLIWQRuKq7vrXbPSJkMcy9jfG2rL4=,iv:UaSoi7gODXgjzihJIDVIdDHJcSAZNV8UKfGeM6YzxqI=,tag:cOUDblcMStP8E4fp+s1WRQ==,type:str] + hash: ENC[AES256_GCM,data:jE1CvFo+mjb/Xc3Ft5ky7on03vcnv79cw/5g/xaldXsv94VRrIjmfGMgHAj07r8j5mDpP34A5bYO1PSe9DYrwRcsXa9OUQuzm/8avFy9wVZDhBUUAGR+jiW1BP9hc6nmSpPVPtle+3sbqOB0ZMjXWwlcAcuknOtuhH1mzwmaDP9yf+M=,iv:CSSaXY/6MpHBMhPLUWPkabIeJ9zpZkcVjiEhxVF0zJM=,tag:f72ekkjJs7Qmh1K9wC8L9w==,type:str] +#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment] +# +# #ENC[AES256_GCM,data:T4Wtn49AAxPd2QUFTR+q,iv:bH5goGWBDqumAat9dUv2OwfCUJUpuVqncTMqMBZUXhI=,tag:G+W6hHA+yftQ+4RJpXrxHg==,type:comment] switch: password: ENC[AES256_GCM,data:qu0f9L7A0eFq/UCpaRs=,iv:W8LLOp3MSfd/+EfNEZNf91K8GgI5eUfVPoWTRES2C0Y=,tag:Q5FlAOfwqwJwPvd7k6i+0g==,type:str] @@ -272,7 +284,7 @@ sops: UmliaFNxVTBqRkI1QWJpWGpTRWxETW8KEY/8AfU73UOzCGhny1cNnd5dCNv7bHXt k+uyWPPi+enFkVaceSwMFrA66uaWWrwAj11sXEB7yzvGFPrnAGezjQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-04-03T08:39:32Z" - mac: ENC[AES256_GCM,data:Lcv2BK6nhGhMrWBfcTXC0zzi1cAPxCU/Rwlxck1Uz6tN6b1SQi0Xq5LcmXUOFhFAYNg7Bd6njspYzdJ1MRI85bR/RKye7XcY+Nmdk8ZWDouxd8a8zKsWDCPXbLbIn1/ZiKZlS0Rd46xGVv8nbyxq0smp34RAzCzkxCGjob/LcF0=,iv:7wn7kfC9aSOAELHKaPby8nCVy3H++tY9bkV+STWS1vo=,tag:eRvsZ+L1+lUAdtHOrCR0LQ==,type:str] + lastmodified: "2026-04-06T14:32:22Z" + mac: ENC[AES256_GCM,data:OFiSsBBAzOUoOwnAwhaplQQ8k2kUo+Avzk475BpaiOJoaB2c0wsJ3siP15tcLMrav4Qw8boZFo64v+rjdMoNI/MRo1EOYWNr1ZRMqHzwmQeaiMH2QcfoRZ0oLqrn5ekQztuPR9ULjDYZb63AwVGmzseUf4R5lGXgdgN5tjU/pH4=,iv:hqzDwryMuJ7JnkBazzDSznw05m7k61Sk61aPgO3JtpU=,tag:Lhhlgwy+YuQ1S0hkbsjecg==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1 diff --git a/config/services/containers/app/affine/affine.container.j2 b/config/services/containers/app/affine/affine.container.j2 new file mode 100644 index 0000000..8ff97e4 --- /dev/null +++ b/config/services/containers/app/affine/affine.container.j2 @@ -0,0 +1,49 @@ +[Quadlet] +DefaultDependencies=false + +[Unit] +Description=AFFiNE + +After=redis_affine.service manticore_affine.service +Wants=redis_affine.service manticore_affine.service + +[Container] +Image=ghcr.io/toeverything/affine:{{ version['containers']['affine'] }} +ContainerName=affine +HostName=affine + +PublishPort={{ services['affine']['ports']['http'] }}:3010 + +Volume=%h/data/containers/affine:/root/.affine/storage:rw +Volume=%h/containers/affine/config:/root/.affine/config +Volume=%h/containers/affine/ssl:/etc/ssl/affine:ro + +# General +Environment="TZ=Asia/Seoul" +## OIDC callback URIs +Environment="AFFINE_SERVER_HOST={{ services['affine']['domain']['public'] }}.{{ domain['public'] }}" +Environment="AFFINE_SERVER_EXTERNAL_URL=https://{{ services['affine']['domain']['public'] }}.{{ domain['public'] }}" +Environment="AFFINE_SERVER_HTTPS=true" + +Secret=AFFINE_PRIVATE_KEY,type=env + +# Database +Secret=AFFINE_DATABASE_URL,type=env,target=DATABASE_URL +## Enable AI function: this needs pgvector + +# Redis +Environment="REDIS_SERVER_HOST=host.containers.internal" +Environment="REDIS_SERVER_PORT={{ services['affine']['ports']['redis'] }}" + +# Indexer +Environment="AFFINE_INDEXER_ENABLED=true" +Environment="AFFINE_INDEXER_SEARCH_ENDPOINT=http://host.containers.internal:{{ services['affine']['ports']['manticore'] }}" + +[Service] +ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }} +Restart=always +RestartSec=10s +TimeoutStopSec=120 + +[Install] +WantedBy=default.target diff --git a/config/services/containers/app/manticore/manticore.container.j2 b/config/services/containers/app/manticore/manticore.container.j2 index 89912b5..ea3b55c 100644 --- a/config/services/containers/app/manticore/manticore.container.j2 +++ b/config/services/containers/app/manticore/manticore.container.j2 @@ -2,7 +2,7 @@ DefaultDependencies=false [Unit] -Description=Manticore +Description=Manticore - {{ manticore_service }} [Container] Image=docker.io/manticoresearch/manticore:{{ version['containers']['manticore'] }} diff --git a/config/services/containers/auth/authelia/config/authelia.yaml.j2 b/config/services/containers/auth/authelia/config/authelia.yaml.j2 index 5279f0e..494d3ec 100644 --- a/config/services/containers/auth/authelia/config/authelia.yaml.j2 +++ b/config/services/containers/auth/authelia/config/authelia.yaml.j2 @@ -110,7 +110,7 @@ identity_providers: key: {{ secret "/run/secrets/AUTHELIA_JWKS_RS256" | mindent 10 "|" | msquote }} - algorithm: 'ES256' use: 'sig' - key: {{ secret "/run/secrets/AUTHELIA_JWKS_ES256" | mindent 10 "|" | msquote }}{% endraw %} + key: {{ secret "/run/secrets/AUTHELIA_JWKS_ES256" | mindent 10 "|" | msquote }}{% endraw %} clients: # https://www.authelia.com/integration/openid-connect/clients/synology-dsm/ - client_id: 'dsm' @@ -344,3 +344,24 @@ identity_providers: access_token_signed_response_alg: 'RS256' userinfo_signed_response_alg: 'none' token_endpoint_auth_method: 'none' + # https://docs.affine.pro/self-host-affine/administer/oauth-2-0 + - client_id: 'affine' + client_name: 'Affine' + client_secret: '{{ hostvars['console']['affine']['oidc']['hash'] }}' + public: false + authorization_policy: 'one_factor' + require_pkce: false + pkce_challenge_method: '' + redirect_uris: + - 'https://{{ services['affine']['domain']['public'] }}.{{ domain['public'] }}/oauth/callback' + scopes: + - 'openid' + - 'profile' + - 'email' + response_types: + - 'code' + grant_types: + - 'authorization_code' + access_token_signed_response_alg: 'none' + userinfo_signed_response_alg: 'none' + token_endpoint_auth_method: 'client_secret_post' diff --git a/config/services/containers/common/caddy/etc/app/Caddyfile.j2 b/config/services/containers/common/caddy/etc/app/Caddyfile.j2 index 98182fb..da5699b 100644 --- a/config/services/containers/common/caddy/etc/app/Caddyfile.j2 +++ b/config/services/containers/common/caddy/etc/app/Caddyfile.j2 @@ -71,3 +71,9 @@ header_up Host {http.request.header.X-Forwarded-Host} } } +{{ services['affine']['domain']['internal'] }}.{{ domain['internal'] }} { + import private_tls + reverse_proxy host.containers.internal:{{ services['affine']['ports']['http'] }} { + header_up Host {http.request.header.X-Forwarded-Host} + } +} diff --git a/config/services/containers/common/caddy/etc/auth/Caddyfile.j2 b/config/services/containers/common/caddy/etc/auth/Caddyfile.j2 index eb2eb13..b01e762 100644 --- a/config/services/containers/common/caddy/etc/auth/Caddyfile.j2 +++ b/config/services/containers/common/caddy/etc/auth/Caddyfile.j2 @@ -127,6 +127,15 @@ } } } +{{ services['affine']['domain']['public'] }}.{{ domain['public'] }} { + import crowdsec_log + route { + crowdsec + reverse_proxy https://{{ services['affine']['domain']['internal'] }}.{{ domain['internal'] }} { + header_up Host {http.reverse_proxy.upstream.host} + } + } +} # Internal domain {{ node['name'] }}.{{ domain['internal'] }} { diff --git a/docs/services/app/affine.md b/docs/services/app/affine.md new file mode 100644 index 0000000..70bab14 --- /dev/null +++ b/docs/services/app/affine.md @@ -0,0 +1,119 @@ +# affine + +## Prerequisite + +### Create database + +- Create the password with `openssl rand -base64 32` + - Save this value in secrets.yaml in `postgresql.password.affine` + - Access infra server to create affine_db with `podman exec -it postgresql psql -U postgres` + +```SQL +CREATE USER affine WITH PASSWORD 'postgresql.password.affine'; +CREATE DATABASE affine_db; +ALTER DATABASE affine_db OWNER TO affine; +\connect affine_db +CREATE EXTENSION IF NOT EXISTS vector; +\dx +-- Check the extension is activated with `\dx` +-- postgresql image is built with `pgvector` and `vectorchord` already +``` + +### Create oidc secret and hash + +- Create the secret with `openssl rand -base64 32` +- access to auth vm + - `podman exec -it authelia sh` + - `authelia crypto hash generate pbkdf2 --password 'affine.oidc.secret'` +- Save this value in secrets.yaml in `affine.oidc.secret` and `affine.oidc.hash` + +### Create secret key value + +- Create the secret with `openssl genpkey -algorithm ed25519 -outform PEM` + - Save this value in secrets.yaml in `affine.secret_key` + +### Create admin password + +- Create the secret with `openssl rand -base64 32` +- Save this value in secrets.yaml in `affine.il.password` + +### Add postgresql dump backup list + +- [set_postgresql.yaml](../../../ansible/roles/infra/tasks/services/set_postgresql.yaml) + +```yaml +- name: Set connected services list + ansible.builtin.set_fact: + connected_services: + - ... + - "affine" +``` + +## Configuration + +### About quota + +- Workspace seats for family: below 10 seats + - If 10 members is needed, then buy a licence +- Workspace storage quota + - They are planning unlimited storage quota, not now. Now they have 100GB quota for sync. + +### Following feature which will be applied in this system + +- Linking local caldav vaikal or radicale ... +- Apply AI function with API + +### Access to affine + +- https://affine.ilnmors.com + - Getting started + - admin name + - admin E-mail + - admin password + - Initial setting allows only 32 digit password, now just set temporary password + +### Server configuration +- https://affine.ilnmors.com/admin + +#### Server + +- A recognizable name for the server. Will be shown when connected with AFFiNE Desktop. + - Ilnmors + +#### Auth + +- [ ] Whether allow new registrations +- [x] Whether allow new registration via configured oauth +- Minimum length requirement of password: 8 +- Maximum length requirement of password: 50 +- save + +#### Oauth configuration + +```ini +# These options are required +## OIDC callback URIs +Environment="AFFINE_SERVER_HOST={{ services['affine']['domain']['public'] }}.{{ domain['public'] }}" +Environment="AFFINE_SERVER_EXTERNAL_URL=https://{{ services['affine']['domain']['public'] }}.{{ domain['public'] }}" +Environment="AFFINE_SERVER_HTTPS=true" +``` +- OIDC Oauth provider config + +```json +{ + "clientId":"affine", + "clientSecret":"affine.oidc.secret", + "issuer":"https://authelia.ilnmors.com", + "args":{ + "scope": "openid profile email" + } +} +``` + +- save + +#### Flags + +- [ ] Whether allow guest users to create demo workspaces +- save +