우분투(Ubuntu) + LEMP 스택 + 워드프레스 서버 구축하기(Nginx, MariaDB, PHP)


기나긴 CentOS 삽질 끝에 우분투 서버로 정착 성공기...

약 2~3년 전에 아마존 라이트세일과 비트나미(bitnami)를 사용하여 워드프레스 블로그를 구축하여 운영하고 있었습니다. 그런데 몇 달 전부터 php를 업데이트하라는 알림이 워드프레스 대시보드에서 뜨기 시작했습니다. 워드프레스 일부 플러그인이 제대로 작동하지 않는 것 같기도 했었고(실제로 그렇지 않았지만…) 검색해보니 비트나미로 만든 서버의 php 버전을 올릴 수 있는 방법은 없으니 새로 서버를 만들어 이전해야 한다길래 이참에 아예 서버를 새로 구축해보았습니다.

본래 CentOS를 사용한 서버를 구축하려했으나 온갖 삽질을 거듭해도 nginx와 php가 연동되지 않는 문제를 해결하지 못하는 바람에 결국 포기했습니다. 에러 로그에 [error] 1916#1916: *3 open() "/usr/share/nginx/html/info.php" failed (2: No such file or directory) 라고 찍히기는 했지만 아무리 구글링을 해봐도 해결책을 찾이 못하여 결국 시간만 낭비해버렸습니다… 아까운 내 주말

이 글은 아마존 라이트세일 우분투(Ubuntu) 20.04 LTS 플랫폼에 LEMP 스택과 워드프레스를 설치하는 방법과 Let’s Encrypt를 사용하여 사이트에 SSL/TLS 인증서를 적용하는 방법을 설명합니다. 여기서 설치할 LEMP 구성요소는 다음과 같습니다.

  • Nginx v1.18 (웹서버)
  • MariaDB v10.5 (데이터베이스)
  • PHP v7.4

여담으로 CentOS로 삽질하다가 우분투로 갈아타보니… 리포지토리를 따로 업데이트해주지 않아도 CentOS에 비해 최신 소프트웨어 설치가 대체로 가능한 게 괜찮은 것 같았습니다.

우분투 업데이트

아래 명령어로 우분투 업데이트를 진행해줍니다.

$ sudo apt-get update -y
$ sudo apt-get upgrade -y
$ sudo apt-get dist-upgrade -y

업데이트가 완료되면 서버를 한 번 재기동해줍니다.

$ sudo reboot

Nginx 설치

다음 명령어로 Nginx를 설치합니다.

$ sudo apt install nginx

설치가 완료되면 잘 실행되는지 확인해봅니다.

$ nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

참고로, 우분투 apt로 설치한 nginx의 설정파일과 html 폴더 경로는 다음과 같습니다.

  • 설정파일: /etc/nginx/sites-available/default
  • html 폴더: /var/www/html

php 및 php-fpm 설치

아래 명령어를 사용하여 php 7.4와 관련 모듈들을 설치해줍니다.

$ sudo apt install -y nginx php7.4-fpm php7.4-cli php7.4-bcmath php7.4-dev php7.4-common php7.4-json php7.4-opcache php7.4-readline php7.4-mbstring php7.4-curl php7.4-gd php7.4-mysql php7.4-zip php7.4-intl php7.4-xml php-pear

php-fpm은 nginx와 php를 연동하기 위하여 사용합니다. php-fpm의 설정파일 경로는 /etc/php/7.4/fpm/pool.d/www.conf 입니다. 콜론(;) 기호로 구성된 주석 부분을 제외하곤 대부분 다음과 같이 설정되어 있을 것입니다.

user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

만약 www.conf 파일을 수정했다면 아래 명령어로 php-fpm 서비스를 재시작합니다.

$ systemctl restart php7.4-fpm

nginx 설정파일 경로는 /etc/nginx/sites-available/default 입니다. 이 파일에 nginx과 pnp-fpm을 연동하기 위한 설정을 추가합니다.

server {
        # 생략...

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }

        # 생략...
}

nginx 설정파일을 수정했다면 nginx 서비스를 재시작합니다.

$ systemctl restart nginx

이제 nginx와 php가 잘 연동되는지 확인해야 합니다. /var/www/html 경로에 info.php 파일을 생성합니다.

<?php phpinfo(); ?>

