웹서버¶
대표적인 HTTP 웹서버 프로그램으로 아파치(apache2)와 nginx가 있다. 여기서는 nginx에 대해서만 다룬다.
nginx¶
설치¶
nginx
는 Extra Packages for Enterprise Linux(EPEL) 사이트로부터 다운받기 때문에 저장소를 설정해야 한다.
sudo yum install epel-release
sudo yum install nginx
nginx
를 시작한다.
sudo systemctl start nginx.service
제대로 설치되었는지 확인한다.
sudo systemctl status nginx
CentOS는 기본적으로 SSH 포트를 제외한 모든 포트를 외부로부터 차단하기 때문에 외부에서 접속이 안된다. 따라서 방화벽을 열어 주어야 웹서버로 접속이 가능하다.
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
제대로 되었나 확인해보자.
$ sudo firewall-cmd --list-all
부팅시 자동 시작하도록 설정한다.
$ sudo systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
기본 인덱스 파일 위치는 /usr/share/nginx/html/index.html
이다. 그 파일을 수정하고
sudo systemctl restart nginx
를 실행하고 접속한다.
기본 설정 폴더는 /etc/nginx
이다.
설정 파일을 수정하고 제대로 작동하는지 테스트하는 명령어이다.
sudo nginx -t
자체 인증서(self contained certificate) 생성¶
Step 2: SSL 인증서 만들기¶
TLS/SSL 은 공용 인증서와 사설 키를 이용해서 작동한다. SSL key는 서버에 안전하게 저장되며 이것은 클라이언트들에게 보내는 내용을 암호화하기 위해 사용된다. SSL 인증서는 원하는 모든 사람들에게 공유된다. 이것은 SSL 키에 의해서 암호화된 내용을 복호화하는데 사용된다.
공용키를 지니고 있는 /etc/ssl/certs
디렉토리는 이미 서버에 만들어져 있다. 사설 키를 저장할 수 있는 /etc/ssl/private
를 만든다. 사설키 안전을 위해서 권한이 없는 사용자들이 보지 못하도록 허가를 설정한다.
$ sudo mkdir /etc/ssl/private
$ sudo chmod 700 /etc/ssl/private
이제는 OpenSSL
을 이용해 사설 키와 자체 공용 인증서를 다음과 같이 만든다.
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt
명령을 실행하면 몇 가지 질문들에 대답해야 한다.You will be asked a series of questions. Before we go over that, let’s take a look at what is happening in the command we are issuing:
- openssl:
OpenSSL
인증서를 생성하고 관리하는 명령어 이다. - req: 이 부분명령어는 X.509를 인증 사인 요청(csr) 관리하는데 사용한다. “X.509”는 SSL 및 TLS의 인증키 관리하는 표준이다.
- -nodes: 이것은
OpenSSL
이 매번 암호를 요구하는 것을 건너뛰도록 한다. - -days 365: 이 옵션은 인증서의 유효 기간이다. 여기서는 1년으로 설정했다.
- -newkey rsa:2048: 이것은 새로운 키와 인증서를 동시에 생성하는 것이고 2048비트 길이의
RSA
키를 생성한다는 의미이다. - -keyout: 이것은 사설키 저장 위치를 알려주는 것이다.
- -out: 이것은 공용 인증서 저장 위치를 알려주는 것이다.
여기서 가장 중요한 것은 Common Name으로 서버 도메인 이름 주소 또는 아이피를 적어 주면 된다. 아래 예시를 참조한다.
Output
Generating a 2048 bit RSA private key
......+++
..................+++
writing new private key to '/etc/ssl/private/nginx-selfsigned.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:KR
State or Province Name (full name) []:Choongnam
Locality Name (eg, city) [Default City]:Cheonan
Organization Name (eg, company) [Default Company Ltd]:KoreaUniv
Organizational Unit Name (eg, section) []:ServerTeam
Common Name (eg, your name or your server's hostname) []:localhost.localdomain
Email Address []:daeki88@gmail.com
생성된 파일들은 /etc/ssl
디렉토리 밑에 위치해 있다.
더 안전한 통신을 위해서 다음과 같이 강력한 Diffie-Hellman
그룹을 만들도록 한다.
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
이것은 약간의 시간이 걸리지만 강력한 DH 그룹을 가지게 되며 /etc/ssl/certs/dhparam.pem
에 위치한다.
Step 3: Nginx가 SSL을 사용하도록 설정¶
The default Nginx configuration in CentOS is fairly unstructured, with the default HTTP server block living within the main configuration file. Nginx will check for files ending in .conf in the /etc/nginx/conf.d directory for additional configuration.
We will create a new file in this directory to configure a server block that serves content using the certificate files we generated. We can then optionally configure the default server block to redirect HTTP requests to HTTPS.
TLS/SSL 서버 구역 설정¶
/etc/nginx/conf.d
디렉토리에 ssl.conf
파일을 만들고 열자.
$ sudo vi /etc/nginx/conf.d/ssl.conf
Inside, begin by opening a server block. By default, TLS/SSL connections use port 443, so that should be our listen port. The server_name should be set to the server’s domain name or IP address that you used as the Common Name when generating your certificate. Next, use the ssl_certificate, ssl_certificate_key, and ssl_dhparam directives to set the location of the SSL files we generated
/etc/nginx/conf.d/ssl.conf
server {
listen 443 http2 ssl;
listen [::]:443 http2 ssl;
server_name server_IP_address;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
}
Next, we will add some additional SSL options that will increase our site’s security. The options we will use are recommendations from Remy van Elst on the Cipherli.st site. This site is designed to provide easy-to-consume encryption settings for popular software. You can learn more about his decisions regarding the Nginx choices by reading Strong SSL Security on nginx.
Note: The default suggested settings on Cipherli.st offer strong security. Sometimes, this comes at the cost of greater client compatibility. If you need to support older clients, there is an alternative list that can be accessed by clicking on the link labeled “Yes, give me a ciphersuite that works with legacy / old software.”
The compatibility list can be used instead of the default suggestions in the configuration above between the two comment blocks. The choice of which config you use will depend largely on what you need to support.
There are a few pieces of the configuration that you may wish to modify. First, you can add your preferred DNS resolver for upstream requests to the resolver directive. We used Google’s for this guide, but you can change this if you have other preferences.
Finally, you should take a moment to read up on HTTP Strict Transport Security, or HSTS, and specifically about the “preload” functionality. Preloading HSTS provides increased security, but can have far reaching consequences if accidentally enabled or enabled incorrectly. In this guide, we will not preload the settings, but you can modify that if you are sure you understand the implications.
/etc/nginx/conf.d/ssl.conf
server {
listen 443 http2 ssl;
listen [::]:443 http2 ssl;
server_name server_IP_address;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
########################################################################
# from https://cipherli.st/ #
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html #
########################################################################
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
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;
# Disable preloading HSTS for now. You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
##################################
# END https://cipherli.st/ BLOCK #
##################################
}
Because we are using a self-signed certificate, the SSL stapling will not be used. Nginx will simply output a warning, disable stapling for our self-signed cert, and continue to operate correctly.
Finally, add the rest of the Nginx configuration for your site. This will differ depending on your needs. We will just copy some of the directives used in the default location block for our example, which will set the document root and some error pages
server {
listen 443 http2 ssl;
listen [::]:443 http2 ssl;
server_name server_IP_address;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
########################################################################
# from https://cipherli.st/ #
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html #
########################################################################
. . .
##################################
# END https://cipherli.st/ BLOCK #
##################################
root /usr/share/nginx/html;
location / {
}
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
When you are finished, save and exit. This configures Nginx to use our generated SSL certificate to encrypt traffic. The SSL options specified ensure that only the most secure protocols and ciphers will be used. Note that this example configuration simply serves the default Nginx page, so you may want to modify it to meet your needs.
(Optional) Create a Redirect from HTTP to HTTPS With our current configuration, Nginx responds with encrypted content for requests on port 443, but responds with unencrypted content for requests on port 80. This means that our site offers encryption, but does not enforce its usage. This may be fine for some use cases, but it is usually better to require encryption. This is especially important when confidential data like passwords may be transferred between the browser and the server.
Thankfully, the default Nginx configuration file allows us to easily add directives to the default port 80 server block by adding files in the /etc/nginx/default.d directory. Create a new file called ssl-redirect.conf and open it for editing with this command
sudo vi /etc/nginx/default.d/ssl-redirect.conf
Then paste in this line
return 301 https://$host$request_uri/;
Save and close the file when you are finished. This configures the HTTP on port 80 (default) server block to redirect incoming requests to the HTTPS server block we configured.
Step 4: Enable the Changes in Nginx¶
Now that we’ve made our changes, we can restart Nginx to implement our new configuration.
First, we should check to make sure that there are no syntax errors in our files. We can do this by typing
sudo nginx -t
If everything is successful, you will get a result that looks like this
Output
nginx: [warn] "ssl_stapling" ignored, issuer certificate not found for certificate "/etc/ssl/certs/nginx-selfsigned.crt"
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Notice the warning in the beginning. As noted earlier, this particular setting throws a warning since our self-signed certificate can’t use SSL stapling. This is expected and our server can still encrypt connections correctly.
If your output matches the above, your configuration file has no syntax errors. We can safely restart Nginx to implement our changes:
sudo systemctl restart nginx
The Nginx process will be restarted, implementing the SSL settings we configured.
무료 SSL 공인 인증서 생성¶
준비물¶
참고: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-centos-7
- 등록된 공인 도메인 이름이 있어야 한다. 즉,
example.com
과 같은 이름이 등록되어 있어야 한다 - 등록된 도메인 이름이 DNS를 통해서 접근가능해야 한다.
Certbot 설치¶
Certbot는 Let’s Encrypt 인증서를 자동으로 재발급할 수 있게하는 프로그램이다.
sudo yum install epel-release
sudo yum install certbot-nginx
Step 2 — Setting up Nginx¶
If you haven’t installed Nginx yet, you can do so now. The EPEL repository should already be enabled from the previous section, so you can install Nginx by typing
sudo yum install nginx
Then, start Nginx using systemctl
sudo systemctl start nginx
Certbot can automatically configure SSL for Nginx, but it needs to be able to find the correct server block in your config. It does this by looking for a server_name directive that matches the domain you’re requesting a certificate for. If you’re staring out with a fresh Nginx install, you can update the default config file
sudo vi /etc/nginx/nginx.conf
Find the existing server_name line
/etc/nginx/sites-available/default
server_name _;
Replace the _ underscore with your domain name
/etc/nginx/nginx.conf
server_name example.com www.example.com;
Save the file and quit your editor. Verify the syntax of your configuration edits with
sudo nginx -t
If that runs with no errors, reload Nginx to load the new configuration
sudo systemctl reload nginx
Certbot will now be able to find the correct server block and update it. Now we’ll update our firewall to allow HTTPS traffic.
Step 3 — Updating the Firewall¶
If you have a firewall enabled, make sure port 80 and 443 are open to incoming traffic. If you are not running a firewall, you can skip ahead.
If you have a firewalld firewall running, you can open these ports by typing
sudo firewall-cmd --add-service=http
sudo firewall-cmd --add-service=https
sudo firewall-cmd --runtime-to-permanent
If have an iptables firewall running, the commands you need to run are highly dependent on your current rule set. For a basic rule set, you can add HTTP and HTTPS access by typing
sudo iptables -I INPUT -p tcp -m tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT -p tcp -m tcp --dport 443 -j ACCEPT
We’re now ready to run Certbot and fetch our certificates.
Step 4 — Obtaining a Certificate¶
Certbot provides a variety of ways to obtain SSL certificates, through various plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary
sudo certbot --nginx -d example.com -d www.example.com
This runs certbot with the –nginx plugin, using -d to specify the names we’d like the certificate to be valid for.
If this is your first time running certbot, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot will communicate with the Let’s Encrypt server, then run a challenge to verify that you control the domain you’re requesting a certificate for.
If that’s successful, certbot will ask how you’d like to configure your HTTPS settings
Output
$ sudo certbot --nginx -d example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): daeki88@gmail.com
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A
-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and
our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o: Y
Starting new HTTPS connection (1): supporters.eff.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/nginx.conf
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): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/nginx.conf
-------------------------------------------------------------------------------
Congratulations! You have successfully enabled https://example.com
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=example.com
-------------------------------------------------------------------------------
Select your choice then hit ENTER. The configuration will be updated, and Nginx will reload to pick up the new settings. certbot will wrap up with a message telling you the process was successful and where your certificates are stored
Output
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.com/privkey.pem
Your cert will expire on 2018-08-05. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Your certificates are downloaded, installed, and loaded. Try reloading your website using https:// and notice your browser’s security indicator. It should represent that the site is properly secured, usually with a green lock icon.
Step 5 — Updating Diffie-Hellman Parameters¶
이부분은 certbot가 자동으로 만들어주는 것 같다. 중복되는 내용이니 생략해도 될 것 같다.
If you test your server using the SSL Labs Server Test now, it will only get a B grade due to weak Diffie-Hellman parameters. This effects the security of the initial key exchange between our server and its users. We can fix this by creating a new dhparam.pem file and adding it to our server block.
Create the file using openssl
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
This will take a while, up to a few minutes. When it’s done, open up the Nginx config file that contains your server block. In our example, it’s the default config file
sudo vi /etc/nginx/nginx.conf
Past the following line anywhere within the server block
/etc/nginx/nginx.conf
. . .
ssl_dhparam /etc/ssl/certs/dhparam.pem;
Save the file and quit your editor, then verify the configuration
sudo nginx -t
If you have no errors, reload Nginx
sudo systemctl reload nginx
Your site is now more secure, and should receive an A rating.
Step 6 — 자동 갱신 설정¶
Let’s Encrypt’s certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. We’ll need to set up a regularly run command to check for expiring certificates and renew them automatically.
To run the renewal check daily, we will use cron, a standard system service for running periodic jobs. We tell cron what to do by opening and editing a file called a crontab.
sudo crontab -e
Your text editor will open the default crontab which is an empty text file at this point. Paste in the following line, then save and close it
crontab
. . .
15 3 * * * /usr/bin/certbot renew --quiet
The 15 3 * * * part of this line means “run the following command at 3:15 am, every day”. You may choose any time.
The renew command for Certbot will check all certificates installed on the system and update any that are set to expire in less than thirty days. –quiet tells Certbot not to output information or wait for user input.
cron will now run this command daily. All installed certificates will be automatically renewed and reloaded when they have thirty days or less before they expire.
For more information on how to create and schedule cron jobs, you can check our How to Use Cron to Automate Tasks in a VPS guide.
자동 갱신할 때 다음과 같은 에러가 나올 때는 nginx 서버를 멈추고 갱신을 해본다.
Incorrect validation certificate for tls-sni-01 challenge ... Received 2 certificate(s)
즉,
$ sudo systemctl stop nginx
$ sudo certbot renew
또는 gitlab 서버가 작동할 때는 nginx가 깃랩에 종속으로 실행이 됩니다. 따라서
sudo systemctl status gitlab-runsvdir
gitlab-runsvdir을 수동으로 죽여도
$ sudo systemctl stop gitlab-runsvdir
계속해서 nginx가 살아 있어서 수동으로 nginx 프로세스를 죽일 수 밖에 없었습니다. 그리고 certbot를 renew를 한 후
$ sudo certbot renew
깃랩을 다시 시작했습니다.
$ sudo systemctl start gitlab-runsvdir
$ sudo gitlab-ctl start
다음과 같이 했더니 실행이 잘 되었습니다.(2019년 3월 27일)
먼저 gitlab-ctl 명령어를 이용해서 다음과 같이 실행했습니다.
$ sudo gitlab-ctl renew-le-certs
우선 --dry-run
옵션으로 에러가 발생하는지를 확인하고 발생하지 않으면 옵션 빼고 실행하면 됩니다.
$ sudo certbot renew --dry-run
$ sudo certbot renew
갱신 되었는지는 사이트 접속하여 주소창 왼쪽에 자물쇠를 클릭하면 종료일이 변경된 것을 확인할 수 있습니다.
자동 리다이렉트¶
cerbot은 http를 https로 자동으로 리다이렉트하는 스크립트를 nginx.conf 파일에 다음과 같이 적습니다.
server {
if ($host = compmath.korea.ac.kr) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name compmath.korea.ac.kr;
return 404; # managed by Certbot
}
따라서 브라우저 또는 curl을 이용하여 http post로 접속하면 자동으로 get으로 전환시켜서 get 메소드가 자동 실행되는 경우가 생깁니다. 이럴 때는 https post를 이용하는 방법과 301을 307로 변경하는 방법이 있습니다. 그렇지만 이 방법은 위험한 방법입니다. 다음 글을 읽어보세요. https://rsec.kr/?p=315 와 https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/