DEV/Docker-Debian

2. Docker httpd 환경 설정하기 (PHP 연동, Virtualhost 및 무료인증서 SSL 적용)

서버엔지니어 2023. 3. 1.
728x90

1) httpd 기본 환경 설정 방법

httpd 컨테이너 내의 설정 파일 (conf) 를 호스트 서버로 복사하고 호스트 서버의 conf 디렉토리를 사용하도록 해야 합니다.
컨테이너가 구동중인 상태에서 아래와 같이 파일을 복사 합니다.

httpd 컨테이너의 /usr/local/apache2/conf 디렉토리를 /home/93it/httpd/ 디렉토리 아래로 복사합니다.
docker cp httpd:/usr/local/apache2/conf/ /home/93it/httpd/

호스트 서버에서 httpd 에 대한 conf 설정과 logs 확인이 가능하도록 docker-compose.yml 파일을 수정합니다.
그리고 아래 SSL 인증서 사용을 위해 호스트 서버와 컨테이너의 포트 (443) 도 연결 설정을 해줍니다.

vi docker-compose.yml

=================================================================

    httpd:
        image: httpd:2.4.54
        container_name: httpd
        restart: unless-stopped
        ports:
            - "80:80"
            - "443:443"
        volumes:
            - /home/93it/httpd/html/:/usr/local/apache2/htdocs/
            - /home/93it/httpd/conf/:/usr/local/apache2/conf/
            - /home/93it/httpd/logs/:/usr/local/apache2/logs/

=================================================================

 

변경된 yml파일을 적용하기 위해서 컨테이너를 종료하고 삭제한 뒤 다시 적용하여 실행합니다.
docker compose stop httpd
docker rm -v httpd
docker compose up -d httpd

 

2) PHP 연동

PHP 연동에 필요한 httpd 모듈을 활성화 합니다.

 

cp -arp /home/93it/httpd/conf/httpd.conf /home/93it/httpd/conf/httpd.conf_ori
vi /home/93it/httpd/conf/httpd.conf
=================================================================

# 아래 주석 해제

LoadModule deflate_module /usr/local/apache2/modules/mod_deflate.so

LoadModule proxy_module /usr/local/apache2/modules/mod_proxy.so
LoadModule proxy_fcgi_module /usr/local/apache2/modules/mod_proxy_fcgi.so
...
# 아래 확장자는 php 컨테이너로 포워딩 처리

# 추가
ProxyPassMatch ^/(.*\.html(/.*)?)$ fcgi://php:9000/var/www/html/$1
ProxyPassMatch ^/(.*\.htm(/.*)?)$ fcgi://php:9000/var/www/html/$1
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/var/www/html/$1

=================================================================

 

echo "" >> /home/93it/httpd/conf/httpd.conf
echo "<Directory \"/home/*\">
 AllowOverride All
 Options Indexes FollowSymLinks
 Require all granted
</Directory>" >> /home/93it/httpd/conf/httpd.conf
echo "" >> /home/93it/httpd/conf/httpd.conf

 

설정 적용을 위해 httpd 컨테이너를 재시작 합니다.
docker compose restart httpd

 

3) virtualhost 설정

아래 파일에서 virtualhost 부분을 사용할 수 있도록 주석 제거하고 virtualhost 설정 파일을 수정합니다.
vi /home/93it/httpd/conf/httpd.conf
=================================================================

# 수정

<Directory />
    AllowOverride none
    Require all granted
</Directory>
=================================================================

# 주석 해제
Include conf/extra/httpd-vhosts.conf
 

cp -arp /home/93it/httpd/conf/extra/httpd-vhosts.conf /home/93it/httpd/conf/extra/httpd-vhosts.conf_ori
vi /home/93it/httpd/conf/extra/httpd-vhosts.conf
=================================================================

# 기존에 주석처리 풀려있던것들 다 삭제하고 설정

<VirtualHost *:80>
    ServerAdmin root@localhost
    DocumentRoot "/home/93it/httpd/html"

