Can GPT5 / Claude Sonet replace me and my team ?



Can AI Agents replace my team including myself ?

Seems to be the question on everyones mind lately. Well can they really ?. Let's find out shall we ?

Spoiler alert, the answer is not a simple YES or NO. 

Vibe Coding

Lets gets some things clarified. I'm not vibe coding here. I have strong opinions about the pitfalls of vibe coding in production systems. This is not the place to discuss that. I don't exactly know what to call this but to put things simply I'm using AI with well defined context to do this experiment. 

Credits

This project is based on Ed Donner's CrewAI project featured in The Complete AI Engineering Course, If you are interested in learning more you should check out the learning material by Ed Donner. I highly recommend them. 

The Project

In order to test out this hypothesis I'm gonna use Crew AI . The title was a catchy one, the project however has a narrower context. I'm not trying to create an AI Engineering team to replace us humans, rather experimenting to see how we can use AI to boost our productivity. 

The problem I have chosen, I believe is not too complex, not too simple. This will allow me to analyze the results easily and get a good baseline for further experimentation. 

The task is to get a containerized solution up and running to a provided problem statement. Which is classified as an "assignment" in the below config. We'll go into details when analyzing the two different approaches. 

Task Definitions

design_task:
  description: >
    Create a solution determining what docker images can be used to solve the {assignment}
    Follow docker and docker compose best practices
    IMPORTANT: Output ONLY the raw markdown without any markdown formatting, code block delimiters, or backticks.
    the current year is {current_year}.
  expected_output: >
    A docker compose file to do the {assignment}
  agent: senior_engineer
  output_file: output/design.md

coding_task:
  description: >
    Create a docker compose file that implements the design described by senior_engineer, in order to achieve the requirements.
    Here are the requirements: {assignment}
    Follow docker and docker compose best practices
    IMPORTANT: Output ONLY the raw docker compose code without any markdown formatting, code block delimiters, or backticks.
    the current year is {current_year}.
  expected_output: >
    A docker compose file to do the {assignment}
  agent: docker_engineer
  context:
    - design_task
  output_file: output/docker-compose.yml

documentation_task:
  description: >
    Create a readme.md markdown file explaining the docker compose file and how to run it
    IMPORTANT: Output ONLY the raw markdown code without any markdown formatting, code block delimiters, or backticks.
    the current year is {current_year}.
  expected_output: >
    A readme.md file explaining the solution and how to run it
  agent: docker_engineer
  context:
    - coding_task
  output_file: output/readme.md    

Give me the details, gimme, gimme

I try two different approaches in this experiment. The first approach is to use a human senior engineer with an AI engineer to build the system. The human senior engineer is going to provide very prescriptive instructions for the AI engineer to complete the task in hand. 

In the second approach we are going to use two different AI agents. One senior engineer which we will equip with design capabilities. We are gonna provide this agent with a problem statement with some guidelines. Then this senior AI agent is going to create the prescriptive instructions that will be used by the same AI engineer from the pervious  example to produce the code. 

Models Used

I tried using different models to try out this concept
  • Claude Sonet 4 (claude-sonnet-4-20250514) by Anthropic
  • gpt-4.1 by OpenAI
  • gpt5 by OpenAI
  • deepseek-chat by DeepSeek
  • llama3.2 by Meta hosted with Ollama locally

Human Senior Engineer with an AI Engineering team

In the first approach we have a human senior engineer providing the detailed instructions to the AI engineering team. The senior engineer is going to provide a very prescriptive task for the AI engineers
assignment = f"""Created a self hosted nextcloud instance. Use the docker hub image nextcloud:31.0.8-apache
use mariadb:10.11 as the database 
use redis:alpine3.22 with nextcloud
create separate containers for nextcloud and cron jobs
Use jc21/nginx-proxy-manager:latest as a reverse proxy to expose the nextcloud instance to the internet
# """

AI Senior Engineer with an AI Engineering Team

In the second approach the senior engineer is also replaced by an AI Agent. We provide the problem statement to the AI Senior Engineering Agent. This agent in turn is gonna provide a prescriptive task for the crew to generate the output
assignment = f"""Created a self hosted nextcloud instance. 
Think about separation of concerns, maintainability and other software development best practices
The instance needs to be exposed to the internet
The same server that is going to host the nextcloud instance also has some simple websites exposed to the internet
The nextcloud instance and the other websites need their own ssl certificates 
The server hosting all these is behind a pfsense firewall
"""

