version: "3.7" services: letsencrypt-git: # nginx reverse proxy for all apps (except drone in a subdomain) # automatically obtains and refreshes ssl certificates with letsencrypt deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}letsencrypt-git environment: - CERTBOT_EMAIL=${CERTBOT_EMAIL} - SERVER_NAME=${GIT_DOMAIN} - GIT_PROXY_PASS=http://gitea:3000/ - BLOG_PROXY_PASS=http://ghost:2368/ - CHAT_PROXY_PASS=http://chat:3000/ - COMMENTO_PROXY_PASS=http://commento:8080/ - REMOTE_PROXY_PASS=http://guacamole:8080/guacamole/ - DRONE_PROXY_PASS=http://drone-server:8080/ - REGISTRY_PROXY_PASS=http://registry-1:5000 - PORTAINER_PROXY_PASS=http://portainer:9000/ - PORTAINER_LOCATION=/portainer/ - MATOMO_PROXY_PASS=http://matomo-web/ - MATOMO_LOCATION=/analytics/ - NAGIOS_PROXY_PASS=http://nagios/ - NAGIOS_LOCATION=/nagios/ - ZABBIX_PROXY_PASS=http://zabbix-web:8080/ - ZABBIX_LOCATION=/zabbix/ - GIT_LOCATION=/git/ - BLOG_LOCATION=/ - CHAT_LOCATION=/chat/ - COMMENTO_LOCATION=/comment/ - REMOTE_LOCATION=/remote/ - DRONE_SERVER_HOST=$DRONE_SERVER_HOST - TITLE=$TITLE - DESCRIPTION=$DESCRIPTION - DRONE_REPO_LINK=$DRONE_REPO_LINK - DRONE_COMMIT=$DRONE_COMMIT volumes: - letsencrypt-git:/etc/letsencrypt networks: - appnet ports: - 80:80 - 443:443 - 5000:5000 - 5001:5001 - 5005:5005 letsencrypt-drone: # reverse proxy for drone in a subdomain deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 0 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}letsencrypt-drone environment: - CERTBOT_EMAIL=${CERTBOT_EMAIL} - SERVER_NAME=${DRONE_DOMAIN} - PROXY_PASS=http://drone-server:8080/ volumes: - letsencrypt-drone:/etc/letsencrypt networks: - appnet gitea: # gitea application deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}gitea environment: - USER_UID=1000 - USER_GID=1000 - ROOT_URL=https://${GIT_DOMAIN}/git - SSH_DOMAIN=${GIT_DOMAIN} - GITEA_APP_NAME=${GITEA_APP_NAME} - GIT_DOMAIN=${GIT_DOMAIN} - GITEA_SERVER_LFS_JWT_SECRET=$GITEA_SERVER_LFS_JWT_SECRET - GITEA_SECURITY_SECRET_KEY=$GITEA_SECURITY_SECRET_KEY - GITEA_SECURITY_INTERNAL_TOKEN=$GITEA_SECURITY_INTERNAL_TOKEN - GITEA_OAUTH2_JWT_SECRET=$GITEA_OAUTH2_JWT_SECRET - GITEA_MAILER_HOST=$GITEA_MAILER_HOST - GITEA_MAILER_USER=$GITEA_MAILER_USER - GITEA_MAILER_FROM=$GITEA_MAILER_FROM - GITEA_MAILER_PASSWD=$GITEA_MAILER_PASSWD volumes: - gitea-app:/data ports: - 3000:3000 - 22:22 networks: - appnet ngrok: # ngrok tunnel client deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 0 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}ngrok-gitea ports: - "4040:4040" environment: - GIT_DOMAIN=${GIT_DOMAIN} - DRONE_DOMAIN=${DRONE_DOMAIN} - REMOTE_DOMAIN=${REMOTE_DOMAIN} - BLOG_DOMAIN=${BLOG_DOMAIN} - CHAT_DOMAIN=${CHAT_DOMAIN} - NGROK_AUTH_TOKEN=${NGROK_AUTH_TOKEN} networks: - appnet drone-server: # drone server application deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: drone/drone:1.7.0 volumes: - drone:/var/lib/drone - drone-data:/data environment: - DRONE_LOGS_DEBUG=true - DRONE_LOGS_PRETTY=true - DRONE_GITEA_SERVER=${DRONE_GITEA_SERVER} - DRONE_GITEA_CLIENT_ID=${DRONE_GITEA_CLIENT_ID} - DRONE_GITEA_CLIENT_SECRET=${DRONE_GITEA_CLIENT_SECRET} - DRONE_SERVER_HOST=${DRONE_SERVER_HOST} # tunnel hostname - DRONE_ADMIN=giles - DRONE_SERVER_PROTO=https # tunnel adds https on top - DRONE_SERVER_PORT=:8080 - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} - DRONE_USER_CREATE=username:giles,admin:true - DRONE_AGENTS_ENABLED=true - DRONE_CONVERT_PLUGIN_ENDPOINT=http://drone-starlark:3000 - DRONE_CONVERT_PLUGIN_SECRET=${DRONE_CONVERT_SECRET} networks: - appnet drone-docker-runner: # drone runner performs builds deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: drone/drone-runner-docker:1 volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - DRONE_RPC_PROTO=https - DRONE_RPC_HOST=${DRONE_SERVER_HOST} - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} - DRONE_RUNNER_CAPACITY=8 - DRONE_RUNNER_NAME="docker-runner" drone-starlark: # drone starlark server converts starlark to yaml deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}drone-starlark environment: - DRONE_DEBUG=true - DRONE_SECRET=${DRONE_CONVERT_SECRET} - DRONE_STARLARK_REPO_PATHS=this:/repos - SIGYL_STACK_NAME=$SIGYL_STACK_NAME - SIGYL_STACK_ROOT=$SIGYL_STACK_ROOT networks: - appnet registry: # internal registry deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: registry:2 volumes: - registry-data:/var/lib/registry environment: - REGISTRY_HTTP_ADDR=0.0.0.0:5000 - REGISTRY_HTTP_TLS_CERTIFICATE="/run/secrets/registry-cert" - REGISTRY_HTTP_TLS_KEY="/run/secrets/registry-key" networks: - appnet secrets: - registry-cert - registry-key ports: - 5003:5000 registry-1: # internal registry #1 (why?) deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: registry:2 volumes: - registry-data:/var/lib/registry environment: - REGISTRY_HTTP_ADDR=0.0.0.0:5000 networks: - appnet registry-cache: # registry cache (used?) deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: registry:2 ports: - 5002:5001 volumes: - registry-cache-data:/var/lib/registry environment: - REGISTRY_HTTP_ADDR=0.0.0.0:5001 - REGISTRY_HTTP_TLS_CERTIFICATE="/run/secrets/registry-cert" - REGISTRY_HTTP_TLS_KEY="/run/secrets/registry-key" - REGISTRY_PROXY_REMOTEURL=http://registry-1.docker.io networks: - appnet secrets: - registry-cert - registry-key ghost: # ghost blog deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}ghost volumes: - ghost-content-images:/var/lib/ghost/content/images - ghost-content-settings:/var/lib/ghost/content/settings - ghost-content-adapters:/var/lib/ghost/content/adapters - ghost-content-data:/var/lib/ghost/content/data - ghost-content-logs:/var/lib/ghost/content/logs environment: - GIT_DOMAIN=$GIT_DOMAIN - GHOST-MAIL-SERVICE=$GHOST-MAIL-SERVICE - GHOST-MAIL-USER=$GHOST-MAIL-USER - GHOST-MAIL-PASSWORD=$GHOST-MAIL-PASSWORD - COMMENTO_ORIGIN=$COMMENTO_ORIGIN - database__client=mysql - database__connection__host=ghost-mysql - database__connection__user=root - database__connection__password=$GHOST_MYSQL_ROOT_PASSWORD - database__connection__database=ghost networks: - appnet ghost-mysql: image: mysql:5.7 deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any volumes: - ghost-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: $GHOST_MYSQL_ROOT_PASSWORD networks: - appnet commento: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: registry.gitlab.com/commento/commento:latest environment: COMMENTO_ORIGIN: $COMMENTO_ORIGIN COMMENTO_SMTP_PASSWORD: $COMMENTO_SMTP_PASSWORD COMMENTO_ASKIMET_KEY: $COMMENTO_ASKIMET_KEY COMMENTO_SMTP_HOST: $COMMENTO_SMTP_HOST COMMENTO_SMTP_PORT: $COMMENTO_SMTP_PORT COMMENTO_SMTP_USERNAME: $COMMENTO_SMTP_USERNAME COMMENTO_SMTP_FROM_ADDRESS: $COMMENTO_SMTP_FROM_ADDRESS COMMENTO_GITHUB_KEY: $COMMENTO_GITHUB_KEY COMMENTO_GITHUB_SECRET: $COMMENTO_GITHUB_SECRET COMMENTO_FORBID_NEW_OWNERS: $COMMENTO_FORBID_NEW_OWNERS COMMENTO_PORT: 8080 COMMENTO_POSTGRES: postgres://${COMMENTO_POSTGRES_USER}:${COMMENTO_POSTGRES_PASSWORD}@commento-postgres:5432/${COMMENTO_POSTGRES_DB}?sslmode=disable networks: - appnet commento-postgres: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: postgres:11-alpine environment: POSTGRES_DB: ${COMMENTO_POSTGRES_DB} POSTGRES_USER: ${COMMENTO_POSTGRES_USER} POSTGRES_PASSWORD: ${COMMENTO_POSTGRES_PASSWORD} networks: - appnet volumes: - commento-postgresql-data:/var/lib/postgresql/data guacamole-postgresql: # database for guacamole deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: ${LOCAL_DOCKER_REGISTRY}guacamole-postgresql:latest environment: POSTGRES_PASSWORD: ${GUACAMOLE_POSTGRES_PASSWORD} POSTGRES_DB: ${GUACAMOLE_POSTGRES_DB} volumes: - guacamole-postgresql-data:/var/lib/postgresql/data networks: - appnet nagios: image: jasonrivers/nagios:latest deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any environment: - NAGIOSADMIN_USER=${NAGIOS_ADMIN_USER} - NAGIOSADMIN_PASS=${NAGIOS_ADMIN_PASSWORD} volumes: - ./nagios/conf.d:/opt/nagios/etc/conf.d/ - ./nagios/contacts/contacts.cfg:/opt/nagios/etc/objects/contacts.cfg networks: - appnet matomo: image: matomo:fpm-alpine deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any volumes: # - ./config:/var/www/html/config:rw # - ./logs:/var/www/html/logs - matomo:/var/www/html environment: - MATOMO_DATABASE_HOST=matomo-mariadb - MYSQL_PASSWORD=${MATOMO_MYSQL_PASSWORD} - MYSQL_DATABASE=matomo - MYSQL_USER=matomo - MATOMO_DATABASE_ADAPTER=mysql - MATOMO_DATABASE_TABLES_PREFIX=matomo_ - MATOMO_DATABASE_USERNAME=matomo - MATOMO_DATABASE_PASSWORD=${MATOMO_MYSQL_PASSWORD} - MATOMO_DATABASE_DBNAME=matomo networks: - appnet matomo-web: image: nginx:alpine deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any volumes: - matomo:/var/www/html:ro # see https://github.com/matomo-org/matomo-nginx - ./matomo/matomo.conf:/etc/nginx/conf.d/default.conf:ro networks: - appnet matomo-mariadb: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: mariadb:10 command: --max-allowed-packet=128MB networks: - appnet volumes: - matomo-mariadb:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: ${MATOMO_MYSQL_ROOT_PASSWORD} MYSQL_USER: matomo MYSQL_DATABASE: matomo MYSQL_PASSWORD: ${MATOMO_MYSQL_PASSWORD} zabbix-mariadb: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: mariadb:10 command: --max-allowed-packet=128MB networks: - appnet volumes: - zabbix-mariadb:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: ${ZABBIX_MYSQL_ROOT_PASSWORD} MYSQL_USER: zabbix MYSQL_DATABASE: zabbix MYSQL_PASSWORD: ${ZABBIX_MYSQL_PASSWORD} zabbix-server: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: zabbix/zabbix-server-mysql networks: - appnet environment: DB_SERVER_HOST: zabbix-mariadb MYSQL_USER: zabbix MYSQL_PASSWORD: ${ZABBIX_MYSQL_PASSWORD} networks: - appnet ports: - 10050:10050 - 10051:10051 zabbix-web: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: zabbix/zabbix-web-nginx-mysql networks: - appnet environment: DB_SERVER_HOST: zabbix-mariadb MYSQL_USER: zabbix MYSQL_PASSWORD: ${ZABBIX_MYSQL_PASSWORD} ZBX_SERVER_HOST: zabbix-server PHP_TZ: Europe/London # The backend guacamole server. guacd: deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: guacamole/guacd:latest networks: - appnet guacamole: deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 1 restart_policy: condition: any image: guacamole/guacamole:latest environment: - POSTGRES_HOSTNAME=guacamole-postgresql - POSTGRES_PORT=5432 - POSTGRES_USER=${GUACAMOLE_POSTGRES_USER} - POSTGRES_PASSWORD=${GUACAMOLE_POSTGRES_PASSWORD} - POSTGRES_DATABASE=${GUACAMOLE_POSTGRES_DB} - GUACD_HOSTNAME=guacd networks: - appnet chat: deploy: placement: constraints: [node.labels.com.sigyl.git-stack == yes] replicas: 0 # will scale after mongo initated restart_policy: condition: any image: rocketchat/rocket.chat:3.0.7 networks: - appnet environment: - MONGO_OPLOG_URL=mongodb://chat-mongo:27017/local - ROOT_URL=https://${GIT_DOMAIN}/chat - PORT=3000 - MONGO_URL=mongodb://chat-mongo:27017/rocketchat - ADMIN_USERNAME=${CHAT_ADMIN_NAME} - ADMIN_PASS=${CHAT_ADMIN_PASSWORD} - ADMIN_EMAIL=${CHAT_ADMIN_EMAIL} volumes: - chat-uploads:/app/uploads chat-mongo: deploy: placement: constraints: [node.labels.com.sigyl.git-stack-data == yes] replicas: 1 restart_policy: condition: any image: mongo:4.0 networks: - appnet environment: - MONGO_DATA_DIR=/data/db - MONGO_LOG_DIR=/dev/null volumes: - mongo-chat:/data/db command: mongod --smallfiles --replSet rs0 --oplogSize 128 portainer: image: portainer/portainer:1.23.2 command: -H tcp://tasks.portainer-agent:9001 --tlsskipverify # command: -H unix:///var/run/docker.sock deploy: replicas: 1 placement: constraints: [node.role == manager] restart_policy: condition: any volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer-data:/data networks: #- proxy - appnet portainer-agent: image: portainer/agent:1.5.1 environment: # REQUIRED: Should be equal to the service name prefixed by "tasks." when # deployed inside an overlay network AGENT_CLUSTER_ADDR: tasks.portainer-agent # AGENT_PORT: 9001 # LOG_LEVEL: debug volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes networks: - appnet deploy: mode: global placement: constraints: [node.platform.os == linux] volumes: gitea-app: drone: drone-data: registry-data: registry-cache-data: guacamole-postgresql-data: commento-postgresql-data: letsencrypt-git: letsencrypt-drone: ghost-content: ghost-data: ghost-content-adapters: ghost-content-settings: ghost-content-images: ghost-content-data: ghost-content-logs: mongo-chat: chat-uploads: portainer-data: matomo: matomo-mariadb: zabbix-mariadb: networks: appnet: driver: overlay #external: true secrets: 'registry-cert': file: .certificates/registry.crt 'registry-key': file: .certificates/registry.key