# -> 여기서 DocumentRoot를 어디로 설정하는지 따라 문제가 생깁니다.
    ServerName 도메인

    ServerAlias www.도메인
    ErrorLog "logs/도메인-error_log"
    CustomLog "logs/도메인-access_log" common
</VirtualHost>

=================================================================

 

DocumentRoot "/home/93it/httpd/html"

일단 도커 컨테이너의 httpd 기본 웹루트 디렉토리/usr/local/apache2/htdocs/ 입니다.

그러나 실제 호스트 서버에서는 /home/93it/httpd/html 인것 뿐입니다. 그렇기 때문에 해당 설정을 다시 적용한다면, 도커 컨테이너 안에서 /home/93it/httpd/html 디렉토리는 없으므로 404 error 나타냅니다.

컨테이너에 접속을 하여 설정을 하거나, 서버의 파일을 컨테이너에 넣어야합니다.

 

분명 해당 디렉토리 폴더경로가 없으므로 컨테이너 안에 접속해서 디렉토리를 만들어줘야 합니다.

docker exec -it httpd /bin/bash

=================================================================

root@4df7a309c528:/usr/local/apache2# mkdir -p /home/93it/httpd/html/

root@4df7a309c528:/usr/local/apache2# exit

=================================================================

4) Docker 서버 <-> 컨테이너 파일 전송

명령어
1. 호스트 -> 컨테이너

명령어 : docker cp /path입력/text.txt 도커명:/path입력/text.txt
ex : docker cp /tmp/text.txt dockertest:/tmp/text.txt

2. 컨테이너 -> 호스트

명령어 : docker cp 도커명:/path입력/text.txt    /path입력/text.txt 
ex : docker cp dockertest:/tmp/text.txt    /tmp/text.txt 

 

