Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
@@ -0,0 +1,18 @@
---
document this deployment example in: docs/qsfera/deployment/qsfera_full.md
---
# КуСфера WOPI Deployment Example
This deployment example is documented in two locations for different audiences:
* In the [Admin Documentation](https://docs.qsfera.eu/docs/admin/intro)\
Providing two variants using detailed configuration step by step guides:\
[Docker Compose Setup](https://docs.qsfera.eu/docs/admin/getting-started/container/docker-compose) and [Docker Compose Local](https://docs.qsfera.eu/docs/admin/getting-started/container/docker-compose-local).\
Note that these examples use LetsEncrypt certificates and are intended for production use.
* In the [Developer Documentation](https://docs.qsfera.eu/docs/dev/intro)\
Providing details which are more developer focused. This description can also be used when deviating from the default.\
Note that this examples uses self signed certificates and is intended for testing purposes.
@@ -0,0 +1,31 @@
---
services:
qsfera:
environment:
ANTIVIRUS_SCANNER_TYPE: "clamav"
ANTIVIRUS_CLAMAV_SOCKET: "/var/run/clamav/clamd.sock"
ANTIVIRUS_MAX_SCAN_SIZE_MODE: ${ANTIVIRUS_MAX_SCAN_SIZE_MODE:-partial}
ANTIVIRUS_MAX_SCAN_SIZE: ${ANTIVIRUS_MAX_SCAN_SIZE:-100MB}
# the antivirus service needs manual startup, see .env and qsfera.yaml for START_ADDITIONAL_SERVICES
# configure the antivirus service
POSTPROCESSING_STEPS: "virusscan"
# PROXY_TLS is set to "false", the download url has no https
STORAGE_USERS_DATA_GATEWAY_URL: http://qsfera:9200/data
volumes:
- "clamav-socket:/var/run/clamav"
clamav:
image: clamav/clamav:${CLAMAV_DOCKER_TAG:-latest}
# release notes: https://blog.clamav.net
networks:
qsfera-net:
volumes:
- "clamav-socket:/tmp"
- "clamav-db:/var/lib/clamav"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
clamav-socket:
clamav-db:
@@ -0,0 +1,87 @@
---
services:
traefik:
networks:
qsfera-net:
aliases:
- ${COLLABORA_DOMAIN:-collabora.qsfera.test}
- ${WOPISERVER_DOMAIN:-wopiserver.qsfera.test}
qsfera:
environment:
# make collabora the secure view app
FRONTEND_APP_HANDLER_SECURE_VIEW_APP_ADDR: qsfera.api.collaboration.CollaboraOnline
GRAPH_AVAILABLE_ROLES: "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5,a8d5fe5e-96e3-418d-825b-534dbdf22b99,fb6c3e19-e378-47e5-b277-9732f9de6e21,58c63c02-1d89-4572-916a-870abc5a1b7d,2d00ce52-1fc2-4dbc-8b95-a73b73395f5a,1c996275-f1c9-4e71-abdf-a42f6495e960,312c0871-5ef7-4b3a-85b6-0e4074c64049,aa97fe03-7980-45ac-9e50-b325749fd7e6"
collaboration:
image: ${OC_DOCKER_IMAGE:-qsfera/qsfera-rolling}:${OC_DOCKER_TAG:-latest}
networks:
qsfera-net:
depends_on:
qsfera:
condition: service_started
collabora:
condition: service_healthy
entrypoint:
- /bin/sh
command: [ "-c", "qsfera collaboration server" ]
environment:
COLLABORATION_GRPC_ADDR: 0.0.0.0:9301
COLLABORATION_HTTP_ADDR: 0.0.0.0:9300
MICRO_REGISTRY: "nats-js-kv"
MICRO_REGISTRY_ADDRESS: "qsfera:9233"
COLLABORATION_WOPI_SRC: https://${WOPISERVER_DOMAIN:-wopiserver.qsfera.test}
COLLABORATION_APP_NAME: "CollaboraOnline"
COLLABORATION_APP_PRODUCT: "Collabora"
COLLABORATION_APP_ADDR: https://${COLLABORA_DOMAIN:-collabora.qsfera.test}
COLLABORATION_APP_ICON: https://${COLLABORA_DOMAIN:-collabora.qsfera.test}/favicon.ico
COLLABORATION_APP_INSECURE: "${INSECURE:-true}"
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}"
COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info}
OC_URL: https://${OC_DOMAIN:-cloud.qsfera.test}
volumes:
# configure the .env file to use own paths instead of docker internal volumes
- ${OC_CONFIG_DIR:-qsfera-config}:/etc/qsfera
labels:
- "traefik.enable=true"
- "traefik.http.routers.collaboration.entrypoints=https"
- "traefik.http.routers.collaboration.rule=Host(`${WOPISERVER_DOMAIN:-wopiserver.qsfera.test}`)"
- "traefik.http.routers.collaboration.tls.certresolver=http"
- "traefik.http.routers.collaboration.service=collaboration"
- "traefik.http.services.collaboration.loadbalancer.server.port=9300"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
collabora:
image: collabora/code:25.04.2.1.1
# release notes: https://www.collaboraonline.com/release-notes/
networks:
qsfera-net:
environment:
aliasgroup1: https://${WOPISERVER_DOMAIN:-wopiserver.qsfera.test}:443
DONT_GEN_SSL_CERT: "YES"
extra_params: |
--o:ssl.enable=${COLLABORA_SSL_ENABLE:-true} \
--o:ssl.ssl_verification=${COLLABORA_SSL_VERIFICATION:-true} \
--o:ssl.termination=true \
--o:welcome.enable=false \
--o:net.frame_ancestors=${OC_DOMAIN:-cloud.qsfera.test}
username: ${COLLABORA_ADMIN_USER:-admin}
password: ${COLLABORA_ADMIN_PASSWORD:-admin}
cap_add:
- MKNOD
labels:
- "traefik.enable=true"
- "traefik.http.routers.collabora.entrypoints=https"
- "traefik.http.routers.collabora.rule=Host(`${COLLABORA_DOMAIN:-collabora.qsfera.test}`)"
- "traefik.http.routers.collabora.tls.certresolver=http"
- "traefik.http.routers.collabora.service=collabora"
- "traefik.http.services.collabora.loadbalancer.server.port=9980"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
entrypoint: ['/bin/bash', '-c']
command: ['coolconfig generate-proof-key && /start-collabora-online.sh']
healthcheck:
test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/9980 && echo -e 'GET /hosting/discovery HTTP/1.1\r\nHost: localhost:9980\r\n\r\n' >&3 && head -n 1 <&3 | grep '200 OK'"]
@@ -0,0 +1,63 @@
{
"clientId": "КуСфераAndroid",
"name": "КуСфера Android App",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"oc://android.qsfera.eu"
],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"post.logout.redirect.uris": "oc://android.qsfera.eu",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"profile",
"roles",
"groups",
"basic",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}
@@ -0,0 +1,64 @@
{
"clientId": "КуСфераDesktop",
"name": "КуСфера Desktop Client",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"http://127.0.0.1",
"http://localhost"
],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"post.logout.redirect.uris": "+",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"profile",
"roles",
"groups",
"basic",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}
@@ -0,0 +1,63 @@
{
"clientId": "КуСфераIOS",
"name": "КуСфера iOS App",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"oc://ios.qsfera.eu"
],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"post.logout.redirect.uris": "oc://ios.qsfera.eu",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"profile",
"roles",
"groups",
"basic",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}
@@ -0,0 +1,66 @@
{
"clientId": "Cyberduck",
"name": "Cyberduck",
"description": "File transfer utility client",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"x-cyberduck-action:oauth",
"x-mountainduck-action:oauth"
],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"oauth2.device.authorization.grant.enabled": "false",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"oidc.ciba.grant.enabled": "false",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"profile",
"roles",
"groups",
"basic",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}
@@ -0,0 +1,74 @@
{
"clientId": "web",
"name": "КуСфера Web App",
"description": "",
"rootUrl": "{{OC_URL}}",
"adminUrl": "{{OC_URL}}",
"baseUrl": "",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": [
"{{OC_URL}}/",
"{{OC_URL}}/oidc-callback.html",
"{{OC_URL}}/oidc-silent-redirect.html"
],
"webOrigins": [
"{{OC_URL}}"
],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"saml.force.post.binding": "false",
"saml.multivalued.roles": "false",
"saml.encrypt": "false",
"post.logout.redirect.uris": "+",
"oauth2.device.authorization.grant.enabled": "false",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"exclude.session.state.from.auth.response": "false",
"oidc.ciba.grant.enabled": "false",
"backchannel.logout.url": "{{OC_URL}}/backchannel_logout",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"profile",
"roles",
"groups",
"basic",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
],
"access": {
"view": true,
"configure": true,
"manage": true
}
}
@@ -0,0 +1,8 @@
#!/bin/bash
printenv
# replace qsfera domain and LDAP password in keycloak realm import
mkdir /opt/keycloak/data/import
sed -e "s/cloud.qsfera.test/${OC_DOMAIN}/g" -e "s/ldap-admin-password/${LDAP_ADMIN_PASSWORD:-admin}/g" /opt/keycloak/data/import-dist/qsfera-realm.json > /opt/keycloak/data/import/qsfera-realm.json
# run original docker-entrypoint
/opt/keycloak/bin/kc.sh "$@"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,9 @@
#!/bin/bash
printenv
if [ ! -f /opt/bitnami/openldap/share/openldap.key ]
then
openssl req -x509 -newkey rsa:4096 -keyout /opt/bitnami/openldap/share/openldap.key -out /opt/bitnami/openldap/share/openldap.crt -sha256 -days 365 -batch -nodes
fi
# run original docker-entrypoint
/opt/bitnami/scripts/openldap/entrypoint.sh "$@"
@@ -0,0 +1,24 @@
dn: dc=qsfera,dc=eu
objectClass: organization
objectClass: dcObject
dc: qsfera
o: qsfera
dn: ou=users,dc=qsfera,dc=eu
objectClass: organizationalUnit
ou: users
dn: cn=admin,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: person
cn: admin
sn: admin
uid: ldapadmin
dn: ou=groups,dc=qsfera,dc=eu
objectClass: organizationalUnit
ou: groups
dn: ou=custom,ou=groups,dc=qsfera,dc=eu
objectClass: organizationalUnit
ou: custom
@@ -0,0 +1,84 @@
# Start dn with uid (user identifier / login), not cn (Firstname + Surname)
dn: uid=alan,ou=users,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: alan
givenName: Alan
sn: Turing
cn: alan
displayName: Alan Turing
description: An English mathematician, computer scientist, logician, cryptanalyst, philosopher and theoretical biologist. He was highly influential in the development of theoretical computer science, providing a formalisation of the concepts of algorithm and computation with the Turing machine.
mail: alan@example.org
userPassword:: e1NTSEF9Y2ZMdVlqMTBDUFpLWE44VC9mQ0FzYnFHQmtyZExJeGg=
dn: uid=lynn,ou=users,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: lynn
givenName: Lynn
sn: Conway
cn: lynn
displayName: Lynn Conway
description: An American computer scientist, electrical engineer, and transgender activist.
mail: lynn@example.org
userPassword:: e1NTSEF9Y2ZMdVlqMTBDUFpLWE44VC9mQ0FzYnFHQmtyZExJeGg=
dn: uid=mary,ou=users,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: mary
givenName: Mary
sn: Kenneth Keller
cn: mary
displayName: Mary Kenneth Keller
description: Mary Kenneth Keller of the Sisters of Charity of the Blessed Virgin Mary was a pioneer in computer science.
mail: mary@example.org
userPassword:: e1NTSEF9Y2ZMdVlqMTBDUFpLWE44VC9mQ0FzYnFHQmtyZExJeGg=
dn: uid=margaret,ou=users,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: margaret
givenName: Margaret
sn: Hamilton
cn: margaret
displayName: Margaret Hamilton
description: A director of the Software Engineering Division of the MIT Instrumentation Laboratory, which developed on-board flight software for NASA's Apollo program.
mail: margaret@example.org
userPassword:: e1NTSEF9Y2ZMdVlqMTBDUFpLWE44VC9mQ0FzYnFHQmtyZExJeGg=
dn: uid=dennis,ou=users,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: dennis
givenName: Dennis
sn: Ritchie
cn: dennis
displayName: Dennis Ritchie
description: American computer scientist. He created the C programming language and the Unix operating system and B language with long-time colleague Ken Thompson.
mail: dennis@example.org
userPassword:: e1NTSEF9Y2ZMdVlqMTBDUFpLWE44VC9mQ0FzYnFHQmtyZExJeGg=
dn: uid=admin,ou=users,dc=qsfera,dc=eu
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
uid: admin
givenName: Admin
sn: Admin
cn: admin
displayName: Admin
description: An admin for this КуСфера instance.
mail: admin@example.org
userPassword:: e1NTSEF9UWhmaFB3dERydTUydURoWFFObDRMbzVIckI3TkI5Nmo==
@@ -0,0 +1,70 @@
dn: cn=users,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: users
description: Users
member: uid=alan,ou=users,dc=qsfera,dc=eu
member: uid=mary,ou=users,dc=qsfera,dc=eu
member: uid=margaret,ou=users,dc=qsfera,dc=eu
member: uid=dennis,ou=users,dc=qsfera,dc=eu
member: uid=lynn,ou=users,dc=qsfera,dc=eu
member: uid=admin,ou=users,dc=qsfera,dc=eu
dn: cn=chess-lovers,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: chess-lovers
description: Chess lovers
member: uid=alan,ou=users,dc=qsfera,dc=eu
dn: cn=machine-lovers,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: machine-lovers
description: Machine Lovers
member: uid=alan,ou=users,dc=qsfera,dc=eu
dn: cn=bible-readers,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: bible-readers
description: Bible readers
member: uid=mary,ou=users,dc=qsfera,dc=eu
dn: cn=apollos,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: apollos
description: Contributors to the Appollo mission
member: uid=margaret,ou=users,dc=qsfera,dc=eu
dn: cn=unix-lovers,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: unix-lovers
description: Unix lovers
member: uid=dennis,ou=users,dc=qsfera,dc=eu
dn: cn=basic-haters,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: basic-haters
description: Haters of the Basic programming language
member: uid=dennis,ou=users,dc=qsfera,dc=eu
dn: cn=vlsi-lovers,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: vlsi-lovers
description: Lovers of VLSI microchip design
member: uid=lynn,ou=users,dc=qsfera,dc=eu
dn: cn=programmers,ou=groups,dc=qsfera,dc=eu
objectClass: groupOfNames
objectClass: top
cn: programmers
description: Computer Programmers
member: uid=alan,ou=users,dc=qsfera,dc=eu
member: uid=margaret,ou=users,dc=qsfera,dc=eu
member: uid=dennis,ou=users,dc=qsfera,dc=eu
member: uid=lynn,ou=users,dc=qsfera,dc=eu
@@ -0,0 +1,65 @@
app_registry:
mimetypes:
- mime_type: application/pdf
extension: pdf
name: PDF
description: PDF document
icon: ''
default_app: ''
allow_creation: false
- mime_type: application/vnd.oasis.opendocument.text
extension: odt
name: OpenDocument
description: OpenDocument text document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.oasis.opendocument.spreadsheet
extension: ods
name: OpenSpreadsheet
description: OpenDocument spreadsheet document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.oasis.opendocument.presentation
extension: odp
name: OpenPresentation
description: OpenDocument presentation document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
extension: docx
name: Microsoft Word
description: Microsoft Word document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.wordprocessingml.form
extension: docxf
name: Form Document
description: Form Document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
extension: xlsx
name: Microsoft Excel
description: Microsoft Excel document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.openxmlformats-officedocument.presentationml.presentation
extension: pptx
name: Microsoft PowerPoint
description: Microsoft PowerPoint document
icon: ''
default_app: CollaboraOnline
allow_creation: true
- mime_type: application/vnd.jupyter
extension: ipynb
name: Jupyter Notebook
description: Jupyter Notebook
icon: ''
default_app: ''
allow_creation: true
@@ -0,0 +1,17 @@
importer:
config:
companionUrl: https://${COMPANION_DOMAIN|companion.qsfera.test}
supportedClouds:
- WebdavPublicLink
#- OneDrive # needs a client id and secret
#- GoogleDrive # needs a client id and secret and an addition to the DNS zone
external-sites:
config:
sites:
# For settings see: https://github.com/opencloud-eu/web-extensions/tree/main/packages/web-app-external-sites
- name: Documentation
url: "https://docs.qsfera.eu"
target: embedded
color: "#E2BAFF"
icon: cloud
priority: 50
@@ -0,0 +1,5 @@
password
12345678
123
КуСфера
КуСфера-1
@@ -0,0 +1,44 @@
directives:
child-src:
- '''self'''
connect-src:
- '''self'''
- 'blob:'
- 'https://${COMPANION_DOMAIN|companion.qsfera.test}/'
- 'wss://${COMPANION_DOMAIN|companion.qsfera.test}/'
- 'https://raw.githubusercontent.com/qsfera-eu/awesome-apps/'
- 'https://${KEYCLOAK_DOMAIN|keycloak.qsfera.test}/'
default-src:
- '''none'''
font-src:
- '''self'''
frame-ancestors:
- '''self'''
frame-src:
- '''self'''
- 'blob:'
- 'https://embed.diagrams.net/'
# In contrary to bash and docker the default is given after the | character
- 'https://${COLLABORA_DOMAIN|collabora.qsfera.test}/'
# This is needed for the external-sites web extension when embedding sites
- 'https://docs.qsfera.eu'
img-src:
- '''self'''
- 'data:'
- 'blob:'
- 'https://raw.githubusercontent.com/qsfera-eu/awesome-apps/'
# In contrary to bash and docker the default is given after the | character
- 'https://${COLLABORA_DOMAIN|collabora.qsfera.test}/'
manifest-src:
- '''self'''
media-src:
- '''self'''
object-src:
- '''self'''
- 'blob:'
script-src:
- '''self'''
- '''unsafe-inline'''
style-src:
- '''self'''
- '''unsafe-inline'''
@@ -0,0 +1,40 @@
# This adds four additional routes to the proxy. Forwarding
# request on '/carddav/', '/caldav/' and the respective '/.well-knwown'
# endpoints to the radicale container and setting the required headers.
additional_policies:
- name: default
routes:
- endpoint: /caldav/
backend: http://radicale:5232
remote_user_header: X-Remote-User
skip_x_access_token: true
additional_headers:
- X-Script-Name: /caldav
- endpoint: /.well-known/caldav
backend: http://radicale:5232
remote_user_header: X-Remote-User
skip_x_access_token: true
additional_headers:
- X-Script-Name: /caldav
- endpoint: /carddav/
backend: http://radicale:5232
remote_user_header: X-Remote-User
skip_x_access_token: true
additional_headers:
- X-Script-Name: /carddav
- endpoint: /.well-known/carddav
backend: http://radicale:5232
remote_user_header: X-Remote-User
skip_x_access_token: true
additional_headers:
- X-Script-Name: /carddav
# To enable the radicale web UI add this rule.
# "unprotected" is True because the Web UI itself ask for
# the password.
# Also set "type" to "internal" in the config/radicale/config
# - endpoint: /caldav/.web/
# backend: http://radicale:5232/
# unprotected: true
# skip_x_access_token: true
# additional_headers:
# - X-Script-Name: /caldav
@@ -0,0 +1,325 @@
# -*- mode: conf -*-
# vim:ft=cfg
# Config file for Radicale - A simple calendar server
#
# Place it into /etc/radicale/config (global)
# or ~/.config/radicale/config (user)
#
# The current values are the default ones
[server]
# CalDAV server hostnames separated by a comma
# IPv4 syntax: address:port
# IPv6 syntax: [address]:port
# Hostname syntax (using "getaddrinfo" to resolve to IPv4/IPv6 adress(es)): hostname:port
# For example: 0.0.0.0:9999, [::]:9999, localhost:9999
hosts = 0.0.0.0:5232
# Max parallel connections
#max_connections = 8
# Max size of request body (bytes)
#max_content_length = 100000000
# Socket timeout (seconds)
#timeout = 30
# SSL flag, enable HTTPS protocol
#ssl = False
# SSL certificate path
#certificate = /etc/ssl/radicale.cert.pem
# SSL private key
#key = /etc/ssl/radicale.key.pem
# CA certificate for validating clients. This can be used to secure
# TCP traffic between Radicale and a reverse proxy
#certificate_authority =
# SSL protocol, secure configuration: ALL -SSLv3 -TLSv1 -TLSv1.1
#protocol = (default)
# SSL ciphersuite, secure configuration: DHE:ECDHE:-NULL:-SHA (see also "man openssl-ciphers")
#ciphersuite = (default)
# script name to strip from URI if called by reverse proxy
#script_name = (default taken from HTTP_X_SCRIPT_NAME or SCRIPT_NAME)
[encoding]
# Encoding for responding requests
#request = utf-8
# Encoding for storing local collections
#stock = utf-8
[auth]
# Authentication method
# Value: none | htpasswd | remote_user | http_x_remote_user | dovecot | ldap | oauth2 | pam | denyall
type = http_x_remote_user
# Cache logins for until expiration time
#cache_logins = false
# Expiration time for caching successful logins in seconds
#cache_successful_logins_expiry = 15
## Expiration time of caching failed logins in seconds
#cache_failed_logins_expiry = 90
# Ignore modifyTimestamp and createTimestamp attributes. Required e.g. for Authentik LDAP server
#ldap_ignore_attribute_create_modify_timestamp = false
# URI to the LDAP server
#ldap_uri = ldap://localhost
# The base DN where the user accounts have to be searched
#ldap_base = ##BASE_DN##
# The reader DN of the LDAP server
#ldap_reader_dn = CN=ldapreader,CN=Users,##BASE_DN##
# Password of the reader DN
#ldap_secret = ldapreader-secret
# Path of the file containing password of the reader DN
#ldap_secret_file = /run/secrets/ldap_password
# the attribute to read the group memberships from in the user's LDAP entry (default: not set)
#ldap_groups_attribute = memberOf
# The filter to find the DN of the user. This filter must contain a python-style placeholder for the login
#ldap_filter = (&(objectClass=person)(uid={0}))
# the attribute holding the value to be used as username after authentication
#ldap_user_attribute = cn
# Use ssl on the ldap connection
# Soon to be deprecated, use ldap_security instead
#ldap_use_ssl = False
# the encryption mode to be used: tls, starttls, default is none
#ldap_security = none
# The certificate verification mode. Works for ssl and starttls. NONE, OPTIONAL, default is REQUIRED
#ldap_ssl_verify_mode = REQUIRED
# The path to the CA file in pem format which is used to certificate the server certificate
#ldap_ssl_ca_file =
# Connection type for dovecot authentication (AF_UNIX|AF_INET|AF_INET6)
# Note: credentials are transmitted in cleartext
#dovecot_connection_type = AF_UNIX
# The path to the Dovecot client authentication socket (eg. /run/dovecot/auth-client on Fedora). Radicale must have read / write access to the socket.
#dovecot_socket = /var/run/dovecot/auth-client
# Host of via network exposed dovecot socket
#dovecot_host = localhost
# Port of via network exposed dovecot socket
#dovecot_port = 12345
# IMAP server hostname
# Syntax: address | address:port | [address]:port | imap.server.tld
#imap_host = localhost
# Secure the IMAP connection
# Value: tls | starttls | none
#imap_security = tls
# OAuth2 token endpoint URL
#oauth2_token_endpoint = <URL>
# PAM service
#pam_serivce = radicale
# PAM group user should be member of
#pam_group_membership =
# Htpasswd filename
#htpasswd_filename = /etc/radicale/users
# Htpasswd encryption method
# Value: plain | bcrypt | md5 | sha256 | sha512 | autodetect
# bcrypt requires the installation of 'bcrypt' module.
#htpasswd_encryption = autodetect
# Enable caching of htpasswd file based on size and mtime_ns
#htpasswd_cache = False
# Incorrect authentication delay (seconds)
#delay = 1
# Message displayed in the client when a password is needed
#realm = Radicale - Password Required
# Convert username to lowercase, must be true for case-insensitive auth providers
#lc_username = False
# Strip domain name from username
#strip_domain = False
[rights]
# Rights backend
# Value: authenticated | owner_only | owner_write | from_file
#type = owner_only
# File for rights management from_file
#file = /etc/radicale/rights
# Permit delete of a collection (global)
#permit_delete_collection = True
# Permit overwrite of a collection (global)
#permit_overwrite_collection = True
[storage]
# Storage backend
# Value: multifilesystem | multifilesystem_nolock
#type = multifilesystem
# Folder for storing local collections, created if not present
#filesystem_folder = /var/lib/radicale/collections
# Folder for storing cache of local collections, created if not present
# Note: only used in case of use_cache_subfolder_* options are active
# Note: can be used on multi-instance setup to cache files on local node (see below)
#filesystem_cache_folder = (filesystem_folder)
# Use subfolder 'collection-cache' for 'item' cache file structure instead of inside collection folder
# Note: can be used on multi-instance setup to cache 'item' on local node
#use_cache_subfolder_for_item = False
# Use subfolder 'collection-cache' for 'history' cache file structure instead of inside collection folder
# Note: use only on single-instance setup, will break consistency with client in multi-instance setup
#use_cache_subfolder_for_history = False
# Use subfolder 'collection-cache' for 'sync-token' cache file structure instead of inside collection folder
# Note: use only on single-instance setup, will break consistency with client in multi-instance setup
#use_cache_subfolder_for_synctoken = False
# Use last modifiction time (nanoseconds) and size (bytes) for 'item' cache instead of SHA256 (improves speed)
# Note: check used filesystem mtime precision before enabling
# Note: conversion is done on access, bulk conversion can be done offline using storage verification option: radicale --verify-storage
#use_mtime_and_size_for_item_cache = False
# Use configured umask for folder creation (not applicable for OS Windows)
# Useful value: 0077 | 0027 | 0007 | 0022
#folder_umask = (system default, usual 0022)
# Delete sync token that are older (seconds)
#max_sync_token_age = 2592000
# Skip broken item instead of triggering an exception
#skip_broken_item = True
# Command that is run after changes to storage, default is emtpy
# Supported placeholders:
# %(user)s: logged-in user
# %(cwd)s : current working directory
# %(path)s: full path of item
# Command will be executed with base directory defined in filesystem_folder
# For "git" check DOCUMENTATION.md for bootstrap instructions
# Example(test): echo \"user=%(user)s path=%(path)s cwd=%(cwd)s\"
# Example(git): git add -A && (git diff --cached --quiet || git commit -m "Changes by \"%(user)s\"")
#hook =
# Create predefined user collections
#
# json format:
#
# {
# "def-addressbook": {
# "D:displayname": "Personal Address Book",
# "tag": "VADDRESSBOOK"
# },
# "def-calendar": {
# "C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
# "D:displayname": "Personal Calendar",
# "tag": "VCALENDAR"
# }
# }
#
predefined_collections = {
"def-addressbook": {
"D:displayname": "Personal Address Book",
"tag": "VADDRESSBOOK"
},
"def-calendar": {
"C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
"D:displayname": "Personal Calendar",
"tag": "VCALENDAR"
}
}
[web]
# Web interface backend
# Value: none | internal
type = none
[logging]
# Threshold for the logger
# Value: debug | info | warning | error | critical
#level = info
# Don't include passwords in logs
#mask_passwords = True
# Log bad PUT request content
#bad_put_request_content = False
# Log backtrace on level=debug
#backtrace_on_debug = False
# Log request header on level=debug
#request_header_on_debug = False
# Log request content on level=debug
#request_content_on_debug = False
# Log response content on level=debug
#response_content_on_debug = False
# Log rights rule which doesn't match on level=debug
#rights_rule_doesnt_match_on_debug = False
# Log storage cache actions on level=debug
#storage_cache_actions_on_debug = False
[headers]
# Additional HTTP headers
#Access-Control-Allow-Origin = *
[hook]
# Hook types
# Value: none | rabbitmq
#type = none
#rabbitmq_endpoint =
#rabbitmq_topic =
#rabbitmq_queue_type = classic
[reporting]
# When returning a free-busy report, limit the number of returned
# occurences per event to prevent DOS attacks.
#max_freebusy_occurrence = 10000
@@ -0,0 +1,9 @@
---
services:
collaboration:
command: [ "-c", "dlv --listen=:40000 --headless=true --continue --check-go-version=false --api-version=2 --accept-multiclient exec /usr/bin/qsfera collaboration server" ]
environment:
COLLABORATION_LOG_LEVEL: debug
ports:
- 40001:40000
@@ -0,0 +1,9 @@
---
services:
collaboration-oo:
command: [ "-c", "dlv --listen=:40002 --headless=true --continue --check-go-version=false --api-version=2 --accept-multiclient exec /usr/bin/qsfera collaboration server" ]
environment:
COLLABORATION_LOG_LEVEL: debug
ports:
- 40002:40002
@@ -0,0 +1,7 @@
---
services:
qsfera:
command: [ "-c", "qsfera init || true; dlv --listen=:40000 --headless=true --continue --check-go-version=false --api-version=2 --accept-multiclient exec /usr/bin/qsfera server" ]
ports:
- 40000:40000
@@ -0,0 +1,6 @@
---
services:
qsfera:
environment:
STORAGE_USERS_DRIVER: decomposed
@@ -0,0 +1,14 @@
---
services:
qsfera:
environment:
# activate decomposeds3 storage driver
STORAGE_USERS_DRIVER: decomposeds3
# keep system data on qsfera storage since this are only small files atm
STORAGE_SYSTEM_DRIVER: decomposed
# decomposeds3 specific settings
STORAGE_USERS_DECOMPOSEDS3_ENDPOINT: ${DECOMPOSEDS3_ENDPOINT:-http://minio:9000}
STORAGE_USERS_DECOMPOSEDS3_REGION: ${DECOMPOSEDS3_REGION:-default}
STORAGE_USERS_DECOMPOSEDS3_ACCESS_KEY: ${DECOMPOSEDS3_ACCESS_KEY:-qsfera}
STORAGE_USERS_DECOMPOSEDS3_SECRET_KEY: ${DECOMPOSEDS3_SECRET_KEY:-qsfera-secret-key}
STORAGE_USERS_DECOMPOSEDS3_BUCKET: ${DECOMPOSEDS3_BUCKET:-qsfera-bucket}
@@ -0,0 +1,62 @@
---
services:
traefik:
image: traefik:v3.3.1
# release notes: https://github.com/traefik/traefik/releases
networks:
qsfera-net:
command:
- "--log.level=${TRAEFIK_LOG_LEVEL:-ERROR}"
# letsencrypt configuration
- "--certificatesResolvers.http.acme.email=${TRAEFIK_ACME_MAIL:-example@example.org}"
- "--certificatesResolvers.http.acme.storage=/certs/acme.json"
- "--certificatesResolvers.http.acme.httpChallenge.entryPoint=http"
- "--certificatesResolvers.http.acme.caserver=${TRAEFIK_ACME_CASERVER:-https://acme-v02.api.letsencrypt.org/directory}"
# enable dashboard
- "--api.dashboard=true"
# define entrypoints
- "--entryPoints.http.address=:80"
- "--entryPoints.http.http.redirections.entryPoint.to=https"
- "--entryPoints.http.http.redirections.entryPoint.scheme=https"
- "--entryPoints.https.address=:443"
# http2 optimizations
- "--entryPoints.https.http2.maxConcurrentStreams=512"
- "--serversTransport.maxIdleConnsPerHost=100"
# allow self signed certificate from КуСфера
- "--serversTransport.insecureSkipVerify=true"
# change default timeouts for long-running requests
# this is needed for webdav clients that do not support the TUS protocol
- "--entryPoints.https.transport.respondingTimeouts.readTimeout=12h"
- "--entryPoints.https.transport.respondingTimeouts.writeTimeout=12h"
- "--entryPoints.https.transport.respondingTimeouts.idleTimeout=3m"
# docker provider (get configuration from container labels)
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--providers.docker.exposedByDefault=false"
# access log
- "--accessLog=true"
- "--accessLog.format=json"
- "--accessLog.fields.headers.names.X-Request-Id=keep"
ports:
- "80:80"
- "443:443"
volumes:
- "${DOCKER_SOCKET_PATH:-/var/run/docker.sock}:/var/run/docker.sock:ro"
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
# defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.qsfera.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"
- "traefik.http.routers.traefik.tls.certresolver=http"
- "traefik.http.routers.traefik.service=api@internal"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
certs:
networks:
qsfera-net:
@@ -0,0 +1,34 @@
---
services:
qsfera:
environment:
NOTIFICATIONS_SMTP_HOST: inbucket
NOTIFICATIONS_SMTP_PORT: 2500
NOTIFICATIONS_SMTP_SENDER: КуСфера notifications <notifications@${OC_DOMAIN:-cloud.qsfera.test}>
NOTIFICATIONS_SMTP_USERNAME: notifications@${OC_DOMAIN:-cloud.qsfera.test}
# the mail catcher uses self signed certificates
NOTIFICATIONS_SMTP_INSECURE: "true"
inbucket:
image: inbucket/inbucket
# changelog: https://github.com/inbucket/inbucket/blob/main/CHANGELOG.md
networks:
- qsfera-net
entrypoint:
- /bin/sh
command: [ "-c", "apk add openssl; openssl req -subj '/CN=inbucket.test' -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/server.key -out /tmp/server.crt; /start-inbucket.sh" ]
environment:
INBUCKET_SMTP_TLSENABLED: "true"
INBUCKET_SMTP_TLSPRIVKEY: /tmp/server.key
INBUCKET_SMTP_TLSCERT: /tmp/server.crt
INBUCKET_STORAGE_MAILBOXMSGCAP: 1000
labels:
- "traefik.enable=true"
- "traefik.http.routers.inbucket.entrypoints=https"
- "traefik.http.routers.inbucket.rule=Host(`${INBUCKET_DOMAIN:-mail.qsfera.test}`)"
- "traefik.http.routers.inbucket.tls.certresolver=http"
- "traefik.http.routers.inbucket.service=inbucket"
- "traefik.http.services.inbucket.loadbalancer.server.port=9000"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
@@ -0,0 +1,41 @@
---
services:
qsfera:
environment:
# Keycloak IDP specific configuration for auto-provisioning
OC_LDAP_SERVER_WRITE_ENABLED: "true"
PROXY_AUTOPROVISION_ACCOUNTS: "true"
# Use the `sub` claim from keycloak for the user ID
# Keycloak uses the keycloak user ID as the `sub` claim
PROXY_USER_OIDC_CLAIM: "sub"
# Use the `sub` claim as identifier during autoprovisioning
# That mitigates problems when a user is renamed in keycloak
PROXY_AUTOPROVISION_CLAIM_USERNAME: "sub"
PROXY_USER_CS3_CLAIM: "username"
# This triggers the creation of the qsferaUUID during the provisioning of users and groups
GRAPH_LDAP_SERVER_UUID: "false"
# This is the default value, we need to set it here because we overwrite the values
OC_LDAP_USER_SCHEMA_ID: "qsferaUUID"
# This is the default value, we need to set it here because we overwrite the values
OC_LDAP_GROUP_SCHEMA_ID: "qsferaUUID"
# This is the default value, we need to set it here because we overwrite the values
OC_LDAP_DISABLE_USER_MECHANISM: "attribute"
# These values should only be set in keycloak, because qsfera updates them from the claims
FRONTEND_READONLY_USER_ATTRIBUTES: "user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.memberOf"
ldap-server:
volumes:
# Use an empty named volume to overwrite the inherited values
- empty-dir:/ldifs
# Only use the base ldif file to create the base structure
- ./config/ldap/ldif/10_base.ldif:/ldifs/10_base.ldif
# Use the custom schema from qsfera because we are in full control of the ldap server
- ../shared/config/ldap/schemas/10_qsfera_schema.ldif:/schemas/10_qsfera_schema.ldif
- ./config/ldap/docker-entrypoint-override.sh:/opt/bitnami/scripts/openldap/docker-entrypoint-override.sh
- ldap-certs:/opt/bitnami/openldap/share
- ldap-data:/bitnami/openldap
keycloak:
volumes:
- "./config/keycloak/docker-entrypoint-override.sh:/opt/keycloak/bin/docker-entrypoint-override.sh"
- "./config/keycloak/qsfera-realm-autoprovisioning.dist.json:/opt/keycloak/data/import-dist/qsfera-realm.json"
volumes:
empty-dir:
@@ -0,0 +1,74 @@
---
services:
traefik:
networks:
qsfera-net:
aliases:
- ${KEYCLOAK_DOMAIN:-keycloak.qsfera.test}
qsfera:
environment:
# Keycloak IDP specific configuration
PROXY_AUTOPROVISION_ACCOUNTS: "false"
PROXY_ROLE_ASSIGNMENT_DRIVER: "oidc"
OC_OIDC_ISSUER: https://${KEYCLOAK_DOMAIN:-keycloak.qsfera.test}/realms/${KEYCLOAK_REALM:-qsfera}
PROXY_OIDC_REWRITE_WELLKNOWN: "true"
WEB_OIDC_CLIENT_ID: ${OC_OIDC_CLIENT_ID:-web}
PROXY_USER_OIDC_CLAIM: "uuid"
PROXY_USER_CS3_CLAIM: "userid"
WEB_OPTION_ACCOUNT_EDIT_LINK_HREF: "https://${KEYCLOAK_DOMAIN:-keycloak.qsfera.test}/realms/${KEYCLOAK_REALM:-qsfera}/account"
# admin and demo accounts must be created in Keycloak
OC_ADMIN_USER_ID: ""
SETTINGS_SETUP_DEFAULT_ASSIGNMENTS: "false"
GRAPH_ASSIGN_DEFAULT_USER_ROLE: "false"
GRAPH_USERNAME_MATCH: "none"
KEYCLOAK_DOMAIN: ${KEYCLOAK_DOMAIN:-keycloak.qsfera.test}
postgres:
image: postgres:alpine
networks:
qsfera-net:
volumes:
- keycloak_postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak
logging:
driver: ${LOG_DRIVER:-local}
restart: always
keycloak:
image: quay.io/keycloak/keycloak:25.0.0
networks:
qsfera-net:
command: ["start", "--proxy=edge", "--spi-connections-http-client-default-disable-trust-manager=${INSECURE:-false}", "--import-realm"]
entrypoint: ["/bin/sh", "/opt/keycloak/bin/docker-entrypoint-override.sh"]
volumes:
- "./config/keycloak/docker-entrypoint-override.sh:/opt/keycloak/bin/docker-entrypoint-override.sh"
- "./config/keycloak/qsfera-realm.dist.json:/opt/keycloak/data/import-dist/qsfera-realm.json"
environment:
OC_DOMAIN: ${OC_DOMAIN:-cloud.qsfera.test}
KC_HOSTNAME: ${KEYCLOAK_DOMAIN:-keycloak.qsfera.test}
KC_DB: postgres
KC_DB_URL: "jdbc:postgresql://postgres:5432/keycloak"
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
KC_FEATURES: impersonation
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USER:-admin}
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
labels:
- "traefik.enable=true"
- "traefik.http.routers.keycloak.entrypoints=https"
- "traefik.http.routers.keycloak.rule=Host(`${KEYCLOAK_DOMAIN:-keycloak.qsfera.test}`)"
- "traefik.http.routers.keycloak.tls.certresolver=http"
- "traefik.http.routers.keycloak.service=keycloak"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
depends_on:
- postgres
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
keycloak_postgres_data:
@@ -0,0 +1,59 @@
---
services:
traefik:
networks:
qsfera-net:
qsfera:
environment:
# Ldap IDP specific configuration
OC_LDAP_URI: ldaps://ldap-server:1636
OC_LDAP_INSECURE: "true"
OC_LDAP_BIND_DN: "cn=admin,dc=qsfera,dc=eu"
OC_LDAP_BIND_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
OC_LDAP_GROUP_BASE_DN: "ou=groups,dc=qsfera,dc=eu"
OC_LDAP_GROUP_SCHEMA_ID: "entryUUID"
OC_LDAP_USER_BASE_DN: "ou=users,dc=qsfera,dc=eu"
OC_LDAP_USER_FILTER: "(objectclass=inetOrgPerson)"
OC_LDAP_USER_SCHEMA_ID: "entryUUID"
OC_LDAP_DISABLE_USER_MECHANISM: "none"
GRAPH_LDAP_SERVER_UUID: "true"
GRAPH_LDAP_GROUP_CREATE_BASE_DN: "ou=custom,ou=groups,dc=qsfera,dc=eu"
GRAPH_LDAP_REFINT_ENABLED: "true" # osixia has refint enabled.
FRONTEND_READONLY_USER_ATTRIBUTES: "user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.accountEnabled,user.appRoleAssignments"
OC_LDAP_SERVER_WRITE_ENABLED: "false" # assuming the external ldap is not writable
# OC_RUN_SERVICES specifies to start all services except glauth, idm and accounts. These are replaced by external services
OC_EXCLUDE_RUN_SERVICES: idm
ldap-server:
image: bitnamilegacy/openldap:2.6
networks:
qsfera-net:
entrypoint: ["/bin/sh", "/opt/bitnami/scripts/openldap/docker-entrypoint-override.sh", "/opt/bitnami/scripts/openldap/run.sh" ]
environment:
BITNAMI_DEBUG: true
LDAP_TLS_VERIFY_CLIENT: never
LDAP_ENABLE_TLS: "yes"
LDAP_TLS_CA_FILE: /opt/bitnami/openldap/share/openldap.crt
LDAP_TLS_CERT_FILE: /opt/bitnami/openldap/share/openldap.crt
LDAP_TLS_KEY_FILE: /opt/bitnami/openldap/share/openldap.key
LDAP_ROOT: "dc=qsfera,dc=eu"
LDAP_ADMIN_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
ports:
- "127.0.0.1:389:1389"
- "127.0.0.1:636:1636"
volumes:
- ./config/ldap/ldif:/ldifs
- ./config/ldap/docker-entrypoint-override.sh:/opt/bitnami/scripts/openldap/docker-entrypoint-override.sh
- ldap-certs:/opt/bitnami/openldap/share
- ldap-data:/bitnami/openldap
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
ldap-certs:
ldap-data:
networks:
qsfera-net:
@@ -0,0 +1,32 @@
---
services:
minio:
image: minio/minio:latest
# release notes: https://github.com/minio/minio/releases
networks:
qsfera-net:
entrypoint:
- /bin/sh
command:
[
"-c",
"mkdir -p /data/${DECOMPOSEDS3_BUCKET:-qsfera-bucket} && minio server --console-address ':9001' /data",
]
volumes:
- minio-data:/data
environment:
MINIO_ROOT_USER: ${DECOMPOSEDS3_ACCESS_KEY:-qsfera}
MINIO_ROOT_PASSWORD: ${DECOMPOSEDS3_SECRET_KEY:-qsfera-secret-key}
labels:
- "traefik.enable=true"
- "traefik.http.routers.minio.entrypoints=https"
- "traefik.http.routers.minio.rule=Host(`${MINIO_DOMAIN:-minio.qsfera.test}`)"
- "traefik.http.routers.minio.tls.certresolver=http"
- "traefik.http.routers.minio.service=minio"
- "traefik.http.services.minio.loadbalancer.server.port=9001"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
minio-data:
@@ -0,0 +1,26 @@
---
services:
qsfera:
environment:
# tracing
OC_TRACING_ENABLED: "true"
OC_TRACING_TYPE: "jaeger"
OC_TRACING_ENDPOINT: jaeger-agent:6831
# metrics
# if КуСфера runs as a single process, all <debug>/metrics endpoints
# will expose the same metrics, so it's sufficient to query one endpoint
PROXY_DEBUG_ADDR: 0.0.0.0:9205
collaboration-oo:
environment:
# tracing
OC_TRACING_ENABLED: "true"
OC_TRACING_TYPE: "jaeger"
OC_TRACING_ENDPOINT: jaeger-agent:6831
# metrics
COLLABORATION_DEBUG_ADDR: 0.0.0.0:9304
networks:
qsfera-net:
external: true
@@ -0,0 +1,26 @@
---
services:
qsfera:
environment:
# tracing
OC_TRACING_ENABLED: "true"
OC_TRACING_TYPE: "jaeger"
OC_TRACING_ENDPOINT: jaeger-agent:6831
# metrics
# if КуСфера runs as a single process, all <debug>/metrics endpoints
# will expose the same metrics, so it's sufficient to query one endpoint
PROXY_DEBUG_ADDR: 0.0.0.0:9205
collaboration:
environment:
# tracing
OC_TRACING_ENABLED: "true"
OC_TRACING_TYPE: "jaeger"
OC_TRACING_ENDPOINT: jaeger-agent:6831
# metrics
COLLABORATION_DEBUG_ADDR: 0.0.0.0:9304
networks:
qsfera-net:
external: true
@@ -0,0 +1,82 @@
---
services:
traefik:
networks:
qsfera-net:
aliases:
- ${OC_DOMAIN:-cloud.qsfera.test}
qsfera:
image: ${OC_DOCKER_IMAGE:-qsfera/qsfera-rolling}:${OC_DOCKER_TAG:-latest}
# changelog: https://github.com/qsfera/server/tree/main/changelog
# release notes: https://docs.qsfera.eu/qsfera_release_notes.html
networks:
qsfera-net:
entrypoint:
- /bin/sh
# run qsfera init to initialize a configuration file with random secrets
# it will fail on subsequent runs, because the config file already exists
# therefore we ignore the error and then start the qsfera server
command: ["-c", "qsfera init || true; qsfera server"]
environment:
# enable services that are not started automatically
OC_ADD_RUN_SERVICES: ${START_ADDITIONAL_SERVICES}
OC_URL: https://${OC_DOMAIN:-cloud.qsfera.test}
OC_LOG_LEVEL: ${LOG_LEVEL:-info}
OC_LOG_COLOR: "${LOG_PRETTY:-false}"
OC_LOG_PRETTY: "${LOG_PRETTY:-false}"
# do not use SSL between Traefik and КуСфера
PROXY_TLS: "true"
# make the REVA gateway accessible to the app drivers
GATEWAY_GRPC_ADDR: 0.0.0.0:9142
# INSECURE: needed if КуСфера / Traefik is using self generated certificates
OC_INSECURE: "${INSECURE:-false}"
# basic auth (not recommended, but needed for eg. WebDav clients that do not support OpenID Connect)
PROXY_ENABLE_BASIC_AUTH: "${PROXY_ENABLE_BASIC_AUTH:-false}"
# admin user password
IDM_ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}" # this overrides the admin password from the configuration file
# demo users
IDM_CREATE_DEMO_USERS: "${DEMO_USERS:-false}"
# idp login form settings
IDP_DEFAULT_SIGNIN_PAGE_TEXT: "${IDP_DEFAULT_SIGNIN_PAGE_TEXT}"
# email server (if configured)
NOTIFICATIONS_SMTP_HOST: "${SMTP_HOST}"
NOTIFICATIONS_SMTP_PORT: "${SMTP_PORT}"
NOTIFICATIONS_SMTP_SENDER: "${SMTP_SENDER:-КуСфера notifications <notifications@${OC_DOMAIN:-cloud.qsfera.test}>}"
NOTIFICATIONS_SMTP_USERNAME: "${SMTP_USERNAME}"
NOTIFICATIONS_SMTP_PASSWORD: "${SMTP_PASSWORD}"
NOTIFICATIONS_SMTP_INSECURE: "${SMTP_INSECURE}"
NOTIFICATIONS_SMTP_AUTHENTICATION: "${SMTP_AUTHENTICATION}"
NOTIFICATIONS_SMTP_ENCRYPTION: "${SMTP_TRANSPORT_ENCRYPTION:-none}"
FRONTEND_ARCHIVER_MAX_SIZE: "10000000000"
# make the registry available to the app provider containers
MICRO_REGISTRY_ADDRESS: 127.0.0.1:9233
NATS_NATS_HOST: 0.0.0.0
NATS_NATS_PORT: 9233
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/qsfera/csp.yaml
# these three vars are needed to the csp config file to include the web office apps and the importer
COLLABORA_DOMAIN: ${COLLABORA_DOMAIN:-collabora.qsfera.test}
COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.qsfera.test}
# enable to allow using the banned passwords list
OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: banned-password-list.txt
volumes:
- ./config/qsfera/app-registry.yaml:/etc/qsfera/app-registry.yaml
- ./config/qsfera/csp.yaml:/etc/qsfera/csp.yaml
- ./config/qsfera/banned-password-list.txt:/etc/qsfera/banned-password-list.txt
# configure the .env file to use own paths instead of docker internal volumes
- ${OC_CONFIG_DIR:-qsfera-config}:/etc/qsfera
- ${OC_DATA_DIR:-qsfera-data}:/var/lib/qsfera
labels:
- "traefik.enable=true"
- "traefik.http.routers.qsfera.entrypoints=https"
- "traefik.http.routers.qsfera.rule=Host(`${OC_DOMAIN:-cloud.qsfera.test}`)"
- "traefik.http.routers.qsfera.tls.certresolver=http"
- "traefik.http.routers.qsfera.service=qsfera"
- "traefik.http.services.qsfera.loadbalancer.server.port=9200"
- "traefik.http.services.qsfera.loadbalancer.server.scheme=https"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
qsfera-config:
qsfera-data:
@@ -0,0 +1,18 @@
---
services:
qsfera:
volumes:
# external sites needs to have additional routes configured in the proxy
- ./config/qsfera/proxy.yaml:/etc/qsfera/proxy.yaml
radicale:
image: ${RADICALE_DOCKER_IMAGE:-opencloudeu/radicale}:${RADICALE_DOCKER_TAG:-latest}
networks:
qsfera-net:
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
- ./config/radicale/config:/etc/radicale/config
- ${RADICALE_DATA_DIR:-radicale-data}:/var/lib/radicale
volumes:
radicale-data:
@@ -0,0 +1,17 @@
---
services:
tika:
image: ${TIKA_IMAGE:-apache/tika:latest-full}
# release notes: https://tika.apache.org
networks:
qsfera-net:
restart: always
logging:
driver: ${LOG_DRIVER:-local}
qsfera:
environment:
# fulltext search
SEARCH_EXTRACTOR_TYPE: tika
SEARCH_EXTRACTOR_TIKA_TIKA_URL: http://tika:9998
FRONTEND_FULL_TEXT_SEARCH_ENABLED: "true"
@@ -0,0 +1,15 @@
---
services:
qsfera:
depends_on:
drawio-init:
condition: service_completed_successfully
drawio-init:
image: opencloudeu/web-extensions:draw-io-1.0.0
user: root
volumes:
- qsfera-apps:/apps
entrypoint:
- /bin/sh
command: ["-c", "cp -R /usr/share/nginx/html/draw-io/ /apps"]
@@ -0,0 +1,7 @@
services:
qsfera:
volumes:
- qsfera-apps:/var/lib/qsfera/web/assets/apps
volumes:
qsfera-apps:
@@ -0,0 +1,18 @@
---
services:
qsfera:
volumes:
# external sites needs to have sites configured in the web.yaml
- ./config/qsfera/apps.yaml:/etc/qsfera/apps.yaml
depends_on:
externalsites-init:
condition: service_completed_successfully
externalsites-init:
image: opencloudeu/web-extensions:external-sites-1.0.0
user: root
volumes:
- qsfera-apps:/apps
entrypoint:
- /bin/sh
command: ["-c", "cp -R /usr/share/nginx/html/external-sites/ /apps"]
@@ -0,0 +1,52 @@
---
services:
traefik:
networks:
qsfera-net:
aliases:
- ${COMPANION_DOMAIN:-companion.qsfera.test}
qsfera:
volumes:
# the cloud importer needs to be enabled in the web.yaml
- ./config/qsfera/apps.yaml:/etc/qsfera/apps.yaml
depends_on:
importer-init:
condition: service_completed_successfully
importer-init:
image: opencloudeu/web-extensions:importer-1.0.0
user: root
volumes:
- qsfera-apps:/apps
entrypoint:
- /bin/sh
command: [ "-c", "cp -R /usr/share/nginx/html/importer/ /apps" ]
companion:
image: ${COMPANION_IMAGE:-transloadit/companion:5.5.0}
networks:
- qsfera-net
environment:
NODE_ENV: production
NODE_TLS_REJECT_UNAUTHORIZED: 0
COMPANION_DATADIR: /tmp/companion/
COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.qsfera.test}
COMPANION_PROTOCOL: https
COMPANION_UPLOAD_URLS: "^https://${OC_DOMAIN:-cloud.qsfera.test}/"
COMPANION_ONEDRIVE_KEY: "${COMPANION_ONEDRIVE_KEY}"
COMPANION_ONEDRIVE_SECRET: "${COMPANION_ONEDRIVE_SECRET}"
volumes:
- companion-data:/tmp/companion/
labels:
- "traefik.enable=true"
- "traefik.http.routers.companion.entrypoints=https"
- "traefik.http.routers.companion.rule=Host(`${COMPANION_DOMAIN:-companion.qsfera.test}`)"
- "traefik.http.routers.companion.tls.certresolver=http"
- "traefik.http.routers.companion.service=companion"
- "traefik.http.services.companion.loadbalancer.server.port=3020"
logging:
driver: ${LOG_DRIVER:-local}
restart: always
volumes:
companion-data:
@@ -0,0 +1,15 @@
---
services:
qsfera:
depends_on:
jsonviewer-init:
condition: service_completed_successfully
jsonviewer-init:
image: opencloudeu/web-extensions:json-viewer-1.0.0
user: root
volumes:
- qsfera-apps:/apps
entrypoint:
- /bin/sh
command: ["-c", "cp -R /usr/share/nginx/html/json-viewer/ /apps"]
@@ -0,0 +1,15 @@
---
services:
qsfera:
depends_on:
progressbars-init:
condition: service_completed_successfully
progressbars-init:
image: opencloudeu/web-extensions:progress-bars-1.0.0
user: root
volumes:
- qsfera-apps:/apps
entrypoint:
- /bin/sh
command: ["-c", "cp -R /usr/share/nginx/html/progress-bars/ /apps"]
@@ -0,0 +1,15 @@
---
services:
qsfera:
depends_on:
unzip-init:
condition: service_completed_successfully
unzip-init:
image: opencloudeu/web-extensions:unzip-1.0.2
user: root
volumes:
- qsfera-apps:/apps
entrypoint:
- /bin/sh
command: ["-c", "cp -R /usr/share/nginx/html/unzip/ /apps"]