Nextcloud Ansible Role https://nextcloud.com/
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Conrad e911fc2176
All checks were successful
Lint + Tag / format (push) Successful in 1m16s
Lint + Tag / tag (push) Successful in 1m12s
fix: fixed pipeline
2026-10-12 16:57:36 +07:00
.forgejo/workflows fix: fixed pipeline 2026-10-12 16:57:36 +07:00
defaults feat: added oicd language and default language 2026-09-28 12:24:12 +02:00
files feat: new options for windows compatibility 2026-05-11 09:08:52 +02:00
meta fix: deleted outdated config file 2026-08-25 17:57:33 +02:00
tasks feat: added oicd language and default language 2026-09-28 12:24:12 +02:00
templates feat: added extra hosts + oidc config 2026-09-28 09:35:25 +02:00
.gitignore feat: added first nextcloud draft 2026-05-10 23:53:27 +02:00
CHANGELOG.md fix: fixed pipeline 2026-10-12 16:57:36 +07:00
LICENSE feat: added first nextcloud draft 2026-05-10 23:53:27 +02:00
README.md Prettified Code! 2026-09-28 10:25:18 +00:00

Nextcloud

Deploys a Nextcloud instance via Docker Compose with PostgreSQL, Redis, Collabora Online, notify_push, and Imaginary, using Traefik as a reverse proxy.

Requirements

  • Docker
  • community.docker Ansible collection

Variables

Variable Default Description
nextcloud_instance nextcloud Unique instance name. Used as Compose project name and container name prefix. Change when running multiple instances on the same host.
nextcloud_server_id 1 Numeric server ID written to Nextcloud's serverid config key. Useful for distinguishing multiple instances in logs.
nextcloud_data_path /data/nextcloud Host path for persistent data (DB, files, ClamAV, Elasticsearch data).
nextcloud_docker_path /docker/nextcloud Host path for the compose.yml file and Apache/PHP config snippets.
nextcloud_version 33.0.3-apache Nextcloud image tag. Pin to a specific version in production.
nextcloud_db_version 17 PostgreSQL image tag. Pin to a specific version in production.
nextcloud_redis_version alpine Redis image tag.
nextcloud_collabora_version latest Collabora Online (CODE) image tag.
nextcloud_notify_push_version latest notify_push image tag.
nextcloud_imaginary_version latest Imaginary image tag.
nextcloud_clamav_version stable ClamAV image tag. Only used when nextcloud_clamav_enabled is true.
nextcloud_elasticsearch_version latest Elasticsearch (AIO fulltextsearch) image tag. Only used when nextcloud_elasticsearch_enabled is true.
nextcloud_url ~ Canonical public domain Nextcloud runs on (no protocol prefix). Required.
nextcloud_extra_domains [] Additional public domains this instance also answers on. See Extra domains below.
nextcloud_db_pass ~ PostgreSQL password for the nextcloud user. Required. Generate with openssl rand -hex 32.
nextcloud_admin_user admin Admin account username created on first boot. Ignored on subsequent runs.
nextcloud_admin_password ~ Admin account password. Required. Generate with openssl rand -hex 32.
nextcloud_collabora_password ~ Collabora Online admin password. Required.
nextcloud_collabora_url ~ Public domain Collabora runs on (no protocol prefix). Required.
nextcloud_loglevel 3 Log level: 0=DEBUG 1=INFO 2=WARNING 3=ERROR 4=FATAL. Defaults to ERROR since Docker deployments generate harmless recurring warnings.
nextcloud_windows_compatible_filenames false Enforce Windows-compatible filenames. Enable when sharing files with Windows clients.
nextcloud_sanitize_filenames false Rename all existing files that violate current filename constraints. Set once after enabling nextcloud_windows_compatible_filenames, then reset to false. Can be slow on large instances.
nextcloud_data_location "" Displayed in the Privacy admin panel under "Where is your data?" (e.g. "Germany"). Not shown when empty.
nextcloud_full_disk_encryption false Shows the "This server is using full-disk-encryption" notice in the Privacy admin panel.
nextcloud_phone_region DE Default phone region for number formatting (ISO 3166-1 alpha-2).
nextcloud_maintenance_window 1 Hour (0–23 UTC) when Nextcloud's maintenance window starts (background jobs, updates).
nextcloud_default_language ~ Default language for users without their own setting, e.g. de_DE (formal German) or de. Null follows the browser.
nextcloud_default_locale ~ Default locale (date/number formats), e.g. de_DE. Null derives it from the language.
nextcloud_mounts [] Extra volume mounts appended to the Nextcloud app container. See Extra mounts below.
nextcloud_apps [] Extra Nextcloud Store app IDs to install (e.g. calendar, contacts). See Extra apps below.
nextcloud_imaginary_memory_limit 2g Memory limit for the Imaginary image-conversion container.
nextcloud_clamav_enabled false Deploys a ClamAV container and configures Nextcloud to scan uploads.
nextcloud_elasticsearch_enabled false Deploys an Elasticsearch container and configures full-text search.
nextcloud_elasticsearch_memory 1G JVM heap size for Elasticsearch (passed as both -Xms and -Xmx).
nextcloud_elasticsearch_reindex false Triggers a full re-index of all files on each playbook run. Expensive — only set temporarily when rebuilding the search index.
nextcloud_mail_conf ~ SMTP configuration. See Mail below.
nextcloud_oidc_conf ~ OpenID Connect login (user_oidc app). See OpenID Connect below.
nextcloud_extra_hosts {} Extra /etc/hosts entries (hostname: IP) for the app and Collabora containers. See Extra hosts below.
nextcloud_talk_signaling_url ~ HPB signaling server hostname (no protocol), e.g. signal.example.com. Setting this installs Talk and configures signaling. Requires nextcloud_talk_signaling_secret.
nextcloud_talk_signaling_secret ~ Shared secret for the HPB signaling server.
nextcloud_talk_stun_server ~ STUN server in hostname:port format. Replaces all existing STUN servers (including the Nextcloud default).
nextcloud_talk_turn_server ~ TURN server in hostname:port format. Requires nextcloud_talk_turn_secret.
nextcloud_talk_turn_secret ~ Shared secret for the TURN server.
nextcloud_talk_recording_url ~ Recording backend full URL, e.g. https://recording.example.com. Requires nextcloud_talk_recording_secret.
nextcloud_talk_recording_secret ~ Shared secret for the recording backend.
nextcloud_uninstall false Stops and removes containers and the compose directory.
nextcloud_purge false Also removes the data directory. Requires nextcloud_uninstall: true. Irreversible.