docker cp /home/93it/httpd/html/* httpd:/home/93it/httpd/html/

=================================================================

Preparing to copy...
Copying to container - 2.048kB
Successfully copied 2.048kB to httpd:/home/93it/httpd/html/

=================================================================

 

-> 이 방식을 해야하는 이유는 DocumentRoot 때문에 그럴 수도 있지만, certbot을 이용하여 Let's encrypt 인증서를 받기 위해서 문제가 생깁니다.

 

 

실제 설정이 되어 있는지 확인해볼것

docker exec -it httpd /bin/bash

docker exec -it php /bin/bash

 

컨테이너 재시작 후 웹브라우저에서 잘 출력되는지 다시 확인해봅니다.
docker compose restart httpd

docker compose restart php


('403 Forbidden' 에러가 출력될 경우)
chmod 755 /home/93it 와 같이 홈 소스 디렉토리가 있는지 확인하고 접근 권한 (퍼미션 755) 을 확인해 봅니다.

 

5) SSL 발급 및 설정

준비된 SSL 유료인증서가 없으므로 Let's encrypt 에서 발급받아 적용 해봅니다.

서버에서 설정된 WebRootDirectory는 /home/93it/httpd/html

컨테이너에서 vhost에 의해서 웹소스파일들을 호스트에서 컨테이너로 넣는 작업을 했다면 WebRoot방식의 인증서를 발급받을 수 있습니다. 

그러나 해당 작업을 하지 않는다면, --standalone 방식으로 발급을 받아야합니다.

 

--webroot / 도커를 종료하지 않아도 무중단으로 발급을 받을 수 있습니다.

--standalone / 도커를 종료하고 발급받을 동안 종료된 상태로 재발급을 받아야합니다.

 

nslookup 확인할시 꼭 ip로 접근할 수 있어야합니다.

 

Certbot 설치

apt-get install -y certbot

 

(WebRoot 방식을 적용할 예정)

certbot certonly --webroot --agree-tos -m [서버관리자이메일] -w [웹루트 디렉토리 위치] -d [도메인 1] -d [도메인 2(보통 www.원도메인)] -d [도메인 3] --rsa-key-size 4096

 

(Standalone 방식)

docker compose stop httpd

certbot certonly --webroot --agree-tos -m [서버관리자이메일] -w [웹루트 디렉토리 위치] -d [도메인 1] -d [도메인 2(보통 www.원도메인)] -d [도메인 3] --rsa-key-size 4096

docker compose start httpd

 

인증서 파일을 발급 받았으면 컨테이너에서 인증서 파일 인식이 가능하도록 복사해 줍니다.

mkdir /home/93it/httpd/conf/ssl
cp -arp /etc/letsencrypt/archive   /home/93it/httpd/conf/ssl/

cp -arp /etc/letsencrypt/live   /home/93it/httpd/conf/ssl/

httpd 설정 파일을 아래와 같이 수정합니다.

vi /home/93it/httpd/conf/httpd.conf
=================================================================

LoadModule ssl_module modules/mod_ssl.so    # 주석 해제
Include conf/extra/httpd-ssl.conf    # 주석 해제
=================================================================

 

cp -arp /home/93it/httpd/conf/extra/httpd-ssl.conf /home/93it/httpd/conf/extra/httpd-ssl.conf_ori

 

vi /home/93it/httpd/conf/extra/httpd-ssl.conf

=================================================================

# 주석 처리
#SSLSessionCache        "shmcb:/usr/local/apache2/logs/ssl_scache(512000)"    

#SSLSessionCacheTimeout  300

# 아래처럼 변경

SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLProxyProtocol -all +TLSv1.2 +TLSv1.3

 

<VirtualHost _default_:443>

~

</VirtualHost>

-> 이부분을 전부 아래와 같이 변경 / 주석처리도 전부 제거 

 

<VirtualHost *:443>

ServerAdmin root@localhost
DocumentRoot "/home/93it/httpd/html"
ServerName 도메인
ServerAlias www.도메인
ErrorLog "logs/storeseason.co.kr-error_log"
TransferLog "logs/storeseason.co.kr-access_log"

SSLEngine on

SSLCertificateKeyFile "conf/ssl/live/storeseason.co.kr/privkey.pem"
SSLCertificateFile "conf/ssl/live/storeseason.co.kr/cert.pem"
SSLCertificateChainFile "conf/ssl/live/storeseason.co.kr/fullchain.pem"
########SSLCACertificateFile "conf/ssl/live/storeseason.co.kr/"

<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/usr/local/apache2/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>

BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0

CustomLog /proc/self/fd/1 \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>

=================================================================

여기서 실제 설정파일은 /home/93it/httpd/conf/ssl/ 하위파일에 있지만, 컨테이너 입장에서는 /usr/local/apache2/conf/ssl 입니다. 그렇기 때문에 인증서파일 선언할때 절대경로로 할 경우 무조건 컨테이너 입장에서 디렉토리 경로를 기재를 해야합니다. 아니라면 컨테이너와 호스트 파일의 경로일치를 해야합니다. 그럼 파일 복사 넣어주기... 또는 conf/ssl/live/storeseason.co.kr/privkey.pem 이렇게 말고 /usr/local/apache2/conf/ssl/live/storeseason.co.kr/privkey.pem 이렇게 적어야합니다.

 

설정 적용을 위해 컨테이너를 재시작하면 웹브라우저에서 https 로 접근하여 인증서 확인이 가능합니다.

docker compose restart httpd

 

6) 무료 인증서 자동갱신 설정

재시작 후 접속하면 https 인증서가 제대로 적용이 되어 있을겁니다.

이제 자동 갱신부분을 설정해봅니다.

 

vi /etc/crontab

=================================================================

30 4 1,16 * * root /usr/bin/certbot renew
32 4 1,16 * * root \/usr/bin/cp -arpf /etc/letsencrypt/archive /home/93it/httpd/conf/ssl/
32 4 1,16 * * root \/usr/bin/cp -arpf /etc/letsencrypt/live /home/93it/httpd/conf/ssl/

33 4 1,16 * * root cd /root && /usr/bin/docker compose restart httpd

=================================================================

 

systemctl enable cron

systemctl restart cron

댓글