name: linkwarden

services:
  linkwarden:
    image: ghcr.io/linkwarden/linkwarden:v2.16.2
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      meilisearch:
        condition: service_healthy
    ports:
      - "127.0.0.1:${LINKWARDEN_PORT:-3000}:3000"
    environment:
      DATABASE_URL: postgresql://${POSTGRES_USER:-linkwarden}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-linkwarden}
      NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
      NEXTAUTH_URL: ${LINKWARDEN_URL:-https://links.example.com}/api/v1/auth
      BASE_URL: ${LINKWARDEN_URL:-https://links.example.com}
      NEXT_PUBLIC_DISABLE_REGISTRATION: ${NEXT_PUBLIC_DISABLE_REGISTRATION:-false}
      NEXT_PUBLIC_USER_CONTENT_DOMAIN: ${LINKWARDEN_USER_CONTENT_URL:-https://saved.example.net}
      MEILI_HOST: http://meilisearch:7700
      MEILI_MASTER_KEY: ${MEILI_MASTER_KEY}
      ALLOW_PRIVATE_NETWORK_ACCESS: "false"
      ALLOW_INSECURE_TLS: "false"
      TZ: ${LINKWARDEN_TIME_ZONE:-Etc/UTC}
    volumes:
      - linkwarden-data:/data/data
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
      interval: 30s
      timeout: 10s
      retries: 10
      start_period: 120s
    security_opt:
      - no-new-privileges:true
    stop_grace_period: 60s

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-linkwarden}
      POSTGRES_USER: ${POSTGRES_USER:-linkwarden}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_INITDB_ARGS: "--data-checksums"
      TZ: ${LINKWARDEN_TIME_ZONE:-Etc/UTC}
    volumes:
      - linkwarden-postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-linkwarden} -d ${POSTGRES_DB:-linkwarden}"]
      interval: 10s
      timeout: 5s
      retries: 10
    security_opt:
      - no-new-privileges:true
    stop_grace_period: 60s

  meilisearch:
    image: getmeili/meilisearch:v1.13.3
    restart: unless-stopped
    environment:
      MEILI_ENV: production
      MEILI_NO_ANALYTICS: "true"
      MEILI_MASTER_KEY: ${MEILI_MASTER_KEY}
    volumes:
      - linkwarden-meilisearch:/meili_data
    healthcheck:
      test: ["CMD-SHELL", "curl --fail --silent http://127.0.0.1:7700/health | grep -q '\"status\":\"available\"'"]
      interval: 10s
      timeout: 5s
      retries: 15
    security_opt:
      - no-new-privileges:true
    stop_grace_period: 60s

volumes:
  linkwarden-data:
    name: ${LINKWARDEN_DATA_VOLUME:-linkwarden-data}
  linkwarden-postgres:
    name: ${LINKWARDEN_DB_VOLUME:-linkwarden-postgres}
  linkwarden-meilisearch:
    name: ${LINKWARDEN_MEILI_VOLUME:-linkwarden-meilisearch}
