job "onlyoffice" { datacenters = ["dc1"] region = "global" group "onlyoffice" { network { mode = "bridge" # This can be used to ensure rabbitmq has a stable hostname # Even if for now, we do not persist rabbitmq data hostname = "onlyoffice" } volume "data" { source = "onlyoffice-data" type = "csi" access_mode = "single-node-writer" attachment_mode = "file-system" } volume "rabbitmq" { source = "onlyoffice-rabbitmq" type = "csi" access_mode = "single-node-writer" attachment_mode = "file-system" } service { name = "onlyoffice" port = 8819 connect { sidecar_service { proxy { upstreams { destination_name = "postgres" local_bind_port = 5432 # Work arround, see https://github.com/hashicorp/nomad/issues/18538 destination_type = "service" } } } sidecar_task { config { args = [ "-c", "${NOMAD_SECRETS_DIR}/envoy_bootstrap.json", "-l", "${meta.connect.log_level}", "--concurrency", "${meta.connect.proxy_concurrency}", "--disable-hot-restart" ] } resources { cpu = 50 memory = 64 } } } check { name = "health" type = "http" path = "/healthcheck" expose = true interval = "10s" timeout = "8s" check_restart { limit = 30 grace = "2m" } } tags = [ "traefik.enable=true", "traefik.http.routers.onlyoffice.entrypoints=https", "traefik.http.routers.onlyoffice.rule=Host(`oods.example.org`)", "traefik.http.middlewares.csp-onlyoffice.headers.contentsecuritypolicy=connect-src 'self' https://www.zotero.org https://cdn.jsdelivr.net https://cdn.rawgit.com https://translate.googleapis.com https://code.responsivevoice.org https://onlyoffice.github.io;default-src 'self';font-src 'self' data: https://fonts.googleapis.com https://fonts.gstatic.com;frame-src 'self' https://www.youtube.com https://onlyoffice.github.io;img-src 'self' data: https://*;media-src 'self' https://code.responsivevoice.org;script-src 'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: https://ajax.googleapis.com https://www.youtube.com/ https://*.cloudfront.net https://cdn.rawgit.com https://code.jquery.com https://translate.googleapis.com https://code.responsivevoice.org https://cdn.jsdelivr.net https://onlyoffice.github.io;style-src 'self' 'unsafe-inline' data: https://fonts.googleapis.com https://translate.googleapis.com https://onlyoffice.github.io;", "traefik.http.routers.onlyoffice.middlewares=security-headers@file,rate-limit-std@file,forward-proto@file,inflight-std@file,hsts@file,compression@file,csp-onlyoffice", ] } task "docserver" { driver = "docker" leader = true config { image = "danielberteaud/onlyoffice-docserver:8.0.1-2" pids_limit = 200 readonly_rootfs = true volumes = [ "local/:/tmp", "local/metrics.js:/var/www/onlyoffice/documentserver/server/Metrics/config/config.js:ro" ] } vault { policies = ["onlyoffice"] env = false disable_file = true change_mode = "noop" } env { NGINX_LISTEN_IP = "127.0.0.1" APPLICATION_NAME = "onlyoffice" WAIT_FOR_TARGETS = "127.0.0.1:5672" } # Use a template block instead of env {} so we can fetch values from vault template { data = <<_EOT LANG=fr_FR.utf8 OO_JWT_TOKEN={{ with secret "kv/service/onlyoffice" }}{{ .Data.data.jwt_token }}{{ end }} OO_STORAGE_SECRET={{ with secret "kv/service/onlyoffice" }}{{ .Data.data.storage_secret }}{{ end }} TZ=Europe/Paris _EOT destination = "secrets/.env" perms = 400 env = true } # Database settings template { data = <<_EOT OO_DB_NAME='onlyoffice' OO_DB_HOST=127.0.0.1 OO_DB_PORT=5432 OO_DB_USER={{ with secret "database/creds/onlyoffice" }}{{ .Data.username }}{{ end }} OO_DB_PASS={{ with secret "database/creds/onlyoffice" }}{{ .Data.password }}{{ end }} _EOT destination = "secrets/.db.env" uid = 100000 gid = 100000 perms = 400 env = true } template { data = <<_EOT { port: 8125, address: "127.0.0.1", mgmt_address: "127.0.0.1", mgmt_port: 8126, flushInterval: 600000, backends: [ "./backends/console" ] } _EOT destination = "local/metrics.js" } volume_mount { volume = "data" destination = "/var/lib/onlyoffice/documentserver/App_Data/" } resources { cpu = 300 memory = 512 } } # wait for required services tp be ready before starting the main task task "wait-for" { driver = "docker" user = 1053 config { image = "danielberteaud/wait-for:24.3-1" readonly_rootfs = true pids_limit = 20 } lifecycle { hook = "prestart" } env { SERVICE_0 = "master.postgres.service.consul" } resources { cpu = 10 memory = 10 memory_max = 30 } } # Local redis instance task "redis" { driver = "docker" user = 6379 lifecycle { hook = "prestart" sidecar = true } config { image = "redis:alpine" readonly_rootfs = true force_pull = true args = ["/local/redis.conf"] } template { data = <<_EOT bind 127.0.0.1 maxmemory {{ env "NOMAD_MEMORY_LIMIT" | parseInt | subtract 5 }}mb databases 1 save "" appendonly no _EOT destination = "local/redis.conf" } resources { cpu = 300 memory = 512 } } task "rabbitmq" { driver = "docker" #user = 100 lifecycle { hook = "prestart" sidecar = true } config { image = "rabbitmq:alpine" pids_limit = 100 readonly_rootfs = true volumes = [ "local/rabbitmq.conf:/etc/rabbitmq/conf.d/30-oods.conf" ] } # Use a template block instead of env {} so we can fetch values from vault template { data = <<_EOT LANG=fr_FR.utf8 TZ=Europe/Paris _EOT destination = "secrets/.env" perms = 400 env = true } template { data = <<_EOT listeners.tcp.1 = 127.0.0.1:5672 # Set watermark to 95% of the mem allocated to the container #vm_memory_high_watermark.absolute = 155398932 vm_memory_high_watermark.relative = 0.999 _EOT destination = "local/rabbitmq.conf" } volume_mount { volume = "rabbitmq" destination = "/var/lib/rabbitmq" } resources { cpu = 200 memory = 156 } } } }