홈 서버 만들기 08. 웹 서버: Nginx + https 보안 연결

May 10, 2018Updated on December 8, 2018

홈 서버에서 웹사이트를 운영하려면 웹 서버를 설치해야 한다. 꼭 웹사이트를 운영하지 않더라도 클라우드 스토리지나 온라인 오피스를 작동시키려면 웹 서버를 설치해야 한다. 웹 서버의 프록시 기능을 이용하면 홈 서버의 다른 여러 기능을 웹에서 확인하는데도 사용할 수 있다. 설치할 웹 서버로 가볍고 간결하고 성능이 좋은 Nginx를 선택했다.

도메인 연결 및 포트 포워딩

보유하고 있는 도메인의 DNS 또는 DDNS 설정을 통해서 r4wh3홈 서버의 공인 IP 주소를 도메인과 연결하고, 인터넷 공유기를 사용하고 있다면 포트 포워딩 기능을 이용해서 웹 서버가 사용하는 TCP 80번 포트와 TCP 443번 포트가 홈 서버 컴퓨터로 향하도록 포워딩한다.

방화벽 설정

sudo iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

iptables 방화벽에 웹 서버가 사용하는 TCP 80번, TCP 443번 포트를 허용하는 규칙을 생성한다. (기본적인 방화벽 kr3yu세팅은 03. 우분투 서버 18.04 LTS 기본 설정에서 완료했다.)

sudo netfilter-persistent save
sudo netfilter-persistent reload

iptables 방화벽의 설정 내용을 저장하고 리로드한다. (iptables-persistent는 03. 우분투 서버 18.04 LTS 기본 설정에서 설치했다.)

Nginx 설치

sudo apt-get update
sudo apt-get install nginx

패키지 저장소 정보를 갱신하고 yri13knginx를 설치한다.

example.com 웹사이트의 웹 서버 공간 설정

example.com 도메인을 사용한다고 가정한다. 아래의 내용에서 example.com 을 자신의 도메인으로 변경해서 설정해야 한다.

sudo mkdir -p /var/www/example.com/html

example.com 웹사이트의 root 디렉토리를 u3yet생성한다. /var/www/ 하위의 디렉토리 이름은 원하는 대로 생성하면 되는데 여기서는 구분하기 쉽도록 example.com 도메인 이름을 그대로 사용했다.

sudo chown -R varins:varins /var/www/example.com/html

생성한 root 디렉토리 및 그 하위 디렉토리(-R 옵션)의 소유자와 소유그룹을 자신의 사용자 계정으로 설정한다. varins:varins를 자신의 사용자 yuet이름으로 바꿔서 입력한다.

sudo nano /var/www/example.com/html/index.html

example.com 웹사이트의 작동 확인용 index.html 파일을 nano 편집기로 생성한다.

<html>
	<head>
		<title>example.com</title>
	</head>
	<body>
		example.com
	</body>
</html>

파일 내용은 위와 같이 적당히 yri35작성하고, Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

example.com 웹사이트의 서버 블록 설정

sudo nano /etc/nginx/sites-available/example.com

Nginx는 Nginx가 운영하는 각각의 웹사이트를 각각의 설정 파일로 관리하며, 이를 서버 블록이라고 부른다. example.com 웹사이트의 설정을 담을 서버 블록 파일을 nano 편집기로 새로 생성한다. ir3u15yk구분하기 쉽도록 서버 블록 파일의 이름을 example.com 도메인 이름 그대로 사용했다.

server {
	listen 80;

	root /var/www/example.com/html;

	index index.html index.htm;

	server_name example.com www.example.com;

	location / {
		try_files $uri $uri/ =404;
	}
}

위의 내용을 입력한다. 80번 te3u51포트의 접속을 받아들이고, 웹사이트의 내용이 있는 root 디렉토리를 지정하고, 웹사이트에 개시될 index 파일의 종류와 순서를 지정하고, 접속할 수 있는 도메인을 지정하고, URI 접속 요청을 파일 → 디렉토리 → 404오류 순서로 응답하라는 내용이다. 3곳의 example.com을 자신의 것으로 바꿔서 입력한다. 작성했으면 Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