Agent Definitions

senior_engineer:
  role: >
    Engineer with extensive knowledge about software development practices including web based security vulnerabilities
  goal: >
    Provide solutions for complex software problems
  backstory: >
    You're a tenured engineer with extensive knowledge about software engineering
    You are able to create software designs that can guide other engineers in creating solutions
  llm: anthropic/claude-sonnet-4-20250514

docker_engineer:
  role: >
    Engineer with extensive knowledge about docker and docker compose
  goal: >
    Generate docker compose files with explanations
  backstory: >
    You're a tenured engineer with extensive knowledge about docker and docker compose. 
    You are able to create working docker compose files following best practices to fulfill the given requirements.
  llm: anthropic/claude-sonnet-4-20250514

Output and Conclusions

To be honest this exercise is too narrow and simplistic to come to a concrete conclusion. It does show some good data points though. (Full outputs in appendix)

When it comes to agents I was not able to produce good results with deepseek-chat or llama3.2. Only the frontier models were able to provide good enough data points in this project. 

The first approach created a good simple working solution sticking with the provided guidelines. The second approach created a novel solution which could be classified as overkill. Though on second thought narrowing down the requirements to specify the host environment would have generated better results. 

Some interesting observations include, 

When acting as the Senior Engineer GPT 4.1 choose to use NGINX as the proxy where as GPT5 choose to use Traefik. According to Gemini, Traefik is more suitable for dynamic environments like Docker and Kubernetes. For the simple task definition NGINX would have been acceptable but I can't argue with using Traefik either. The problem statement didn't have enough information about the future extensibility or the available resourcing to lean towards one vs the other. 

As the senior engineer GPT5 choose to use Postgress for the database where GPT 4.1 used MariaDB. The decision between these 2 also is a hard one. If you are curious read more here

In my opinion, both these decision differences indicate GPT5 chose the more modern options than GPT 4.1 in this particular problem. It could simply be due to the training data. 

Claude Sonet 4 failed to act as the senior engineer for my project. It kept giving me "{type:error,error:{type:overloaded_error,message:Overloaded},request_id:null}". I see this error often when I try to do tasks needing more tokens. This I believe is due to the basic plan I'm paying for, not due to the capabilities of the Model.

DeepSeek-Chat hallucinated and returned a template project. Llama 3.2 failed as well. Indicating I'm trying to do too much with them. 

When working with a human senior engineer the results were very similar across all frontier models. 

Check out the appendix section for detailed outputs. 

Conclusion

Well, AI has been a force multiplier when it comes to increasing my productivity. I'm not sold on the fact that AI will be able to completely replace us, however it sure is allowing us to do more with less. How that will pan out, only time will tell. 

I'm excited for the future. What mistakes we will create vibe coding, what we will learn from those mistakes. Potential innovations we will see with responsible AI usage.... etc... etc...

Appendix 

GPT 4.1 output (ai senior engineer)


version: "3.9"

services:
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:2.11.2
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    environment:
      - TZ=UTC
    networks:
      - frontend

  db:
    image: mariadb:11
    container_name: nextcloud-db
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    environment:
      - MYSQL_ROOT_PASSWORD=secure_root_password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=secure_nextcloud_password
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - backend

  nextcloud:
    image: nextcloud:28
    container_name: nextcloud-app
    restart: unless-stopped
    expose:
      - "80"
    environment:
      - MYSQL_PASSWORD=secure_nextcloud_password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=db
    volumes:
      - nextcloud_data:/var/www/html
    depends_on:
      - db
    networks:
      - frontend
      - backend

  web1:
    image: nginx:1.25
    container_name: simple-web1
    restart: unless-stopped
    volumes:
      - ./web1/html:/usr/share/nginx/html:ro
      - ./web1/nginx.conf:/etc/nginx/nginx.conf:ro
    expose:
      - "80"
    networks:
      - frontend

  web2:
    image: nginx:1.25
    container_name: simple-web2
    restart: unless-stopped
    volumes:
      - ./web2/html:/usr/share/nginx/html:ro
      - ./web2/nginx.conf:/etc/nginx/nginx.conf:ro
    expose:
      - "80"
    networks:
      - frontend

volumes:
  npm_data:
  npm_letsencrypt:
  db_data:
  nextcloud_data:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

GPT 5 output (ai senior engineer)


