ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Linux]Nginx Proxy Manager(NPM)에서 DB 오류 날때 해결 방법
    HomeLAB/Linux 2025. 1. 24. 16:24

    오라클 클라우드를 사용하면서 Nginx Proxy Manager(NPM)를 잘 사용하고 있습니다. 홈랩 쪽은 OPNsense에서 HAProxy를 리버스 프록시로 사용하지만, 오라클 클라우드는 ARM에 CLI로 conf 파일을 설정해야 하는 게 좀 귀찮아서 NPM을 Docker로 설치해서 사용하고 있습니다. 올리고 싶은 서비스의 docker-compose.yaml 파일에 대충 네트워크만 맞춰주고 컨테이너 올려주고 웹에서 "딸깍" 몇 번만 하면 그리 어렵지 않게 설정할 수 있어 많은 사람들이 사용하는 리버스 프록시 프로그램입니다.

     

    Let's Encrypt 인증서가 6일 이내에 만료된다는 이메일 - 현재는 해결했다.

     

    NPM에서는 자동으로 인증서를 갱신하기에 딱히 신경 쓸 필요는 없습니다. 그런데 얼마 전에 Let's Encrypt 측에서 인증서가 곧 만료된다는 메일이 왔는데, 왜 이런 메일이 왔는가 싶어서 확인해 봤습니다. 확인해 보니 오랜 기간 도커 이미지의 업데이트를 못해서 컨테이너 내부에 Certbot 패키지 버전을 사용할 수 없게 되면서 인증서를 재발급받을 수 없게 되는 것이 원인인 것으로 결론을 내렸습니다. 그런데 작년에 최신 버전으로 업데이트를 시도했다가 DB 오류로 실패하고 원복 했는데, 이제 인증서를 갱신하지 못하면 잘 돌아가던 서비스를 전부 사용할 수 없게 되니 어쩔 수 없이 업데이트를 미룰 수 없게 되었습니다.

     

    그 시도 중에 하나를 해결하면 문제가 하나 생겨서 2가지 문제를 해결했다. 검색해 보니까 선발대가 Github에 잘 정리해 놔서 생각보다 빠르게 해결할 수 있었습니다.


    0. 시스템 사양

    오라클 클라우드 Ampere A1

    CPU: ARM 4 Core vCPU

    RAM: 24GB

    OS: Ubuntu 22.04 LTS

     

    1. 기존의 NPM의 docker-compose.yaml 구성

    NPM은 역사와 전통의 X86 시스템뿐만이 아니라 ARM 시스템도 지원합니다. yaml 파일이 좀 길어서 접어놨는데 잘못된 파일이라서 볼 필요는 없습니다. 나중에 수정된 yaml 파일이 나오니 이 부분은 구경만 하시면 되겠습니다.

     

    NPM 서비스는 메인 NPM과 MariaDB로 구동됩니다.

    더보기
    version: "3.1"
    services:
      npm:
        image: 'jc21/nginx-proxy-manager:${NPM_VERSION}'
        container_name: NPM_main
        restart: unless-stopped
        ports:
          - '80:80'            # http
          - '443:443'          # https
          - '81:81'            # management page
        environment:
          DB_MYSQL_HOST: "npm_db"
          DB_MYSQL_PORT: 3306
          DB_MYSQL_USER: ${NPM_USER}
          DB_MYSQL_PASSWORD: ${NPM_PASSWD}
          DB_MYSQL_NAME: ${NPM_DBNAME}
        volumes:
          - ./data:/data
          - ./letsencrypt:/etc/letsencrypt
        networks:
          - artemis_net
          - npm_net
        depends_on:
          - npm_db
    
      npm_db:
        image: 'jc21/mariadb-aria:${DB_VERSION}'
        container_name: NPM_DB
        tty: true
        expose:
          - 3306
        restart: unless-stopped
        environment:
          MYSQL_ROOT_PASSWORD: ${NPM_ROOT_PASSWD}
          MYSQL_DATABASE: ${NPM_DBNAME}
          MYSQL_USER: ${NPM_USER}
          MYSQL_PASSWORD: ${NPM_PASSWD}
          MARIADB_AUTO_UPGRADE: 1
        volumes:
          - ./data/mysql:/var/lib/mysql
        networks:
          - npm_net
    
    networks:
      artemis_net:
        external: true
      npm_net:
        external: true

     

    .env 파일에 나머지 구성을 저장했습니다.

     

    2. 문제 상황 해결 방법

    1) npm 'Can\'t create table `NPM_DB`.`migrations`

    기존의 yaml 파일에서 NPM과 MariaDB의 버전을 최신 버전으로 업데이트하기 위해 버전 부분만 "latest"로 지정하고 docker copmose pull && docker compose up으로 도커 컨테이너를 실행했을 때 만난 문제입니다. 상세 내역은 아래의 이미지를 참고해 주세요.

     

     

    이런 로그가 NPM에서 나타나게 되는데, 이 오류는 NPM 웹은 열리나 제대로 된 인증 정보를 넣더라도 로그인이 불가능한 문제가 생깁니다. DB를 마이그레이션 할 수 없는 문제인 것으로 파악했습니다. 해결 방법을 찾아보니 이 부분은 DB가 버전 마이그레이션을 못하는 게 아니라 DB 파일에 대한 권한 문제인 것이라며 권한을 컨테이너 내부에서 수정하는 방법을 사용했습니다.

     

    하지만 그 방법을 사용한 결과 해결은 했으나 컨테이너를 새로 시작하는 순간 문제가 다시 발생했습니다. 그래서 해결 방법에 관해서 좀 더 살펴본 결과 아예 DB 디렉터리를 NPM 디렉터리에서 분리해야 한다고 했습니다. 즉, 제 docker-compose.yaml 파일에는 NPM 컨테이너에 할당되어 있는 디렉터리 경로 내부에 DB 컨테이너의 디렉터리가 포함되어 있었고 DB 컨테이너가 실행되면서 DB 파일의 권한을 수정한다고 해도 depends_on으로 NPM이 다시 그 DB 파일의 권한을 수정해 버렸던 것으로 보입니다.

     

    제가 예전에 어떤 글을 참고해서 docker-compose.yaml 파일을 작성했는지는 잘 모르겠지만, 혹시나 싶어 확인해 본 공식 문서에서는 확실히 분리가 되어있었습니다. 아마 그때 당시에는 잘 되었으니 그냥 사용한 것으로 보입니다.

     

    해결 방법은 그리 어렵지 않습니다. 

    https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1499#issuecomment-1494593464

    NPM 컨테이너에 할당되어 있던 디렉터리 내부에 DB 컨테이너에 할당된 디렉터리가 있는데 그 디렉터리를 외부로 이동시키고 docker-compose.yaml에서도 그 부분을 수정해 줬습니다.

     

    디렉터리 이동

    # 도커 컨테이너에서 생성된 디렉터리라서 root 권한으로 실행해야함.
    sudo mv data/mysql ./

     

    NPM 컨테이너 볼륨 할당

       volumes:
          - /etc/localtime:/etc/localtime:ro
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - ./data:/data
          - ./letsencrypt:/etc/letsencrypt

     

    MariaDB 컨테이너 볼륨

        volumes:
          - ./mysql:/var/lib/mysql

     

    2) npm Incorrect definition of table mysql.column_stats: expected column 'hist_type' at position 9 to have type enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB'), found type enum('SINGLE_PREC_HB','DOUBLE_PREC_HB').

    DB 파일의 권한 문제를 해결했지만 아직 문제는 남아있었습니다. 로그인은 잘 되나 로그인할 때 DB에 로그가 쌓이기 시작했습니다. 상세 내역은 아래 이미지를 참고해 주세요.

     

     

    이런 로그가 DB에서 나타나게 되는데, 이 오류는 작동 자체는 제대로 되는데 로그인할 때마다 로그가 계속 쌓이게 되는 부분도 있고 억지로 돌아가는 느낌이라 더 큰 문제가 생기기 전에 잡으면 좋을 것 같았습니다. 해결 방법을 찾아보니 DB 버전이 꽤나 구버전이라 그런지 DB를 수동으로 업그레이드시켜줘야 하는 것으로 보입니다.

     

    해결 방법은 어렵지 않습니다.

    https://github.com/NginxProxyManager/nginx-proxy-manager/issues/3428#issuecomment-1885421270

    실행되어 있는 DB 컨테이너에 명령어를 날려서 DB를 수동으로 업그레이드시키면 됩니다.

     

    DB는 중요하니까 꼭 백업을 해놔야 합니다.

    # DB는 중요하니까 꼭 백업을 해놓고 시도하세요.
    # 명령어
    docker exec -it [DB 컨테이너의 이름] mysql_upgrade -u root -p [DB 이름]
    
    # 제 시스템의 경우
    docker exec -it NPM_DB mysql_upgrade -u root -p npm_db

     

    3. 결론

    제가 겪었던 문제의 경우에는 대부분 DB에 관련된 문제였습니다. 이 부분을 좀 더 잘 살피고 제대로 했다면 좋았을 텐데 해결 방법을 찾기가 그리 어렵지 않았고 해결이 100% 안 되는 경우도 가끔 있는데 이 문제는 완전하게 해결할 수 있어서 다행이었습니다.

     

    최종 수정된 docker-compose.yaml 파일

    더보기
    version: "3.1"
    services:
      npm:
        image: 'jc21/nginx-proxy-manager:latest'
        container_name: NPM_main
        restart: unless-stopped
        ports:
          - '80:80'            # http
          - '443:443'          # https
          - '81:81'            # management page
        environment:
          DB_MYSQL_HOST: "npm_db"
          DB_MYSQL_PORT: 3306
          DB_MYSQL_USER: ${NPM_USER}
          DB_MYSQL_PASSWORD: ${NPM_PASSWD}
          DB_MYSQL_NAME: ${NPM_DBNAME}
        volumes:
          - ./data:/data
          - ./letsencrypt:/etc/letsencrypt
          - /etc/localtime:/etc/localtime:ro
          - /var/run/docker.sock:/var/run/docker.sock:ro
        networks:
          - artemis_net
          - npm_net
        depends_on:
          - npm_db
    
      npm_db:
        image: 'jc21/mariadb-aria:latest'
        container_name: NPM_DB
        tty: true
        expose:
          - 3306
        restart: unless-stopped
        environment:
          MYSQL_ROOT_PASSWORD: ${NPM_ROOT_PASSWD}
          MYSQL_DATABASE: ${NPM_DBNAME}
          MYSQL_USER: ${NPM_USER}
          MYSQL_PASSWORD: ${NPM_PASSWD}
          MARIADB_AUTO_UPGRADE: 1
        volumes:
          - ./mysql:/var/lib/mysql
        networks:
          - npm_net
    
    networks:
      artemis_net:
        external: true
      npm_net:
        external: true

     

    .env 파일은 별도 작성되었습니다.

     


    레퍼런스

    https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1499

    https://github.com/NginxProxyManager/nginx-proxy-manager/issues/3428

Designed by Tistory.