본문으로 바로가기

웹호스팅의 DB 자동 백업하기

category 개발/참고자료 2017. 2. 19. 21:14
반응형

DB (MariaDB) 를 이용한 웹프로그램을 하나 개발해서 운영하고 있다. 중요한 프로그램이라 개인서버에 둘 수 없어서 웹호스팅 서비스를 이용하고 있다. 절대 날리면 안되는 데이터이다보니 주기적으로 백업을 해주어야 하는데 웹호스팅 서비스이다보니 제약이 많다. ssh 접속은 가능하지만 crontab을 사용할 수도 없고, DB 자체도 로컬에서만 접속이 가능하게 설정되어 있다. 당연히 Replication 기능도 사용할 수 없다.


방법을 찾다보니 어떤 분은 PHP를 이용해 수동으로 DB를 백업받고 있었다. (참고 : http://itrooms.tistory.com/308)

정말 편리하고 좋은 해결책이지만 어쨌든 내가 원하는 구성은 아니다. 일단 백업이 자동으로 수행되는 것이 아니고, 누구나 주소만 알면 DB를 빼갈 수 있다는 문제가 있다.


내가 원하는 대로 구성하기 위해서 다음과 같이 구성을 해보기로 했다.

1. 웹호스팅서버에서 DB백업 스크립트 작성 (DB백업기능, 백업완료후 백업파일주소를 json으로 출력하는 기능)

2. 내 개인서버에서 웹호스팅의 백업 스크립트를 실행하고 생성된 백업파일의 url을 받아옴 (cURL 이용)

3. 백업파일을 받아서 내 서버에 저장하고 필요한 경우 개인서버의 DB에 복원 (역시 cURL 이용)


1. 웹호스팅 서버에서의 설정

웹호스팅 서버에서 원하는 위치에 다음과 같은 php파일을 만든다. 나는 웹 루트 디렉토리에 backup이라는 디렉토리를 새로 만들고, 그 아래에 db_backup.php 파일을 생성했다. 아무나 DB를 가져갈 수 있는 문제를 막기 위해 간단하게 POST 변수를 사용하기로 했다. 페이지에 접근했을 때 POST 방식으로 key 파라미터가 넘어오지 않거나 내가 정한 key값과 다르면 백업이 수행되지 않고 종료되도록 했고, 정상적인 접근이라면 기존 백업파일 삭제 → 새로운 백업 생성 → 새로 생성된 백업파일 주소 json형식으로 출력 과정을 실행하게 된다.

아래 스크립트 코드에는 php의 system 함수를 사용해서 .sql.gz 확장자를 갖는 모든 파일을 삭제하는 부분이 포함되어 있습니다.
실제 운영하는 서버라면 주의해서 사용하시기 바랍니다.
<?php
    /* 정상적인 접근인지 확인하고 인증 안되면 빈 데이터 출력 */
    if (!isset($_POST['key'])){
        header('Content-Type: application/json');
        echo json_encode(array("url" => ""));
        die();
    }else{
        if ($_POST['key'] != "/* 내가 정한 인증 키 */"){
            header('Content-Type: application/json');
            echo json_encode(array("url" => ""));
            die();
        }
    }

    /* DB 접속 계정 정보 */
    $DB_HOST = 'localhost'; // DB 서버 주소. 웹호스팅을 이용할 때는 보통 localhost만 사용가능
    $DB_USER = '(DB 아이디)';
    $DB_PASS = '(DB 비밀번호)';
    $DB_NAME = '(데이터베이스 이름)';

    /* 백업 데이터 위치 및 파일명 설정 */
    $BACKUP_PATH = '/free/home/사용자아이디/html/backup'; // 백업파일을 저장할 절대경로
    $BACKUP_NAME = date("Ymd_His").'.sql.gz'; // 백업파일명 (20170219_200101.sql.gz 형태)
    $BACKUP_FILE = $BACKUP_PATH.$BACKUP_NAME;

    /* 기존 백업 파일 삭제 */
    system("rm ".$BACKUP_PATH."*.sql.gz"); 

    /* MySQL Dump 시작 */
    system("mysqldump -h$DB_HOST -u$DB_USER -p$DB_PASS $DB_NAME /* 백업할테이블1 백업할테이블2... */ --opt | gzip > $BACKUP_FILE");
    // 데이터베이스의 모든 테이블을 백업하고 싶을 때는 백업할 테이블 이름을 비워두면 된다.

    /* 결과 리턴 */
    header('Content-Type: application/json');
    echo json_encode(array("url" => "http://example.com/backup/".$BACKUP_NAME));
?>

이제 이 스크립트를 브라우저에서 접근하게 되면 POST 변수가 없으므로 빈 데이터가 반환되고,  {"url":""} curl을 사용하든 form을 사용하든 POST 방식으로 내가 정한 key 를 제대로 전송하면 백업파일의 주소가 반환된다. {"url":"http://example.com/db_backup.sql.gz"} 참고로 소스코드에서, 굳이 DB백업을 gzip으로 압축하는 이유는 웹호스팅에서 sql 파일의 전송을 막고 있기 때문이다. 사용하고 있는 웹호스팅서비스에서는 테스트해보니 sql 파일을 생성하고 다운받으려고 하면 에러 페이지로 자동으로 리다이렉트됐다.

2. 서버에서의 설정

서버에서 할 일은 1번에서 만든 php에 올바른 key 값을 POST 형식으로 전송해서 백업된 파일의 주소를 받고, 이 주소를 이용해 백업파일 데이터를 받아 서버의 원하는 위치에 저장하는 것이다. 이 과정을 수행할 PHP 스크립트를 만들고, crontab 을 이용해서 주기적으로 실행해 백업을 자동으로 수행하게 한다.


파일명은 backup_from_remote.php 로 했다. 주의할 점은, 스크립트로 실행할 것이므로 첫줄에 #!/usr/bin/php 를 입력해서 php를 통해 이 스크립트를 실행해야 한다고 알려주어야 하고 파일 작성이 끝난 뒤에는 스크립트 파일에 실행 권한을 주어야 한다는 것이다. 스크립트 파일이 있는 위치에서 아래 명령어를 입력하면 된다.

chmod +x backup_from_remote.php


물론 이렇게 하지 않고 그냥 크론탭에 등록할 때 /usr/bin/php (스크립트 경로/스크립트파일.php)  이런식으로 등록해도 된다. 취향대로.

코드

#!/usr/bin/php
<?php
    // 인증을 위해 POST 형식으로 보낼 파라미터를 설정한다.
    $post_data = array("key" => "(아까 정한 key값)");
    
    // curl을 이용해 데이터를 받아올 예정이다.
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://(백업스크립트가 있는 도메인)/db_backup.php");
    // 웹호스팅 서비스에서 스크립트를 이용한 접근을 막고 있으므로 유저에이전트를 설정해서 사람이 접근하는 것처럼 보이게 한다.
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); // POST 전송
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $json = curl_exec($ch);
    $data = json_decode($json, true); // 실행 및 변수에 결과 저장

    // 결과데이터에 백업 url이 있을 경우에만 실행
    if ($data['url'] != ""){
        // 슬래시(/)를 기준으로 나누어서 파일명만 추출한다.
        $arr = explode("/",$data['url']);
        $filename = $arr[count($arr)-1];

        // 다시 curl을 이용해서 백업 url에 있는 백업 파일을 가져온다.
        $ch = curl_init();
        curl_setopt($ch, CUdRLOPT_URL, $data['url']);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $dump = curl_exec($ch);

        // 가져온 백업 데이터를 원하는 위치에 저장하고 압축을 푼다
        file_put_contents("/free/home/사용자아이디/html/backup/".$filename,$dump);
        system("gzip -d /free/home/사용자아이디/html/backup/*.gz");
        // (선택) 백업된 데이터를 서버의 데이터베이스에 복원한다.
        system("mysql -u(아이디) -p(비밀번호) (복원대상 데이터베이스 이름) < (백업이 존재하는 절대경로) + "/".str_replace(".gz","",$filename));
    }else{
        echo "DB 백업시 오류가 발생했습니다.";
    }
?>

크론탭 설정

크론탭 설정 (데비안에서는 쉘에서 crontab -e 를 입력하면 된다) 에서 아래 내용을 추가하고 저장한다.

0   23  *   *   0   /(스크립트절대경로)/backup_from_remote.php



모든 과정이 완료되었다. 이제 매주 일요일 오후 11시에 웹호스팅에 있는 DB는 자동으로 백업되어 내 서버로 저장되고, 내 서버 DB에도 자동으로 복원되어 같은 데이터베이스를 사용할 수 있게 되었다.

반응형

'개발 > 참고자료' 카테고리의 다른 글

Webhook 테스트 사이트  (0) 2022.04.06
개역개정판 성경에 사용된 글자 목록  (0) 2017.02.13