http://IP주소/info.php 로 접속하여 php 정보가 제대로 뜨는지 확인합니다. 제대로 뜬다면 info.php 파일을 제거해줍니다.

$ sudo rm /var/www/html/info.php

MariaDB 설치

MariaDB 10.5 설치법은 MariaDB – Setting up MariaDB Repositories – MariaDB에 자세히 소개되어 있습니다.

아래 명령어로 MariaDB 10.5를 설치합니다.

$ sudo apt-get install software-properties-common
$ sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] https://ftp.harukasan.org/mariadb/repo/10.5/ubuntu focal main'
$ sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] https://ftp.harukasan.org/mariadb/repo/10.5/ubuntu focal main'
$ sudo apt update
$ sudo apt install mariadb-server

MariaDB root 비밀번호를 설정합니다.

$ sudo /usr/bin/mysqladmin -u root password 'P@ssw0rd'

MariaDB 서비스가 정상적으로 작동하는지 확인합니다.

$ systemctl status mariadb

만약 서비스가 작동 중이지 않다면 다음 명령어로 MariaDB 서비스를 시작합니다.

$ systemctl start mariadb

추후 워드프레스 사용 시 문자꺠짐 현상을 해결하기 위해 MariaDB 기본 언어셋을 utf-8로 수정하겠습니다. /etc/mysql/conf.d/mariadb.conf 파일을 열어 아래와 같이 내용을 수정해줍니다. 만약 파일이 없다면 새로 만들어줍니다.

# MariaDB-specific config file.
# Read by /etc/mysql/my.cnf

[client]
# Default is Latin1, if you need UTF-8 set this (also in server section)
default-character-set = utf8mb4

[mysqld]
#
# * Character sets
#
# Default is Latin1, if you need UTF-8 set all this (also in client section)
#
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci

서버 접속을 끊은 후 다시 접속하면 System restart required 가 나타나납니다. 서버를 한번 재부팅해줍니다.

$ sudo reboot

워드프레스 데이터베이스 생성

MariaDB에 접속합니다.

$ mysql -u root -p
Enter password: P@ssw0rd

데이터베이스를 생성합니다. 데이터베이스_이름 부분에 원하는 데이터베이스 이름을 적어줍니다. wordpress로 적어도 괜찮고, wp_wordpress 등과 같이 적어도 괜찮습니다.

MariaDB [(none)]> CREATE DATABASE 데이터베이스_이름

데이터베이스가 잘 생성됐는지 확인합니다.

MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| 데이터베이스_이름          |  # 생성한 데이터베이스
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)

MariaDB를 사용할 계정을 생성합니다. 사용자_아이디 부분에 원하는 사용자 아이디를 적어줍니다.

MariaDB [(none)]> CREATE USER 사용자_아이디@localhost;
Query OK, 0 rows affected (0.003 sec)

방금 만든 사용자의 비밀번호를 설정합니다.

MariaDB [(none)]> SET PASSWORD FOR 사용자_아이디@localhost=PASSWORD("P@ssw0rd");
Query OK, 0 rows affected (0.001 sec)

데이터베이스 권한을 방금 만든 사용자에게 부여합니다.

MariaDB [(none)]> GRANT ALL PRIVILEGES ON 데이터베이스_이름.* TO 사용자_아이디@localhost IDENTIFIED BY 'P@ssw0rd';
Query OK, 0 rows affected (0.003 sec)

변경한 권한을 반영합니다.

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.000 sec)

추가된 사용자는 다음과 같이 확인합니다.

MariaDB [(none)]> use mysql;
Database changed

MariaDB [mysql]> select user, host from user;
+-------------+-----------+
| User        | Host      |
+-------------+-----------+
| USER_ID     | localhost |
| mariadb.sys | localhost |
| mysql       | localhost |
| root        | localhost |
+-------------+-----------+

(참고!) DB 사용자 삭제는 다음과 같이 합니다.

DROP USER 사용자_아이디@localhost;

MariaDB 접속을 종료합니다.

MariaDB [mysql]> exit
Bye

워드프레스 설치

워드프레스 설치 및 설정 부분은 Nginx에 설치형 워드프레스 최신판 다운로드 및 설치 방법 (NGINX + WordPress) | 스위프트코딩 글의 도움을 많이 받았습니다.

홈 디렉토리로 이동한 후

$ cd ~

워드프레스 최신 버전을 다운로드합니다.