name: selfhosted-apps

# Compose Specification (no version field needed in modern Compose)
# Requirements before use:
# - Create a .env file with:
#     TRAEFIK_ACME_EMAIL=you@example.com
#     NEXTCLOUD_DOMAIN=cloud.example.com
#     SITE1_DOMAIN=site1.example.com
#     SITE2_DOMAIN=site2.example.com
# - Create secrets/nextcloud_db_password.txt with a strong DB password
# - On pfSense: port-forward TCP 80 and 443 to this Docker host
# - Ensure DNS A/AAAA records for all domains point to your public IP

services:
  # Reverse proxy and TLS termination with automatic per-domain certificates
  traefik:
    image: traefik:v3.1
    command:
      - --providers.docker=true
      - --providers.docker.endpoint=tcp://docker-socket-proxy:2375
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=proxy
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL}
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
      - --log.level=INFO
      - --accesslog=true
    ports:
      - 80:80
      - 443:443
    volumes:
      - traefik_letsencrypt:/letsencrypt
    networks:
      - proxy
      - dockerproxy
    depends_on:
      - docker-socket-proxy
    # Run as non-root with capability to bind low ports
    user: "65532:65532"
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped
    labels:
      - traefik.enable=true
      # Shared middlewares for security and compression
      - traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000
      - traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true
      - traefik.http.middlewares.secure-headers.headers.stsPreload=true
      - traefik.http.middlewares.secure-headers.headers.referrerPolicy=no-referrer
      - traefik.http.middlewares.secure-headers.headers.browserXssFilter=true
      - traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true
      - traefik.http.middlewares.compress.compress=true

  # Safer Docker socket access for Traefik (principle of least privilege)
  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy:latest
    environment:
      - CONTAINERS=1
      - SERVICES=1
      - TASKS=1
      - NETWORKS=1
      - NODES=1
      - INFO=1
      - PING=1
      - VERSION=1
      - EVENTS=1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    expose:
      - "2375"
    networks:
      - dockerproxy
    read_only: true
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped

  # Nextcloud application (Apache variant)
  nextcloud:
    image: nextcloud:29-apache # pin to a stable major/minor; update intentionally
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      - POSTGRES_HOST=db
      - POSTGRES_DB=nextcloud
      - POSTGRES_USER=nextcloud
      - POSTGRES_PASSWORD_FILE=/run/secrets/nextcloud_db_password
      - REDIS_HOST=redis
      - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_DOMAIN}
      - TRUSTED_PROXIES=traefik
      - OVERWRITEPROTOCOL=https
      - PHP_MEMORY_LIMIT=1024M
      - PHP_UPLOAD_LIMIT=2048M
    volumes:
      # granular persistence for clean upgrades
      - nextcloud_data:/var/www/html/data
      - nextcloud_config:/var/www/html/config
      - nextcloud_custom_apps:/var/www/html/custom_apps
      - nextcloud_themes:/var/www/html/themes
    labels:
      - traefik.enable=true
      - traefik.http.routers.nextcloud.rule=Host(`${NEXTCLOUD_DOMAIN}`)
      - traefik.http.routers.nextcloud.entrypoints=websecure
      - traefik.http.routers.nextcloud.tls.certresolver=letsencrypt
      - traefik.http.services.nextcloud.loadbalancer.server.port=80
      - traefik.http.routers.nextcloud.middlewares=secure-headers@docker,nextcloud-buffering
      # Allow large uploads and streaming
      - traefik.http.middlewares.nextcloud-buffering.buffering.maxRequestBodyBytes=0
      - traefik.http.middlewares.nextcloud-buffering.buffering.memRequestBodyBytes=8388608
      - traefik.http.middlewares.nextcloud-buffering.buffering.maxResponseBodyBytes=0
    networks:
      - proxy
      - nextcloud
    secrets:
      - nextcloud_db_password
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://localhost/status.php || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 10
    restart: unless-stopped

  # Nextcloud cron (runs background jobs every 5 minutes)
  nextcloud-cron:
    image: nextcloud:29-apache
    entrypoint: /cron.sh
    depends_on:
      - nextcloud
    volumes:
      - nextcloud_data:/var/www/html/data
      - nextcloud_config:/var/www/html/config
      - nextcloud_custom_apps:/var/www/html/custom_apps
      - nextcloud_themes:/var/www/html/themes
    networks:
      - nextcloud
    restart: unless-stopped

  # PostgreSQL database for Nextcloud
  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_DB=nextcloud
      - POSTGRES_USER=nextcloud
      - POSTGRES_PASSWORD_FILE=/run/secrets/nextcloud_db_password
    secrets:
      - nextcloud_db_password
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - nextcloud
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U nextcloud -d nextcloud || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  # Redis for file locking and caching
  redis:
    image: redis:7-alpine
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis_data:/data
    networks:
      - nextcloud
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"]
      interval: 10s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  # Example simple website 1 (static content)
  site1:
    image: nginx:1.27-alpine
    volumes:
      - ./sites/site1:/usr/share/nginx/html:ro
    labels:
      - traefik.enable=true
      - traefik.http.routers.site1.rule=Host(`${SITE1_DOMAIN}`)
      - traefik.http.routers.site1.entrypoints=websecure
      - traefik.http.routers.site1.tls.certresolver=letsencrypt
      - traefik.http.services.site1.loadbalancer.server.port=80
      - traefik.http.routers.site1.middlewares=secure-headers@docker,compress@docker
    networks:
      - proxy
    read_only: true
    tmpfs:
      - /var/cache/nginx
      - /var/run
    restart: unless-stopped

  # Example simple website 2 (static content)
  site2:
    image: nginx:1.27-alpine
    volumes:
      - ./sites/site2:/usr/share/nginx/html:ro
    labels:
      - traefik.enable=true
      - traefik.http.routers.site2.rule=Host(`${SITE2_DOMAIN}`)
      - traefik.http.routers.site2.entrypoints=websecure
      - traefik.http.routers.site2.tls.certresolver=letsencrypt
      - traefik.http.services.site2.loadbalancer.server.port=80
      - traefik.http.routers.site2.middlewares=secure-headers@docker,compress@docker
    networks:
      - proxy
    read_only: true
    tmpfs:
      - /var/cache/nginx
      - /var/run
    restart: unless-stopped

