홈서버 (MacMini) 운용 방법 4
Nginx으로 CodeServer에 https 붙이기
한번 해보면 어렵지 않다. 처음에는 무지 어려웠다...
1. nginx 설치
아래 명령어를 참고해서 nginx를 MacOS에 설치한다.
#1 패키지 설치
brew install nginx
#2 서비스 시작
brew services start nginx
#3 서비스 목록
brew services
# 서비스 재시작
brew services restart nginx
#4 8080포트 접근시 nginx 도달 확인하자.
> http://123.123.123.123:8080/
80 포트로 변경해서 nginx접근이 되는지 확인
설정파일에서 80 포트로 변경해서 nginx접근이 되는지 확인
# 1. nginx.conf 파일 경로 확인
brew info nginx
# 1.1 아래처럼 설정파일 경로를 확인
...
The default port has been set in /opt/homebrew/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.
...
# 2. 설정 파일 변경
설정 파일 경로 : /opt/homebrew/etc/nginx/nginx.conf
- 포트 8080 > 80 변경
#3. 서비스 재시작
brew services restart nginx
#3 nginx 도달 확인 (port 80)
> http://123.123.123.123
2. 도메인 연결
DNS Record
가비아에서 구매한 도메인을 연결하기 위해 DNS 레코드를 수정해야한다.
간단하게 레코드 타입을 설명하면
- A 타입을 주로 사용한다. 도메인과 IP를 연결한다.
- 서브 도메인이라는 개념이 있다.
- 내가 구매한 도메인이 my-coding.site 라면
- www.my-coding.site, blog.my-coding.site 등 무한으로 서브도메인을 사용할 수 있다.
- 서브도메인이 없는 경우는 @ 라고 쓰면 된다.
- CNAME 은 도메인과 도메인을 연결한다.
- 티스토리 블로그를 운영하는데, 개인 도메인을 가지고 싶을때 사용한다.
A Type 설정 후 도메인 접속 확인
my-coding.site 도메인을 구매 후 www.my-coding.site 도메인과 내 맥미니 서버와 연결해야 한다.
#1 A 타입으로 레코드를 추가한다.
- eg) www.my-coding.site -> 123.123.123.123 설정을 원한다면
- host : www ( host는 www 이며 서브도메인을 뜻한다. )
# 참고)
- eg) my-coding.site -> 123.123.123.123 설정을 원한다면
- host:@
- Note) host에 @은 서브도메인이 없는 경우이다.
- 즉, http://my-coding.site 로 접속하면 지정된 IP로 이동한다.
#2 nginx 도달 확인
>http://www.my-coding.site
3. https 적용 - 인증서 발급
https://ukprog.tistory.com/125
certbot으로 인증서를 발급하는 방법은 2가지가 있다.
- manual 방식
- nginx, apache 등 서버를 명시하는 자동 발급 방식
- 후자의 방법을 추천한다.
자동 발급 방식
# 1. nginx에 https 인증서를 받는 명령어
# 도메인이 여러개인/하나인 경우
sudo certbot --nginx --nginx-server-root /opt/homebrew/etc/nginx -d domain.com,www.domain.com
sudo certbot --nginx --nginx-server-root /opt/homebrew/etc/nginx -d domain.com
# --nginx-server-root 경로 지정, brew로 nginx을 설치해서 기본 경로랑 다르다.!
# --nginx : cerbot이 처리할 대상의 서버, apache등이 있다.
# 위 명령어가 수행되면 nginx.conf파일이 저절로 변경된다.
# 2. 아래 파일을 nginx가 읽도록 권한 부여하기
# sudo chmod -R 755 /etc/letsencrypt
# 3. 재시작
# nginx -t
# brew services restart nginx
참고) manual 방식
# 1. 인증서 발급 시작
sudo certbot certonly --manual
(가능하면 아래 명령어로 nginx 설정을 자동으로 설정하게끔 하자.)
sudo certbot --nginx -d yourdomain.com
# 2. 연결할 도메인 입력
www.my-coding.site
# 도메인에 아래 파일 서빙하도록 nginx 설정 변경
Create a file containing just this data:
Emu_LEu_HbaAeKH6OrOER88xvjurfFKRJM7-MoYhjN9.HpJsIlJVhSaVM-6mjKz5_4ZU5tydqNW2B5pjcvuHjS0
And make it available on your web server at this URL:
http://www.my-coding.site/.well-known/acme-challenge/Emu_LEu_HbaAeKH6OrOER88xvjurfFKRJM7-MoYhjN9
# nginx.conf 추가
---
server {
listen 80 ;
server_name www.my-coding.site;
location /.well-known/acme-challenge {
alias /opt/homebrew/etc/nginx/.well-known/acme-challenge; # 실제 파일이 위치한 경로를 지정합니다.
try_files $uri $uri/ /opt/homebrew/etc/nginx/.well-known/acme-challenge/Emu_LEu_HbaAeKH6OrOER88xvjurfFKRJM7-MoYhjN9; # 특정 파일명을 여기에 지정합니다.
}
location / { # HTTP to HTTPS 리디렉션
return 301 https://$host$request_uri;
}
}
...
---
mkdir -p .well-known/acme-challenge/
vi Emu_LEu_HbaAeKH6OrOER88xvjurfFKRJM7-MoYhjN8
Emu_LEu_HbaAeKH6OrOER88xvjurfFKRJM7-MoYhjN8.HpJsIlJVhSaVM-6mjKz5_4ZU5tydqNW2B5pjcvuHjS0 입력 후 저장
#3. nginx 재실행
nginx -t # 문법 검사
brew services restart nginx # 재시작
#4. cerbot 확인 후 발급 성공
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/www.my-coding.site /fullchain.pem
Key is saved at: /etc/letsencrypt/live/www.my-coding.site /privkey.pem
This certificate expires on 2023-11-08.
These files will be updated when the certificate renews.
#5. 인증서 읽기 권한 문제 해결
sudo chmod -R 755 /etc/letsencrypt
#6. https 처리하는 nginx.conf 추가
---
server {
listen 443 ssl;
server_name www.my-coding.site;
ssl_certificate /etc/letsencrypt/live/www.my-coding.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.my-coding.site/privkey.pem;
# SSL 설정 (최신 보안 권장)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
# SSL 세션 캐싱 설정
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:3030/;
}
}
...
4. 인증서 갱신
sudo certbot certonly --manual 명령어를 이용했더라면 자동으로 갱신이 불가능 하다.
[certbot]
# 인증서 정보 , 유효기간, 경로 확인
sudo certbot certificates
# 인증서 발급
sudo certbot --nginx -d yourdomain.com
sudo certbot certonly --manual
# 인증서 갱신 dry-run
sudo certbot renew --dry-run
# 인증서 갱신 (--apache, --nginx 등으로 자동 발급한 경우)
sudo certbot renew
# 인증서 갱신 (자동 발급, --nginx 경로를 지정해야 하는 경우 )
sudo certbot renew --nginx --nginx-server-root /opt/homebrew/etc/nginx
# 인증서 갱신 (--manual 로 발급한 경우)
sudo certbot certonly --manual --dry-run -d www.your-domain.com
- /opt/homebrew/etc/nginx
cron job
echo "0 0,12 * * root python -c 'import random; import time; time.sleep(random.random() 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
최종 nginx.conf
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 443 ssl; # managed by Certbot
server_name www.you-domain.site; # managed by Certbot
ssl_certificate /opt/homebrew/etc/nginx/fullchain.pem; # managed by Certbot
ssl_certificate_key /opt/homebrew/etc/nginx/privkey.pem; # managed by Certbot
# SSL 설정 추가 (optional, 추천)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
location / {
proxy_pass http://127.0.0.1:2229/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80 ;
server_name www.you-domain.site;
location / { # HTTP to HTTPS 리디렉션
return 301 https://$host$request_uri;
}
}
include servers/*;
}
예) 최종 nginx.conf (code-server)
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# vscode
server {
listen 443 ssl;
server_name code.coding-play.site;
ssl_certificate /etc/letsencrypt/live/code.coding-play.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/code.coding-play.site/privkey.pem;
# SSL 설정 추가 (optional, 추천)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384';
# ssl_prefer_server_ciphers off;
# ssl_session_timeout 1d;
# ssl_session_cache shared:SSL:50m;
location / {
proxy_pass http://127.0.0.1:2229;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80 ;
server_name code.coding-play.site;
location /.well-known/acme-challenge {
alias /opt/homebrew/etc/nginx/.well-known/acme-challenge; # 실제 파일이 위치한 경로를 지정합니다.
try_files $uri $uri/ /opt/homebrew/etc/nginx/.well-known/acme-challenge/XGNhDLRm4LMqNgFd3QC3RdI4mGM1ZedPYZiSt0nTCUY; # 특정 파일명을 여기에 지정합니다.
}
location / { # HTTP to HTTPS 리디렉션
return 301 https://$host$request_uri;
}
}
include servers/*;
}
# nginx -t
# brew services restart nginx
# sudo chmod -R 755 /etc/letsencrypt
예) 최종 nginx.conf (ghost cms)
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# ghost cms - coding-play
server {
listen 80 ;
server_name wp.coding-play.site;
location /.well-known/acme-challenge {
alias /opt/homebrew/etc/nginx/.well-known/acme-challenge; # 실제 파일이 위치한 경로를 지정합니다.
try_files $uri $uri/ /opt/homebrew/etc/nginx/.well-known/acme-challenge/GA8XfAQnDC7jp1kjtxMmzhUJ5RVeYWG0MbwfdnH1JXQ; # 특정 파일명을 여기에 지정합니다.
}
location / { # HTTP to HTTPS 리디렉션
return 301 https://$host$request_uri;
# proxy_pass http://127.0.0.1:8080;
}
# location ~ /.well-known {
# allow all;
# }
}
server {
listen 443 ssl;
server_name wp.coding-play.site;
ssl_certificate /etc/letsencrypt/live/wp.coding-play.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wp.coding-play.site/privkey.pem;
# SSL 설정 (최신 보안 권장)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
# SSL 세션 캐싱 설정
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
location / {
# proxy_set_header Host "wp.coding-play.site";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header Host $http_host;
# proxy_set_header X-NginX-Proxy true;
# proxy_redirect off;
proxy_pass http://127.0.0.1:3030/;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header Host $http_host;
}
}
include servers/*;
}
# nginx -t
# brew services restart nginx
# sudo chmod -R 755 /etc/letsencrypt
요약
1.도메인 설정
- 도메인을 구매한다. eg) example.com
- DNS 래코드 설정으로 내 아이피와 연결한다. eg) www.example.com -> 123.123.123.123
2.nginx 80 port 설정
- 맥미니의 80포트 접속 = nginx로 셋업
- 마치 GW 같은 역학을 nginx가 해주는 것이다.
- 그리고 각 도메인 별로 분기처리 하여, 뒷단의 서비스 포트로 연결한다.
server {
listen 80 ; # nginx는 80포트 open
server_name www.example.com; # 특정 서브 도메인에 해당하는 경우만 처리한다.
location / { # HTTP to HTTPS 리디렉션
return 301 https://$host$request_uri;
}
}
3.cerbot 실행
sudo certbot certonly --manual
으로 인증서발급 진행- cerbot에서 임의의 경로에 요청을 보낼테니, 특정 파일을 읽을 수 있도록 셋팅하라 한다.
- 그 설정을
location /
앞단에 한다.
server {
listen 80 ; # nginx는 80포트 opn
server_name www.example.com; # 그 중 특정 도메인에 해당하는 경우만 처리한다.
location /.well-known/acme-challenge {
alias /opt/homebrew/etc/nginx/.well-known/acme-challenge; # 실제 파일이 위치한 경로를 지정합니다.
try_files $uri $uri/ /opt/homebrew/etc/nginx/.well-known/acme-challenge/EaICkPAIxkrb_MYWJPqLihzZCc228BkrgxXPvi9qUTA; # 특정 파일명을 여기에 지정합니다.
}
location / { # HTTP to HTTPS 리디렉션
return 301 https://$host$request_uri;
}
}
4.nginx 443 port 설정
- 인증이 성공되면, 특정 경로에 인증서를 만들어주게 된다.
- 이는 fullchain.pem, privkey.pem 2개가 나온다.
- 해당 디렉터리는 nginx가 읽을권한이 없으므로
sudo chmod -R 755 /etc/letsencrypt
명령어로 권한 부여 - 다음처럼 설정을 추가한다. (아래 예제는 localhost 3030포트로 진입한다.)
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
# SSL 설정 (최신 보안 권장)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
# SSL 세션 캐싱 설정
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:3030/;
}
}
NOTE) brew / nginx / certbot 명령어 정리
[brew]
brew search nginx # 패키지 검색
brew install nginx # 패키지 설치
brew services start nginx # 서비스 시작
brew services restart nginx
( brew services [run|start|stop|restart|cleanup] service_name )
brew services # 서비스 확인
Name Status User File
nginx started dosimpact ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
---
[nginx]
# 설정파일 변경 후 문법 체크하기
nginx -t
# nginx.conf 파일 경로 확인
brew info nginx
...
The default port has been set in /opt/homebrew/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.
...
# nginx root 폴더 확인
>nginx -V
nginx version: nginx/1.25.1 ...
configure arguments: --prefix=/opt/homebrew/Cellar/nginx/1.25.1_1 ...
여기서 : --prefix=/opt/homebrew/Cellar/nginx/1.25.1_1 에 루트 디렉터리가 된다.
하지만 해당 디렉터리의 html 폴더는 링크가 걸려 있다.
최종적으로 /opt/homebrew/var/www 라는 곳에 index.html 이 있다.
# 환경 설정 변경 후 리로드 명령어
nginx -s reload
---
[certbot]
# 인증서 발급
sudo certbot certonly --manual
sudo certbot --nginx -d yourdomain.com
sudo certbot --nginx --nginx-server-root /opt/homebrew/etc/nginx -d yourdomain.com
# 인증서 정보 , 유효기간, 경로 확인
sudo certbot certificates
sudo certbot certificates -d www.domain.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
Certificate Name: MY_DOMAIN
Serial Number: 3841dcd9246507891a8afc5cde8df0e0af1
Key Type: ECDSA
Domains: MY_DOMAIN
Expiry Date: 2023-11-08 12:19:45+00:00 (VALID: 89 days)
Certificate Path: /etc/letsencrypt/live/MY_DOMAIN/fullchain.pem
Private Key Path: /etc/letsencrypt/live/MY_DOMAIN/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 인증서 갱신 dry-run
sudo certbot renew --dry-run
sudo certbot renew --dry-run -d www.domain.com
# 인증서 갱신
( 발급시 90일 연장, 30일 남았을때 연장 가능 )
sudo certbot renew
## tip, nginx 설정, nginx 설정파일 경로 지정
sudo certbot --nginx --nginx-server-root /opt/homebrew/etc/nginx renew
# 인증서 삭제
sudo certbot delete --cert-name yourdomain.com
ref
DNS 레코드 종류.
DNS 레코드 종류 쉽게 이해.
ssh 접속 to mac mini
nginx + code-server 구축.
code-server 자체에 https 적용