$ wget https://wordpress.org/latest.zip

압축을 풀고

$ unzip latest.zip

압축을 풀어 나온 파일들을 nginx 루트 디렉토리로 이동시킵니다.

$ sudo cp -a ~/wordpress/. /var/www/html  # 복사 후
$ rm -rf ~/latest.zip ~/wordpress  # 삭제

워드프레스에서 사용하는 폴더 세 가지를 생성해줍니다.

$ mkdir /var/www/html/wp-content/upgrade
$ mkdir /var/www/html/wp-content/uploads
$ mkdir /var/www/html/wp-content/temp

워드프레스 권한 관련 오류를 방지하기 위하여 폴더 소유자 및 사용자그룹을 각각 www-data와 ubuntu로 변경합니다.

$ sudo chown -R www-data:ubuntu /var/www/html

생성된 새로운 디렉토리가 상위 디렉토리의 그룹 설정을 따라가도록 합니다.

sudo find /var/www/html -type d -exec chmod g+s {} \;

nginx 루트 디렉토리에 있는 파일들을 소유자와 그룹이 읽고 쓰고 실행할 수 있도록 권한을 부여합니다.

sudo chmod -R 775 /var/www/html

워드프레스 설정 (wp-config.php)

워드프레스 설정파일은 wp-config.php 이지만 설치 직후엔 존재하지 않습니다. wp-config-sample.php 파일을 wp-config.php 이름으로 복사하여 사용합니다.

$ cp -p /var/www/html/wp-config-sample.php /var/www/html/wp-config.php

/var/www/html/wp-config.php 파일을 열어 워드프레스 정보를 입력해줍니다.

MariaDB 정보를 입력합니다.

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', '데이터베이스_이름' );

/** MySQL database username */
define( 'DB_USER', '사용자_아이디' );

/** MySQL database password */
define( 'DB_PASSWORD', 'P@ssw0rd' );

워드프레스 인증키 및 솔트 랜덤값을 입력합니다. 직접 입력해도 되고, https://api.wordpress.org/secret-key/1.1/salt/ 에서 랜덤 생성되는 값을 복사 및 붙여넣기 해도 됩니다.