Usage

Minimal setup:

nextcloud_url: "cloud.example.com"
nextcloud_collabora_url: "office.example.com"
nextcloud_db_pass: "{{ vault_nextcloud_db_pass }}"
nextcloud_admin_password: "{{ vault_nextcloud_admin_password }}"
nextcloud_collabora_password: "{{ vault_nextcloud_collabora_password }}"

Multiple instances on the same host:

# instance 1
nextcloud_instance: nextcloud_personal
nextcloud_url: cloud.example.com
nextcloud_collabora_url: office.example.com
nextcloud_db_pass: "secret_a"
nextcloud_collabora_password: "collab_secret_a"
nextcloud_data_path: /data/nextcloud_personal
nextcloud_docker_path: /docker/nextcloud_personal

# instance 2
nextcloud_instance: nextcloud_team
nextcloud_url: team.example.com
nextcloud_collabora_url: office-team.example.com
nextcloud_db_pass: "secret_b"
nextcloud_collabora_password: "collab_secret_b"
nextcloud_data_path: /data/nextcloud_team
nextcloud_docker_path: /docker/nextcloud_team

Mail

When nextcloud_mail_conf is set, Nextcloud's SMTP mailer is configured. Required keys: host, username, password.

nextcloud_mail_conf:
  host: smtp.example.com
  username: support@example.com
  password: secret
  address: support # optional, defaults to the part before @ in username
  domain: example.com # optional, defaults to the part after @ in username
  port: 587 # optional, default: 587
  security: tls # optional, default: tls (options: tls, ssl, none)

Extra domains

nextcloud_extra_domains adds hostnames this same instance also answers on — e.g. a customer's own vanity domain pointed at the same backend:

nextcloud_url: demo.tni.dev
nextcloud_extra_domains:
  - demo.inocloud.it

Each extra domain is added to NEXTCLOUD_TRUSTED_DOMAINS (else Nextcloud rejects the request with "Access through untrusted domain") and OR'd into the Traefik Host() rule, so Traefik requests and renews its own certificate per domain. nextcloud_url stays canonical — OVERWRITECLIURL, ServerName, and the notify_push setup URL are unaffected, so links Nextcloud generates itself always use nextcloud_url regardless of which domain a request came in on.

Extra mounts

Additional volumes can be injected into the Nextcloud app container using nextcloud_mounts. Provide the value as a YAML block scalar — it is indented directly into the volumes list:

nextcloud_mounts: |
  - /mnt/nas/photos:/mnt/nas/photos:ro
  - /mnt/nas/documents:/mnt/nas/documents:ro

Extra apps

nextcloud_apps installs additional apps from the Nextcloud Store by app ID, for anything not already covered by this role's own feature flags (Talk, ClamAV, Elasticsearch, Collabora):

nextcloud_apps:
  - calendar
  - contacts
  - tasks

Each is installed with occ app:install (idempotent — already-installed apps are skipped) and left at its default configuration. Apps this role configures itself (notify_push, richdocuments, files_antivirus, spreed, the Elasticsearch bundle) don't need to be listed here — installing them via nextcloud_apps too would just be a redundant no-op alongside this role's own install.

ClamAV

Set nextcloud_clamav_enabled: true to deploy a ClamAV container alongside Nextcloud. The files_antivirus app is installed and configured automatically. ClamAV performs an initial signature database download on first start, which may take several minutes before it becomes healthy.

Elasticsearch

