docker-compose.yaml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. {% from "macros/nc.jinja.sh" import occ, hosts_update, trusted_domains_update, imaginary_url %}
  2. {% from "macros/nc.jinja.conf" import opcache, php, limit_request_body, use_x_real_ip_in_logs, nginx_conf %}
  3. {% set tpl = ix_lib.base.render.Render(values) %}
  4. {# TODO: Remove this in the future #}
  5. {% if values.nextcloud.postgres_image_selector == "postgres_13_image" %}
  6. {% do tpl.notes.add_deprecation("Postgres 13 is deprecated and will be removed in the near future. Please upgrade.") %}
  7. {% endif %}
  8. {% set nc_custom_image = namespace(x=[]) %}
  9. {% if values.nextcloud.apt_packages %}
  10. {% do nc_custom_image.x.append("RUN apt update || { echo 'Failed to update apt cache. Exiting...'; exit 1; }") %}
  11. {# Main packages #}
  12. {% for pkg in values.nextcloud.apt_packages %}
  13. {% do nc_custom_image.x.append("RUN apt install -y --no-install-recommends %s || { echo 'Failed to install [%s]. Exiting...'; exit 1; }"|format(pkg, pkg)) %}
  14. {% endfor %}
  15. {# Additional Dependencies #}
  16. {% for pkg in values.nextcloud.apt_packages if values.consts.packages[pkg] %}
  17. {% for dep in values.consts.packages[pkg].additional_apt %}
  18. {% do nc_custom_image.x.append("RUN apt install -y --no-install-recommends %s || { echo 'Failed to install [%s]. Exiting...'; exit 1; }"|format(dep, dep)) %}
  19. {% endfor %}
  20. {% for dep in values.consts.packages[pkg].pecl %}
  21. {% do nc_custom_image.x.append("RUN pecl install %s || { echo 'Failed to install [%s]. Exiting...'; exit 1; }"|format(dep, dep)) %}
  22. {% endfor %}
  23. {% for dep in values.consts.packages[pkg].docker_php_ext %}
  24. {% do nc_custom_image.x.append("RUN docker-php-ext-enable %s || { echo 'Failed to install [%s]. Exiting...'; exit 1; }"|format(dep, dep)) %}
  25. {% endfor %}
  26. {% for dep in values.consts.packages[pkg].ldd %}
  27. {% do nc_custom_image.x.append("RUN ldd \"$(php -r 'echo ini_get(\"extension_dir\");')\"/%s || { echo 'Failed to install [%s]. Exiting...'; exit 1; }"|format(dep, dep)) %}
  28. {% endfor %}
  29. {# Tesseract OCR #}
  30. {% for lang in values.nextcloud.tesseract_languages if "ocrmypdf" in values.nextcloud.apt_packages %}
  31. {% set lang_pack = "tesseract-ocr-%s" | format(lang|replace("_", "-")) %}
  32. {% do nc_custom_image.x.append("RUN apt install -y --no-install-recommends %s || { echo 'Failed to install [%s]. Exiting...'; exit 1; }"|format(lang_pack, lang_pack)) %}
  33. {% endfor %}
  34. {% endfor %}
  35. {% endif %}
  36. {% set perm_container = tpl.deps.perms(values.consts.perms_container_name) %}
  37. {% set nc_container = tpl.add_container(values.consts.nextcloud_container_name, "image") %}
  38. {% set pg_config = {
  39. "user": values.nextcloud.db_user,
  40. "password": values.nextcloud.db_password,
  41. "database": values.consts.db_name,
  42. "volume": values.storage.postgres_data,
  43. } %}
  44. {% set postgres = tpl.deps.postgres(
  45. values.consts.postgres_container_name,
  46. values.nextcloud.postgres_image_selector,
  47. pg_config, perm_container
  48. ) %}
  49. {% do tpl.funcs.disallow_chars(values.nextcloud.redis_password, ["&", "@", "#", "%"], "redis_password") %}
  50. {% set redis_config = {
  51. "password": values.nextcloud.redis_password,
  52. "volume": {"type": "temporary", "volume_config": {"volume_name": "redis-data"}},
  53. } %}
  54. {% set redis = tpl.deps.redis(values.consts.redis_container_name, "redis_image", redis_config, perm_container) %}
  55. {% set nc_caps = ["CHOWN", "FOWNER", "DAC_OVERRIDE", "SETGID", "SETUID", "NET_BIND_SERVICE", "NET_RAW"] %}
  56. {# https://github.com/nextcloud/docker/issues/1796 #}
  57. {% set nc_confs = [
  58. ("occ", occ(values), "/usr/local/bin/occ", "0755"),
  59. ("opcache.ini", opcache(values), "/usr/local/etc/php/conf.d/opcache-z-99.ini", ""),
  60. ("php.ini", php(values), "/usr/local/etc/php/conf.d/nextcloud-z-99.ini", ""),
  61. ("limitrequestbody.conf", limit_request_body(values), "/etc/apache2/conf-enabled/limitrequestbody.conf", ""),
  62. ] %}
  63. {% set nc_storage = namespace(x=[
  64. ("/tmp", {"type": "anonymous", "volume_config": {}}),
  65. ]) %}
  66. {% do nc_storage.x.append(("/var/www/html", values.storage.html)) %}
  67. {% do nc_storage.x.append((values.nextcloud.data_dir_path, values.storage.data)) %}
  68. {% for store in values.storage.additional_storage %}
  69. {% do nc_storage.x.append((store.mount_path, store)) %}
  70. {% endfor %}
  71. {% set nc_env = namespace(x=[
  72. ("NEXTCLOUD_DATA_DIR", values.nextcloud.data_dir_path),
  73. ("PHP_UPLOAD_LIMIT", "%dG"|format(values.nextcloud.php_upload_limit)),
  74. ("PHP_MEMORY_LIMIT", "%dM"|format(values.nextcloud.php_memory_limit)),
  75. ("NEXTCLOUD_ADMIN_USER", values.nextcloud.admin_user),
  76. ("NEXTCLOUD_ADMIN_PASSWORD", values.nextcloud.admin_password),
  77. ("REDIS_HOST_PORT", 6379),
  78. ("REDIS_HOST", values.consts.redis_container_name),
  79. ("REDIS_HOST_PASSWORD", values.nextcloud.redis_password),
  80. ("POSTGRES_PASSWORD", values.nextcloud.db_password),
  81. ("POSTGRES_HOST", postgres.get_url("host_port")),
  82. ("POSTGRES_DB", values.consts.db_name),
  83. ("POSTGRES_USER", values.nextcloud.db_user),
  84. ]) %}
  85. {% set trusted_domains = namespace(x=["127.0.0.1", "localhost", values.consts.nextcloud_container_name]) %}
  86. {% set host = namespace(x="") %}
  87. {% if values.nextcloud.host %}
  88. {% set host.x = values.nextcloud.host if ":" in values.nextcloud.host else "%s:%d"|format(values.nextcloud.host, values.network.web_port.port_number) %}
  89. {% set host.x = host.x.replace("https://", "").replace("http://", "") %}
  90. {% endif %}
  91. {% if values.network.certificate_id %}
  92. {% do nc_env.x.append(("APACHE_DISABLE_REWRITE_IP", 1)) %}
  93. {% do nc_env.x.append(("OVERWRITEPROTOCOL", "https")) %}
  94. {% do nc_env.x.append(("TRUSTED_PROXIES", ["127.0.0.1", "192.168.0.0/16", "172.16.0.0/12", "10.0.0.0/8"] | join(" "))) %}
  95. {% do nc_confs.append(("logformat.conf", use_x_real_ip_in_logs(), "/etc/apache2/conf-enabled/logformat.conf", "")) %}
  96. {% if values.nextcloud.host and values.network.nginx.use_different_port %}
  97. {% set temp_host = values.nextcloud.host.split(":") %}
  98. {% if temp_host[1] and temp_host[1] != values.network.nginx.external_port %}
  99. {% do tpl.notes.add_warning("The port in the Host field is different from the external port. The port from the Host field will be ignored.") %}
  100. {% endif %}
  101. {% set host.x = "%s:%d"|format(temp_host[0], values.network.nginx.external_port) %}
  102. {% set host.x = host.x.replace("https://", "").replace("http://", "") %}
  103. {% do nc_env.x.append(("OVERWRITEHOST", host.x)) %}
  104. {% endif %}
  105. {% endif %}
  106. {% if host.x %}
  107. {% set parsed_url = tpl.funcs.url_to_dict(host.x, true) %}
  108. {% do trusted_domains.x.append(parsed_url.host) %}
  109. {% endif %}
  110. {% do nc_env.x.append(("NEXTCLOUD_TRUSTED_DOMAINS", trusted_domains.x|unique|list|join(" "))) %}
  111. {% do nc_container.build_image(nc_custom_image.x) %}
  112. {% do nc_container.set_user(0,0) %}
  113. {% do nc_container.add_caps(nc_caps) %}
  114. {% do nc_container.healthcheck.set_test("curl", {"port": 80, "path": "/status.php", "headers": [("Host", "localhost")]}) %}
  115. {% do nc_container.depends.add_dependency(values.consts.postgres_container_name, "service_healthy") %}
  116. {% do nc_container.depends.add_dependency(values.consts.redis_container_name, "service_healthy") %}
  117. {% do nc_container.configs.add("ix-update-hosts-script.sh", hosts_update(values), "/docker-entrypoint-hooks.d/before-starting/ix-update-hosts-script.sh", "0755") %}
  118. {% do nc_container.configs.add("ix-update-trusted-domains-script.sh", trusted_domains_update(), "/docker-entrypoint-hooks.d/before-starting/ix-update-trusted-domains-script.sh", "0755") %}
  119. {% for c in nc_confs %}
  120. {% do nc_container.configs.add(c[0], c[1], c[2], c[3]) %}
  121. {% endfor %}
  122. {% for e in nc_env.x %}
  123. {% do nc_container.environment.add_env(e[0], e[1]) %}
  124. {% endfor %}
  125. {% for s in nc_storage.x %}
  126. {% do nc_container.add_storage(s[0], s[1]) %}
  127. {% endfor %}
  128. {% if not values.network.certificate_id %}
  129. {% do nc_container.add_port(values.network.web_port, {"container_port": 80}) %}
  130. {% endif %}
  131. {% if values.nextcloud.imaginary.enabled %}
  132. {% do nc_container.configs.add(
  133. "ix-imaginary-url.sh",
  134. imaginary_url(values.consts.imaginary_container_name, values.consts.imaginary_port),
  135. "/docker-entrypoint-hooks.d/before-starting/ix-imaginary-url.sh", "0755",
  136. ) %}
  137. {% endif %}
  138. {% do nc_container.environment.add_user_envs(values.nextcloud.additional_envs) %}
  139. {% if values.nextcloud.cron.enabled %}
  140. {% set cron_container = tpl.add_container(values.consts.cron_container_name, "image") %}
  141. {% do cron_container.build_image(nc_custom_image.x) %}
  142. {% do cron_container.set_user(0,0) %}
  143. {% do cron_container.add_caps(nc_caps) %}
  144. {% do cron_container.healthcheck.set_custom_test("pidof busybox > /dev/null") %}
  145. {% do cron_container.set_entrypoint(["/bin/sh", "-c"]) %}
  146. {% set cmd = [
  147. "echo '%s php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data || { echo 'Failed to create crontab'; exit 1; }"|format(values.nextcloud.cron.schedule),
  148. "/cron.sh || { echo 'Failed to run cron'; exit 1; }"
  149. ]|join("\n") %}
  150. {% do cron_container.set_command([cmd]) %}
  151. {% do cron_container.depends.add_dependency(values.consts.nextcloud_container_name, "service_healthy") %}
  152. {% for c in nc_confs %}
  153. {% do cron_container.configs.add(c[0], c[1], c[2], c[3]) %}
  154. {% endfor %}
  155. {% for e in nc_env.x %}
  156. {% do cron_container.environment.add_env(e[0], e[1]) %}
  157. {% endfor %}
  158. {% for s in nc_storage.x %}
  159. {% do cron_container.add_storage(s[0], s[1]) %}
  160. {% endfor %}
  161. {% do cron_container.environment.add_user_envs(values.nextcloud.additional_envs) %}
  162. {% endif %}
  163. {% if values.nextcloud.imaginary.enabled %}
  164. {% set imaginary_container = tpl.add_container(values.consts.imaginary_container_name, "imaginary_image") %}
  165. {% do imaginary_container.add_caps(["SYS_NICE"]) %}
  166. {% do imaginary_container.set_user(568, 568) %}
  167. {% do imaginary_container.healthcheck.set_test("wget", {"port": 9000, "path": "/health"}) %}
  168. {% endif %}
  169. {% if values.network.certificate_id %}
  170. {% set nginx_container = tpl.add_container(values.consts.nginx_container_name, "nginx_image") %}
  171. {% do nginx_container.deploy.resources.remove_devices() %}
  172. {% do nginx_container.add_caps(["NET_BIND_SERVICE", "CHOWN", "FOWNER", "DAC_OVERRIDE", "SETGID", "SETUID", "NET_RAW"]) %}
  173. {% do nginx_container.depends.add_dependency(values.consts.nextcloud_container_name, "service_healthy") %}
  174. {% do nginx_container.configs.add("private", values.ix_certificates[values.network.certificate_id].privatekey, values.consts.ssl_key_path) %}
  175. {% do nginx_container.configs.add("public", values.ix_certificates[values.network.certificate_id].certificate, values.consts.ssl_cert_path) %}
  176. {% do nginx_container.configs.add("nginx.conf", nginx_conf(values), "/etc/nginx/nginx.conf", "0600") %}
  177. {% for conf_path in values.network.nginx.custom_confs %}
  178. {% do nginx_container.add_storage("/etc/nginx/includes/%d.conf"|format(loop.index0), {"type": "host_path", "host_path_config": {"path": conf_path}}) %}
  179. {% endfor %}
  180. {% do nginx_container.add_storage("/tmp", {"type": "anonymous", "volume_config": {}}) %}
  181. {% do nginx_container.healthcheck.set_test("curl", {
  182. "port": values.network.web_port.port_number, "path": "/status.php",
  183. "headers": [("Host", "localhost")], "scheme": "https"
  184. }) %}
  185. {% do nginx_container.add_port(values.network.web_port) %}
  186. {% endif %}
  187. {% if perm_container.has_actions() %}
  188. {% do perm_container.activate() %}
  189. {% do nc_container.depends.add_dependency(values.consts.perms_container_name, "service_completed_successfully") %}
  190. {% do redis.container.depends.add_dependency(values.consts.perms_container_name, "service_completed_successfully") %}
  191. {% do postgres.add_dependency(values.consts.perms_container_name, "service_completed_successfully") %}
  192. {% endif %}
  193. {% do tpl.portals.add(values.network.web_port, {"scheme": "https" if values.network.certificate_id else "http"}) %}
  194. {{ tpl.render() | tojson }}