define( 'AUTH_KEY',         'put your unique phrase here' );
define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
define( 'NONCE_KEY',        'put your unique phrase here' );
define( 'AUTH_SALT',        'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
define( 'NONCE_SALT',       'put your unique phrase here' );

조금 전 만들었던 임시 폴더를 설정합니다.

/* Set temporary folder for downloaded files */
define('WP_TEMP_DIR', dirname(__FILE__) . '/wp-content/temp');

워드프레스 설정 시 FTP 연결정보를 입력하는 항목을 우회하도록 합니다.

/* FTP connection information  demand bypass */
define('FS_METHOD', 'direct');

워드프레스 접속

Nginx 설정 파일인 /etc/nginx/sites-available/default 파일을 수정하여 index 접속 시 index.php 파일이 우선하도록 설정한 후

server {
    # 생략...

    index index.php index.html index.htm index.nginx-debian.html;

    # 생략...
}

nginx를 재시작합니다.

$ systemctl restart nginx

이제 서버 IP 주소로 접속하면 워드프레스 설치화면이 나타납니다. 이제 안내받는 대로 세팅하면 됩니다.

워드프레스 글 링크 시 404 Not Found 에러 처리

워드프레스 글 링크 클릭 시 not found 에러가 발생한다면 /etc/nginx/sites-available/default 파일의 location / 항목에 아래 설정을 추가합니다.

server {
        location / {
            # 생략...

            try_files $uri $uri/ /index.php?q=$uri&args;

            # 생략...
        }
}

HTTPS 적용을 위한 Certbot 설치

Let’s Encrypt를 사용하여 사이트에 SSL/TLS 인증서를 적용하기 위해 certbot을 설치합니다. 여기서는 웹서버로 nginx를 사용하므로 python3-certbot-nginx도 같이 설치합니다.

$ sudo apt install certbot python3-certbot-nginx

인증서를 발급받기 전에 소유하고 있는 도메인과 서버가 제대로 통신되고 있는지 꼭 확인해야 합니다. 그리고 워드프레서 관리자 화면에서 설정 메뉴로 들어가면 워드프레스 및 사이트 주소(URL)을 설정하는 항목이 있는데, 이 URL을 설정하기 전에 백업을 해두는 것을 권장합니다. 잘못 설정하면 워드프레스 접속이 제대로 되지 않기 때문입니다. 아마존 라이트세일을 사용한다면 잠시 스냅샷을 만들어 두는 게 좋겠지요.

Let’s Encrypt 인증서를 발급받는 명령어는 다음과 같습니다.

$ letsencrypt certonly —webroot —webroot-path=NGINX_루트폴더_경로 -d 해당도메인주소입력

지금까지 설정한 Nginx 루트폴더 경로는 /var/www/html 입니다. 도메인 주소가 asdf.net이라면 Let’s Encrypt 인증서를 발급받는 명령어는 다음과 같습니다.

$ letsencrypt certonly —webroot —webroot-path=/var/www/html -d asdf.net

참고로, 도메인은 여러 개 명시할 수 있습니다.

$ letsencrypt certonly —webroot —webroot-path=/var/www/html -d asdf.net -d www.asdf.net

다시 letsencrypt 명령어를 실행합니다. Authenticator nginx, Installer nginx 알림이 나타난다면 도메인 입력해주고… HTTP 트래픽을 No redirect할 것인지 Redirect할 것인지를 묻는다면… 저는 HTTP를 더 이상 사용하지 않을 것이므로 Redirect로 선택했습니다.

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
Congratulations! You have successfully enabled https://asdf.net

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=asdf.net

Let’s Encrypt 인증서 발급이 완료되면 인증서를 nginx에 적용해야 합니다. /etc/nginx/sites-available/default 파일을 열어 다음과 같이 추가 및 수정한 후

server {
        # HTTP 접속 시 HTTPS로 강제 리다이렉트
        listen 80;
        return 301 https://$host$request_uri;
}

server {
        # HTTP는 더 이상 사용하지 않으므로 주석 처리
        # listen 80 default_server;  
        # listen [::]:80 default_server;

        # 생략...

        # SSL configuration
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;
        ssl_certificate /etc/letsencrypt/live/도메인주소/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/도메인주소/privkey.pem;

        # 생략...
}

nginx 서비스를 재기동합니다.

$ systemctl restart nginx

발급된 인증서 정보는 다음 명령어로 확인할 수 있으며

$ sudo letsencrypt certificates
$ sudo certbot certificates  # 둘 중 택일

인증서를 갱신하는 명령어는 다음과 같습니다.

$ sudo letsencrypt renew
$ sudo certbot renew  # 둘 중 택일

URL 오류 수정

기존 워드프레스 서버에서 새로운 서버로 데이터를 이전하면 URL 링크가 엉뚱하게 설정되어 있거나 이미지가 보이지 않는 문제가 생길 수 있습니다. 저 같은 경우 새로운 서버로 워드프레스를 이전했더니 URL과 이미지 주소에 예전 워드프레스 서버의 IP가 포함돼버리는 문제가 생겼습니다.

이 문제를 해결하려면 DB에 저장된 예전 URL을 새로운 URL로 일괄 변경해줘야 합니다. MariaDB에 접속한 후

$ mysql -u root -p  # MariaDB 루트계정 로그인
Enter password:

MariaDB [(none)]> use 데이터베이스_이름;  # 워드프레스 정보가 저장된 데이터베이스 사용
Database changed

MariaDB [데이터베이스_이름]> _

아래 쿼리문을 실행해주면 됩니다.

UPDATE wp_options SET option_value = replace(option_value, '예전_URL', '새로운_URL') WHERE option_name = 'home' OR option_name = 'siteurl';
UPDATE wp_posts SET guid = replace(guid, '예전_URL','새로운_URL');
UPDATE wp_posts SET post_content = replace(post_content, '예전_URL', '새로운_URL');
UPDATE wp_postmeta SET meta_value = replace(meta_value,'예전_URL','새로운_URL');

-- (참고) 아래는 WP Githuber MD 플러그인을 사용하여 마크다운 형식으로 작성한 글들 보정하는 쿼리
update wp_posts set post_content_filtered = replace(post_content_filtered, '예전_URL', '새로운_URL');

COMMIT;

서비스 자동 실행

서버 재부팅 시 Nginx, MariaDB, php7.4-fpm 서비스가 자동 실행되도록 아래 명령어를 실행합니다.

$ systemctl enable nginx
$ systemctl enable mariadb
$ systemctl enable php7.4-fpm