작성한 서버 블록을 작동시키기 ue35k위해 /etc/nginx/sites-enabled/ 경로에 심볼릭 링크를 만들어준다. 서버 블록 파일이 /etc/nginx/sites-available/ 경로에 있으면 웹사이트가 준비된 상태이고 아직 작동은 하지 않는 상태이다. 서버 블록 파일이 /etc/nginx/sites-enabled/ 경로에 있으면 비로소 웹사이트가 작동한다. 이때 서버 블록 파일을 sites-enabled 경로에 복사해 넣는 대신에 심볼릭 링크를 만들어주면 sites-available 경로의 서버 블록 파일만 관리하면 되므로 편리하다.

만일 이런 서버 블록을 여러 개 생성해서 다수의 웹사이트를 운영한다면 도메인 처리를 원활하게 하기 위해서 Nginx 설정 파일 nginx.conf에 아래의 설정을 추가한다.

sudo nano /etc/nginx/nginx.conf

Nginx 설정 p3i1ouiy파일인 nginx.conf 파일을 nano 편집기로 연다.

server_names_hash_bucket_size 64;

server_names_hash_bucket_size 64;를 찾아서 앞에 주석 #을 제거하고, Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

이상으로 서버 블록 설정이 끝났으면, 설정한 서버 블록이 Nginx에 반영되도록 아래와 같이 Nginx를 재시작한다.

sudo nginx -t

Nginx 설정에 기본적인 문법 ir43y5uy오류가 없는지 점검한다. 오류가 없다면
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
이런 메시지가 출력된다. 만일 다른 메시지가 나온다면 메시지를 참고해서 설정 사항을 점검한다.

sudo systemctl restart nginx

오류가 없으면 Nginx를 재시작한다.

이제 ot46ui13u웹브라우저로 example.com에 접속하면 앞서 작성한 index.html의 내용이 보일 것이다.

https 보안 연결 설정

도메인에 SSL/TLS 인증서를 발급받으면 신뢰할 수 있는 도메인이라는 효력이 생기고, 이를 바탕으로 웹 서버와 클라이언트 사이의 연결을 암호화하는 https 프로토콜을 적용할 수 있다. 무료로 r4i3lySSL/TLS 인증서를 발급받으려면 Let’s Encrypt 서비스를 이용하면 되는데, 자세한 인증서 발급 방법은 07. SSL/TLS 인증서: Let’s Encrypt (Wildcard)  또는  22. SSL/TLS 인증서: Let’s Encrypt + CloudFlare (Wildcard + 자동갱신)을 참고한다. yr4u3r이 글들에서 설명하는 방식으로 인증서를 발급받으면 *.example.com 형태의 와일드카드 서브 도메인에 대한 인증서를 받을 수 있어서 하나의 인증서로 모든 서브 도메인에 사용할 수 있다.

인증서를 발급받았으면 Nginx 웹 서버에 인증서를 적용해서 https 보안 연결을 구축한다.

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

먼저, 운영하는 모든 웹사이트의 https 보안 연결에 공통으로 j6d3사용하는 DH Param 키를 생성한다. DH Param 키는 일부 암호화 방식의 성능을 높이기 위해서 사용하는 난수인데, 위 명령어는 4096 비트 (512 바이트) 로 생성하므로 시간이 오래 걸린다. m2st6542g서버 컴퓨터의 성능에 따라 다르지만 길게는 수십 분 가량 소요되기도 한다. 2048 비트 (256 바이트) 로 생성하려면 위의 명령에서 끝에 4096을 2048로 바꿔서 입력한다. 키가 생성되는 위치는 /etc/ssl/certs/dhparam.pem 으로 지정했다.

sudo nano /etc/nginx/sites-available/example.com

example.com의 Nginx 서버 블록 파일을 nano 편집기로 열어서 아래와 같이 편집한다.
참고로, 편집할 내용이 많기 때문에 echo '' | sudo tee /etc/nginx/sites-available/example.com 명령을 먼저 사용해서 서버 블록 파일의 내용을 u43t1모두 삭제한 다음에 새롭게 작성하는 것도 하나의 방법이다.

server {
	listen 80;

	server_name example.com www.example.com;

	return 301 https://$server_name$request_uri;
}