Set nextcloud_elasticsearch_enabled: true to deploy a full-text search stack (fulltextsearch, fulltextsearch_elasticsearch, files_fulltextsearch apps). The Elasticsearch container uses the nextcloud/aio-fulltextsearch image. Tune memory with nextcloud_elasticsearch_memory (default 1G).

To force a full re-index:

nextcloud_elasticsearch_reindex: true

Reset to false after the run — leaving it true re-indexes every playbook run.

OpenID Connect

nextcloud_oidc_conf installs the user_oidc app and configures one provider. By default it becomes the only way to log in: /login redirects straight to the provider, the password form is hidden and the lost password link is disabled. Local accounts (e.g. nextcloud_admin_user) keep working as a break-glass path at /login?direct=1. Logging out of Nextcloud also ends the session at the provider. Desktop and mobile clients log in through the browser, so they use the provider too.

Key Required Default Description
discovery_uri yes — Full URL of the provider's .well-known/openid-configuration.
client_id yes — Client ID.
client_secret yes — Client secret.
identifier no sso Provider name in Nextcloud, shown on the login button when only is false.
only no true Redirect /login to the provider and disable the lost password link.
scope no openid email profile Requested scopes.
mapping_uid no preferred_username Claim used as the Nextcloud user ID.
mapping_display_name no name Claim used as the display name.
mapping_email no email Claim used as the email address.
mapping_groups no unset Claim holding the user's groups. Enables group provisioning; the values become group IDs, so admin grants admin rights.
group_whitelist_regex no unset Only provision (and remove) groups matching this regex.
pkce no true Use PKCE for the authorization code flow.
mapping_language no unset Claim with the user's language, e.g. locale from Keycloak. Applied on each login.

Example with Keycloak (client from the keycloak role's keycloak_oidc_clients with roles: [admin]):

nextcloud_oidc_conf:
  discovery_uri: https://auth.example.com/realms/example/.well-known/openid-configuration
  client_id: nextcloud
  client_secret: "{{ vault_nextcloud_oidc_secret }}"
  mapping_groups: roles
  group_whitelist_regex: "^admin$"

Extra hosts

Nextcloud calls its own public URL (Collabora's WOPI callbacks, setup checks) and, with nextcloud_oidc_conf, the provider. When the host can't reach its own public IP (no NAT hairpin on the firewall), pin these names to an internal address that serves them, e.g. the reverse proxy in front:

nextcloud_extra_hosts:
  cloud.example.com: 10.0.0.2
  office.example.com: 10.0.0.2
  auth.example.com: 10.0.0.2

While set, Nextcloud's dns_pinning is turned off: Nextcloud otherwise resolves hostnames itself and ignores /etc/hosts.

Talk

Setting nextcloud_talk_signaling_url installs the Talk (spreed) app and configures the HPB signaling server. STUN, TURN, and recording are independently optional.

Signaling (HPB) — required to enable Talk

nextcloud_talk_signaling_url: signal.example.com
nextcloud_talk_signaling_secret: "{{ vault_talk_signaling_secret }}"

STUN

Replaces all current STUN servers (including the Nextcloud default stun.nextcloud.com:443):

nextcloud_talk_stun_server: turn.example.com:3478

TURN

Configures a TURN server (with turn,turns schemes and udp,tcp protocols):

nextcloud_talk_turn_server: turn.example.com:3478
nextcloud_talk_turn_secret: "{{ vault_talk_turn_secret }}"

Recording backend

nextcloud_talk_recording_url: https://recording.example.com
nextcloud_talk_recording_secret: "{{ vault_talk_recording_secret }}"

Full example combining all features (coturn co-located with HPB is a common setup):

nextcloud_talk_enabled: true
nextcloud_talk_signaling_url: signal.example.com
nextcloud_talk_signaling_secret: "{{ vault_talk_signaling_secret }}"
nextcloud_talk_stun_server: signal.example.com:3478
nextcloud_talk_turn_server: signal.example.com:3478
nextcloud_talk_turn_secret: "{{ vault_talk_turn_secret }}"

Uninstall

To stop and remove all containers and the compose directory:

nextcloud_uninstall: true

To also wipe all data including uploaded files and the database (irreversible):

nextcloud_uninstall: true
nextcloud_purge: true

Notes

  • Nextcloud and Collabora are both Traefik-only — there is no port exposure option. Both nextcloud_url and nextcloud_collabora_url are required.
  • notify_push is deployed automatically and routed via Traefik at /push on nextcloud_url and every nextcloud_extra_domains entry.
  • Imaginary handles image preview generation. It is always deployed alongside Nextcloud.
  • Data directory ownership: db/ is owned by 999:999 mode 0700 (PostgreSQL), data/ and tmp/ by 33:33 (www-data/Nextcloud), elasticsearch/ by 1000:0, clamav/ by root.
  • A host cron job is installed at /etc/cron.d/{{ nextcloud_instance }}-nextcloud that runs cron.php every 5 minutes as www-data.
  • PHP upload limits are set to 200 GiB via a mounted zzz-upload-size.ini. Apache's body limit is disabled (APACHE_BODY_LIMIT=0) so PHP limits are the effective ceiling.