secrets:
  nextcloud_db_password:
    file: ./secrets/nextcloud_db_password.txt

volumes:
  traefik_letsencrypt:
  nextcloud_data:
  nextcloud_config:
  nextcloud_custom_apps:
  nextcloud_themes:
  db_data:
  redis_data:

networks:
  proxy:
    driver: bridge
  nextcloud:
    driver: bridge
  dockerproxy:
    driver: bridge

Claude Sonet 4 (human senior engineer)


version: '3.8'

services:
  # Database service
  db:
    image: mariadb:10.11
    container_name: nextcloud_db
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=nextcloud_root_password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud_password
      - MARIADB_AUTO_UPGRADE=1
      - MARIADB_DISABLE_UPGRADE_BACKUP=1
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - nextcloud_network
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      start_period: 1m
      start_interval: 10s
      interval: 1m
      timeout: 5s
      retries: 3

  # Redis cache service
  redis:
    image: redis:alpine3.22
    container_name: nextcloud_redis
    restart: unless-stopped
    networks:
      - nextcloud_network
    command: redis-server --requirepass redis_password
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 30s

  # Nextcloud application
  nextcloud:
    image: nextcloud:31.0.8-apache
    container_name: nextcloud_app
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud_password
      - REDIS_HOST=redis
      - REDIS_HOST_PASSWORD=redis_password
      - NEXTCLOUD_ADMIN_USER=admin
      - NEXTCLOUD_ADMIN_PASSWORD=admin_password
      - TRUSTED_PROXIES=nginx-proxy-manager
      - OVERWRITEPROTOCOL=https
      - OVERWRITECLIURL=https://your-domain.com
      - APACHE_DISABLE_REWRITE_IP=1
    volumes:
      - nextcloud_data:/var/www/html
      - nextcloud_custom_apps:/var/www/html/custom_apps
      - nextcloud_config:/var/www/html/config
      - nextcloud_themes:/var/www/html/themes
    networks:
      - nextcloud_network
      - proxy_network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/status.php"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

  # Nextcloud cron service
  nextcloud_cron:
    image: nextcloud:31.0.8-apache
    container_name: nextcloud_cron
    restart: unless-stopped
    depends_on:
      - nextcloud
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud_password
      - REDIS_HOST=redis
      - REDIS_HOST_PASSWORD=redis_password
    volumes:
      - nextcloud_data:/var/www/html
      - nextcloud_custom_apps:/var/www/html/custom_apps
      - nextcloud_config:/var/www/html/config
      - nextcloud_themes:/var/www/html/themes
    networks:
      - nextcloud_network
    entrypoint: /cron.sh
    user: www-data

  # Nginx Proxy Manager
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx_proxy_manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    environment:
      - DB_SQLITE_FILE=/data/database.sqlite
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    networks:
      - proxy_network
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:81"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