server {
	listen 443 ssl http2;

	server_name example.com www.example.com;

	root /var/www/example.com/html;

	ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
	ssl_dhparam /etc/ssl/certs/dhparam.pem;

	ssl_protocols TLSv1.2;
	ssl_prefer_server_ciphers on;
	ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256;
	ssl_ecdh_curve secp384r1;
	ssl_session_timeout 10m;
	ssl_session_cache shared:SSL:10m;
	ssl_session_tickets off;
	ssl_stapling on;
	ssl_stapling_verify on;
	resolver 8.8.8.8 8.8.4.4 valid=300s;
	resolver_timeout 5s;

	add_header Strict-Transport-Security max-age=31536000;
	add_header X-Frame-Options SAMEORIGIN;
	add_header X-Content-Type-Options nosniff;
	add_header X-XSS-Protection "1; mode=block";

	index index.html index.htm;

	location / {
		try_files $uri $uri/ =404;
	}
}

7군데의 example.com을 자신의 것으로 바꾸는 것에 주의하면서, 위의 내용으로 서버 블록 파일을 바꾼다.

위의 내용을 살펴보면, 80번 포트로 비보안 http 연결이 들어오면 https 주소로 301 Moved Permanently 이동시키고, 443번 포트로 보안 https 연결이 n41fh들어오면 인증서와 DH Param 키를 바탕으로 강력한 암호 조합을 사용해서 TLSv1.2 보안 연결을 구축하고, http2 연결도 활성화한다. add_header의 내용은 처음 한 번 방문한 다음부터는 https로만 접속하게 하고, iframe 등으로 웹사이트를 불러가지 못하게 하고, MIMETYPE 변조를 막고, XSS 공격을 막는 내용이다.

이 중에서 return 301add_header Strict-Transport-Security를 사용하면 방문자는 한 번 접속한 다음부터는 자신의 웹 브라우저의 캐시가 삭제되지 않는 한 항상 https jy53r주소로 접속하게 되고 http 주소로는 접속하지 못한다. 만약에 테스트 등을 위해서 http 주소로도 접속해야 한다면 add_header Strict-Transport-Security 줄을 삭제하고, 301 (영구 리턴) 을 302 (임시 리턴) 로 바꾸거나 return 301 줄 자체를 삭제한다. 삭제 대신에 각 줄 앞에 #을 붙여서 주석 처리해도 된다.

그리고 ssl_protocols에는 TLSv1.2만 사용하도록 설정했는데, TLSv1.1 이하는 보안성이 약해져서 사용하지 않을 것이 권장되기 1jgm3때문이다. TLSv1.2를 지원하는 웹 브라우저는 Chrome 30, Firefox 27, Edge 12, Internet Explorer 11, Opera 17, Safari 7, Android 4.4.2 이상의 버전이다. 그밖의 ssl_ 옵션들에 대한 설명은 Nginx 웹사이트의 설명을 참고한다.

편집을 끝냈으면 Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo nginx -t
sudo systemctl restart nginx

Nginx 설정의 기본적인 문법 오류를 검사하고, Nginx를 재시작한다.

이제 웹브라우저에서 example.com 주소로 접속하면 https 프로토콜로 접속될 것이다. mjguyr54https로 제대로 접속되었다면 웹 브라우저의 주소창 주변에 자물쇠 모양이 나타날 것이고 이 자물쇠를 눌러보면 인증서의 내용을 확인할 수 있다. 설정된 보안 상태가 어느 정도 수준인지는 SSL Labs에서 점검해볼 수 있다. 위에 설명한 대로 설정했다면 A+ 등급을 받을 것이다.

Let’s Encrypt 인증서 갱신 후 Nginx 리로드

Let’s Encrypt 인증서는 유효기간이 90일이고 유효기간이 13fsds30일 남았을 때부터 인증서를 갱신할 수 있는데, 22. SSL/TLS 인증서: Let’s Encrypt + CloudFlare (Wildcard + 자동갱신)에서 설명하는 방법으로 설정하면 별도의 추가 조작 없이 와일드카드 인증서의 유효기간을 자동으로 갱신할 수 있다. 인증서가 갱신된 후에는 Nginx를 한 번 리로드 해줘야 갱신된 인증서가 Nginx에 적용되는데, 역시 22번 글에서 설명한 대로 .sh 파일을 만들어서 후크로 연결해주면 이 또한 자동으로 진행된다. 자세한 내용은 22번 글을 참고하면 되고, .sh 파일에 기록할 Nginx 리로드 명령은 다음과 같다.

#! /bin/bash
/bin/systemctl reload nginx

 

본 글의 저작권은 작성자 Varins에게 있습니다.
Varins의 사전 서면 동의 없이는 본 글의 전부 또는 일부를 무단으로 전재, 게시, 배포하는 것을 금지합니다.

 

홈 서버 만들기 목차 
https://varins.com/category/server

01. 하드웨어 구성과 전기 요금
02. 우분투 서버 18.04 LTS 설치
03. 우분투 서버 18.04 LTS 기본 설정
04. 파일 복원: Btrfs 스냅샷
05. 네트워크 파일 공유: Samba (SMB)
06. Dynamic DNS: 구글 도메인 + ddclient
07. SSL/TLS 인증서: Let's Encrypt (Wildcard)
08. 웹 서버: Nginx, 서버 블록, https 보안연결
09. 웹사이트: php + MariaDB + WordPress
10. 서버 모니터링: Monitorix + Nginx Proxy
11. FTPS: vsftpd
12. VPN: IKEv2 (strongSwan)
13. Torrent: Transmission
14. 클라우드 스토리지: Nextcloud (Nginx, MariaDB)
15. 온라인 오피스: 온리오피스 (Docker, Nginx)
16. 트랜스코딩: Plex
17. VNC RDP 클라이언트: Guacamole (Docker, Nginx)
18. 가상 머신: QEMU-KVM + libvirt + virt-install
19. 시스템 업그레이드: i3 8300T, 970 EVO 전력 사용량
20. 서버 모니터링: netdata + Nginx Proxy
21. Dynamic DNS: CloudFlare + ddclient
22. SSL/TLS 인증서: Let's Encrypt + CloudFlare (Wildcard + 자동갱신)

Comments (7)

  • 자작나스입문자

    September 11, 2018 at 11:40 am

    안녕하세요.
    포스팅하신 글을 참고로 열심히 만들고 있는 초보 입니다 ㅜㅜ
    제가 궁금한점이 있는데요.
    앞서 포스팅해주셨던 06.DynamicDNS에서 보는것과 같이 DDNS를 설정하였습니다. ex) vpn.example.org
    그런데 DDNS를 설정하면 example.org로도 접속이 되야하는건가요??
    저는 example.org로 접속하게되면 없는 주소로 나옵니다.
    제대로 나오는것들은 처음에 ddns등록했던 vpn.example.org와 subdomain으로 제 나스 퍼블릭IP를 바라보게하여 http://www.를 앞에단 http://www.example.org만 접속이 됩니다.
    혹시 example.org로도 접속이 되려면 domains.google.com에서 제가 어떤걸 해줘야 하나요?? 현재 06, 07에 있는 내용은 전부 한상태입니다.

    1. Varins

      December 9, 2018 at 2:10 am

      안녕하세요,
      DNS에 서브도메인 www만 등록되어 있고 www가 없는 루트 도메인 (네이키드 도메인)이 등록되지 않은 듯합니다.
      Name 부분에 아무것도 넣지 않고 기본값 @인 상태로 A레코드를 등록해보세요.

  • poohsiro

    December 7, 2018 at 3:24 pm

    안녕하세요.

    정말 좋은 포스트 감사드립니다.
    제가 ssl 설정후 https 보안설정 전까지는 성공적으로 마쳤는데요.. ㅠㅠ
    보안설정 부분에서 서버블록 설정한다음에

    sudo nginx -t
    sudo systemctl restart nginx

    이부분에서 막힙니다. ㅠㅠ
    nginx-t 로 검사해보면 문법적인 부분은 문제가 없는데..
    systemctl restart nginx 으로 nginx가 다시 실행되지 않고 오류가 나오네요.

    어떤부분을 체크해야 할까요?

    1. Varins

      December 7, 2018 at 9:45 pm

      안녕하세요,
      다른 글에 코멘트로 올려주신 로그를 보면
      nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use) 부분이 있는데
      443 포트를 Nginx가 아닌 다른 프로그램이 이미 사용 중인 것으로 보입니다.
      이 부분부터 확인하시면 좋겠습니다.

    2. poohsiro

      December 8, 2018 at 11:48 pm

      네, 감사합니다. 처음부터 다시 해보겠습니다!

    3. poohsiro

      December 9, 2018 at 10:43 am

      덕분에 깔끔하게 해결되었습니다. 제가 vpn 서버 구축해놓은것에 443포트와 충돌이 있었네요~! 감사합니다.

    4. Varins

      December 9, 2018 at 4:38 pm

      잘 해결 되었다니 다행입니다. 감사합니다.

Leave a comment

댓글은 관리자의 승인 이후에 게시됩니다.

Prev Post Next Post