volumes:
  db_data:
    driver: local
  nextcloud_data:
    driver: local
  nextcloud_custom_apps:
    driver: local
  nextcloud_config:
    driver: local
  nextcloud_themes:
    driver: local
  npm_data:
    driver: local
  npm_letsencrypt:
    driver: local

networks:
  nextcloud_network:
    driver: bridge
    internal: true
  proxy_network:
    driver: bridge

GPT 4.1 output (human senior engineer)


version: "3.9"

services:
  nextcloud:
    image: nextcloud:31.0.8-apache
    restart: unless-stopped
    depends_on:
      - db
      - redis
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud_db_password
      - REDIS_HOST=redis
      - REDIS_HOST_PASSWORD=redis_password
      - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.example.com
    volumes:
      - nextcloud_data:/var/www/html
    networks:
      - nextcloud_network

  nextcloud-cron:
    image: nextcloud:31.0.8-apache
    restart: unless-stopped
    entrypoint: "/cron.sh"
    depends_on:
      - db
      - redis
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud_db_password
      - REDIS_HOST=redis
      - REDIS_HOST_PASSWORD=redis_password
    volumes:
      - nextcloud_data:/var/www/html
    networks:
      - nextcloud_network

  db:
    image: mariadb:10.11
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=strong_root_password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud_db_password
    volumes:
      - nextcloud_db:/var/lib/mysql
    networks:
      - nextcloud_network

  redis:
    image: redis:alpine3.22
    restart: unless-stopped
    command: ["redis-server", "--requirepass", "redis_password"]
    volumes:
      - nextcloud_redis:/data
    networks:
      - nextcloud_network

  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    networks:
      - nextcloud_network

volumes:
  nextcloud_data:
  nextcloud_db:
  nextcloud_redis:
  npm_data:
  npm_letsencrypt:

networks:
  nextcloud_network:
    driver: bridge

GPT 5 output (human senior engineer)


name: nextcloud-stack
services:
  db:
    image: mariadb:10.11
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    restart: unless-stopped
    environment:
      - MARIADB_DATABASE=nextcloud
      - MARIADB_USER=nextcloud
      - MARIADB_ROOT_PASSWORD_FILE=/run/secrets/db_root_password
      - MARIADB_PASSWORD_FILE=/run/secrets/db_password
    volumes:
      - db_data:/var/lib/mysql
    secrets:
      - db_root_password
      - db_password
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u root -p$(cat /run/secrets/db_root_password) || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  redis:
    image: redis:alpine3.22
    restart: unless-stopped
    command: ["redis-server", "--save", "", "--appendonly", "no"]
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    networks:
      - backend
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  app:
    image: nextcloud:31.0.8-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD_FILE=/run/secrets/db_password
      - REDIS_HOST=redis
      - OVERWRITEPROTOCOL=https
      - APACHE_DISABLE_REWRITE_IP=1
    volumes:
      - nextcloud:/var/www/html
    secrets:
      - db_password
    networks:
      - backend
      - frontend
    healthcheck:
      test: ["CMD-SHELL", "php -r \"exit((int)!@fopen('http://127.0.0.1/status.php', 'r'));\""]
      interval: 30s
      timeout: 10s
      retries: 10
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  cron:
    image: nextcloud:31.0.8-apache
    restart: unless-stopped
    depends_on:
      app:
        condition: service_started
    entrypoint: /cron.sh
    volumes:
      - nextcloud:/var/www/html
    networks:
      - backend
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  npm:
    image: jc21/nginx-proxy-manager:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    networks:
      - frontend
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  nextcloud:
  db_data:
  npm_data:
  npm_letsencrypt:

secrets:
  db_root_password:
    file: ./secrets/db_root_password.txt
  db_password:
    file: ./secrets/db_password.txt

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true














Comments

Popular posts from this blog

Setting up KDiff3 to work with TortoiseGIT

How I used Udev with systemd to configure an AIO water cooler in Linux

Arch Install Desktop vs Server Differences