무료 웹호스팅에 가입하면 도메인을 안 사도 주소를 하나 줍니다. myname.hosting.co.kr 같은 형태죠. 호스팅사가 가진 도메인 밑에 계정 아이디를 서브도메인으로 붙여준 겁니다. 여기에 워드프레스를 올리고 브라우저로 열어보면, 주소창 왼쪽에 자물쇠 대신 “주의 요함” 또는 “안전하지 않음”이 뜹니다. 이게 신경 쓰여서 검색으로 들어오는 분이 많습니다.
문제는 무료 호스팅마다 사정이 제각각이라는 점입니다. 버튼 하나로 끝나는 곳이 있고, SSL 메뉴 자체가 없는 곳이 있고, SSH를 열어주는 곳이 있습니다. 그래서 “이렇게 하면 됩니다” 한 줄로 끝나지 않습니다. 내 환경이 어느 쪽인지 먼저 가른 다음, 거기에 맞는 경로를 타야 합니다. 아래는 그 갈림길을 순서대로 정리한 기록입니다.
한눈에 · 내 호스팅 유형 확인(패널/SSH/DNS 제어권) → 패널 AutoSSL 또는 Cloudflare 또는 certbot 중 하나로 인증서 발급 → 혼합 콘텐츠 정리 → http→https 리다이렉트 → curl로 최종 확인
무료 서브도메인에도 HTTPS가 필요한 이유
HTTPS는 브라우저와 서버 사이 통신을 암호화하는 방식입니다. 자물쇠 아이콘은 그 암호화가 정상적으로 걸렸다는 표시고요. 이게 없으면 중간에 있는 누구든(카페 와이파이 관리자, 통신 경로상의 장비) 오가는 내용을 그대로 볼 수 있습니다.
무료 호스팅 서브도메인은 내 도메인과 뭐가 다른가
기술적으로는 똑같은 도메인 이름입니다. 다만 소유권이 내게 없습니다. hosting.co.kr은 호스팅사 것이고, 나는 그 밑의 한 칸을 빌려 쓰는 겁니다. 이 차이가 나중에 결정적으로 작용합니다. DNS 레코드를 내가 직접 만질 수 없으면 Cloudflare 같은 앞단 프록시 방식은 아예 선택지에서 빠집니다.
또 하나, 상위 도메인이 공용이다 보니 Let’s Encrypt의 발급 한도(같은 등록 도메인 기준 주간 제한)를 호스팅사 전체가 공유하게 됩니다. 그래서 무료 인증서 발급을 막아둔 곳도 있습니다.
HTTPS가 없으면 실제로 막히는 기능들
경고 문구만 문제가 아닙니다. 로그인 폼이 있는 사이트라면 아이디와 비밀번호가 평문으로 날아갑니다. 워드프레스 wp-admin 로그인이 대표적입니다. 크롬은 http 페이지의 비밀번호 입력란에 아예 경고를 띄웁니다.
브라우저 API 중에도 HTTPS를 요구하는 게 늘었습니다.
| 기능 | http에서 |
|---|---|
| 서비스 워커 (PWA, 오프라인 캐시) | 등록 자체가 거부됨 |
| 위치 정보 (Geolocation) | 호출 시 즉시 실패 |
| 카메라·마이크 (getUserMedia) | 사용 불가 |
| 클립보드 API | 대부분 차단 |
| HTTP/2, HTTP/3 | 사실상 사용 불가 |
검색 노출 쪽은 과장할 필요 없습니다. HTTPS가 순위에 미치는 영향은 작다고 알려져 있습니다. 다만 https 사이트에서 http 사이트로 이동할 때 리퍼러(어디서 왔는지 정보)가 잘리는 건 실제로 벌어지는 일입니다. 유입 분석이 비는 이유가 이것일 수 있습니다.
시작 전 확인, 내 호스팅 유형
필요성을 봤으면 다음은 방법 고르기인데, 그 전에 내 환경부터 확인해야 합니다. 여기서 잘못 고르면 한 시간을 헛수고합니다. 크게 네 가지로 갈립니다.
| 유형 | 상황 | 권장 경로 |
|---|---|---|
| A | cPanel/DirectAdmin에 SSL 메뉴 있음 | 패널 AutoSSL (5분) |
| B | 패널은 있는데 SSL이 없거나 유료 | 내 도메인 있으면 Cloudflare, 없으면 사실상 방법 없음 |
| C | SSH 접속 가능, 웹서버 설정 수정 가능 | certbot으로 직접 발급 |
| D | DNS도 못 만지고 SSH도 없음 | 호스팅사에 문의하거나 이전 검토 |
관리 패널에서 SSL 메뉴 찾는 위치
cPanel이면 홈 화면에서 Security 그룹 안의 SSL/TLS, 그리고 별도로 SSL/TLS Status가 있습니다. DirectAdmin이면 Account Manager 또는 SSL Certificates 항목입니다. 검색창이 있는 패널이면 “SSL”만 쳐보면 바로 나옵니다. 아무것도 안 나오면 유형 B입니다.
DNS 제어권 확인법
내가 준 주소가 CNAME인지 A레코드인지, 그리고 그 레코드를 내가 편집할 수 있는지 봅니다.
nslookup myname.hosting.co.kr
# 또는
dig +short myname.hosting.co.kr
A레코드로 IP가 바로 나오든 CNAME이 나오든, 중요한 건 그 레코드를 바꿀 수 있는 관리 화면이 나한테 있느냐입니다. 호스팅사가 준 서브도메인은 대개 없습니다.
그리고 443 포트가 열려 있는지 미리 찔러봅니다.
curl -I https://myname.hosting.co.kr
여기서 나오는 반응을 구분할 줄 알아야 합니다.
curl: (7) Failed to connect to ... port 443: Connection refused→ 443 자체가 안 열려 있음. 서버 설정 문제curl: (60) SSL certificate problem: self signed certificate→ 포트는 열렸고 인증서만 잘못됨. 이건 오히려 반가운 신호HTTP/2 200→ 이미 정상 인증서가 붙어 있음
Connection refused와 인증서 오류는 완전히 다른 얘기입니다. 앞쪽은 서버가 https를 아예 안 받는 상태고, 뒤쪽은 받긴 받는데 인증서만 갈아 끼우면 되는 상태입니다.

가장 쉬운 길, 패널의 무료 SSL
유형 A로 판정됐다면 여기서 끝납니다. 뒤 섹션들은 안 읽어도 됩니다(혼합 콘텐츠 부분만 빼고요).
AutoSSL 실행과 결과 읽기
cPanel 기준으로 SSL/TLS Status에 들어가면 도메인 목록이 나옵니다. 인증서가 없는 도메인 옆에 빨간 자물쇠가 표시됩니다. 대상 도메인을 체크하고 Run AutoSSL을 누릅니다.
여기서 조급해하지 않는 게 중요합니다. 발급은 보통 몇 분이면 끝나지만 상황에 따라 몇 시간까지 걸리고, 그동안 사이트는 http로 멀쩡히 뜹니다. 페이지를 새로고침하면서 기다리지 말고 다른 일을 하다 오는 게 낫습니다.
발급이 끝났으면 브라우저에서 자물쇠를 클릭해 발급자와 만료일을 봅니다. 터미널에서 확인하려면 이렇게 합니다.
curl -vI https://myname.hosting.co.kr 2>&1 | grep -i 'issuer\|expire'
출력은 대략 이런 형태입니다.
* expire date: Mar 15 08:22:41 2026 GMT
* issuer: C=US; O=Let's Encrypt; CN=R11
issuer에 Let’s Encrypt나 Sectigo 같은 이름이 보이고 expire date가 미래면 정상입니다.
발급 실패 시 로그 위치
AutoSSL이 실패로 뜨는 이유는 대체로 두 가지입니다. 하나는 서브도메인 DNS가 아직 전파되지 않아서 검증 서버가 도메인을 못 찾는 경우. 도메인을 만든 직후라면 30분쯤 두고 다시 시도합니다.
다른 하나는 .well-known/acme-challenge/ 경로가 차단된 경우입니다. 보안 플러그인이나 .htaccess에서 점(.)으로 시작하는 디렉터리 접근을 막아뒀으면 검증이 실패합니다. .htaccess 맨 위에 예외를 넣습니다.
RewriteEngine On
RewriteRule ^\.well-known/acme-challenge/ - [L]
cPanel이면 SSL/TLS Status 화면에서 도메인 옆 정보 아이콘을 누르면 실패 사유가 영어로 나옵니다. DCV 또는 Domain Control Validation 관련 문구가 보이면 위 경로 문제가 맞습니다.
자동 갱신은 대부분 켜져 있지만 확인해 두는 게 좋습니다. 만료 두 달쯤 뒤로 캘린더에 알림 하나 걸어두면 마음이 편합니다. 무료 호스팅은 갱신이 조용히 실패해도 아무도 알려주지 않습니다.
패널에 SSL이 없을 때, Cloudflare 앞단
패널에 SSL 버튼이 없다면 다음 선택지는 앞단에 프록시를 두는 방식입니다. Cloudflare가 방문자와 내 서버 사이에 끼어들어, 방문자↔Cloudflare 구간만 HTTPS로 감싸줍니다. Cloudflare↔내 서버 구간은 별개입니다.
먼저 솔직하게 짚고 가야 할 제약이 있습니다. 이 방법은 도메인의 네임서버를 Cloudflare 것으로 바꿀 수 있을 때만 가능합니다. 호스팅사가 준 myname.hosting.co.kr은 네임서버가 호스팅사 것이니 불가능합니다. 즉 실질적으로는 “내 도메인을 따로 사서 무료 호스팅에 연결한 경우”에만 쓸 수 있습니다.
Flexible / Full / Full(strict) 비교
Cloudflare 대시보드의 SSL/TLS 메뉴에서 고르는 모드입니다. 이름만 봐서는 차이가 안 보이는데, 실제 동작이 꽤 다릅니다.
| 모드 | 방문자↔CF | CF↔내 서버 | 서버에 인증서 | 권장 여부 |
|---|---|---|---|---|
| Off | http | http | 불필요 | 안 씀 |
| Flexible | https | http (평문) | 불필요 | 임시방편 |
| Full | https | https | 자체 서명도 허용 | 차선 |
| Full (strict) | https | https | 유효한 인증서 필요 | 권장 |
Flexible이 왜 반쪽짜리냐면, Cloudflare에서 내 서버까지 가는 구간이 여전히 평문이기 때문입니다. 방문자 눈에는 자물쇠가 보이지만 실제로 비밀번호는 중간 구간에서 평문으로 흐릅니다. 로그인 기능이 있는 사이트라면 쓰지 않는 게 맞습니다.
Full(strict)를 쓰려면 서버에 유효한 인증서가 필요한데, Cloudflare가 무료로 주는 Origin Certificate를 쓰면 됩니다. 대시보드 SSL/TLS → Origin Server에서 발급받아 서버에 설치하면 됩니다. 이 인증서는 Cloudflare만 신뢰하면 되므로 브라우저 신뢰 여부는 상관없습니다.
무한 리다이렉트가 생기는 조합
Flexible 모드에서 가장 흔한 사고가 ERR_TOO_MANY_REDIRECTS입니다. 원인은 단순합니다.
- 방문자가 https로 접속 → Cloudflare가 내 서버에 http로 요청
- 내 서버의
.htaccess가 “http로 왔네? https로 보내야지” 하고 301 응답 - Cloudflare가 다시 https로 접근 → 다시 http로 서버에 전달
- 무한 반복
해결은 두 가지 중 하나입니다. 모드를 Full 이상으로 올리거나, 서버 쪽 리다이렉트 규칙에서 %{HTTPS} 대신 %{HTTP:X-Forwarded-Proto}를 보게 고치는 겁니다(뒤에서 규칙을 보여드립니다).
부가 설정으로 SSL/TLS → Edge Certificates에 Always Use HTTPS와 Automatic HTTPS Rewrites가 있습니다. 앞의 것은 http 접속을 Cloudflare 단에서 https로 넘겨주고, 뒤의 것은 페이지 안의 http:// 링크를 가능한 범위에서 자동으로 바꿔줍니다. 임시로 혼합 콘텐츠를 가리는 데 도움이 되지만 근본 해결은 아닙니다.
SSH가 되는 서버라면 Let’s Encrypt 직접 발급
패널도 없고 프록시도 못 쓰는데 SSH는 열려 있다. 그러면 인증서를 직접 받는 방법이 남습니다. 단, 미리 못 박아둘 게 있습니다. root 권한이 없는 일반 공유 호스팅에서는 이 방법 자체가 불가능합니다. /etc/letsencrypt에 쓸 수 없고 웹서버 설정도 못 건드리기 때문입니다. VPS나 root를 주는 무료 서버여야 합니다.
webroot 방식과 standalone 방식
certbot이 “이 도메인이 정말 네 것이냐”를 확인하는 방식이 두 가지입니다.
| 방식 | 동작 | 웹서버 중단 | 언제 쓰나 |
|---|---|---|---|
--webroot | 웹 문서 루트에 검증 파일을 놓고 확인 | 불필요 | 이미 사이트가 돌고 있을 때 |
--standalone | certbot이 직접 80포트를 열어 확인 | 필요 | 아직 웹서버가 없거나 껐다 켜도 될 때 |
운영 중인 사이트면 거의 항상 webroot입니다. standalone은 80포트를 certbot이 점유해야 해서 아파치/nginx를 잠깐 내려야 합니다.
설치부터 봅니다. 데비안/우분투 계열은 이렇습니다.
sudo apt update
sudo apt install certbot
로키/알마/CentOS 계열은 이렇습니다.
sudo dnf install epel-release
sudo dnf install certbot
root가 없는데 웹루트에는 쓸 수 있는 애매한 환경이면 acme.sh가 대안입니다. 셸 스크립트 하나로 동작해서 홈 디렉터리에 설치할 수 있습니다.
curl https://get.acme.sh | sh -s email=you@example.com
이제 발급입니다. 웹루트 경로는 자기 환경에 맞게 바꿉니다.
sudo certbot certonly --webroot -w /home/계정/public_html -d 내주소

이 사전 확인을 꼭 하세요. certbot을 돌리기 전에 http://내주소/.well-known/acme-challenge/ 경로가 외부에서 200으로 열리는지 봐야 합니다. hello가 안 나오고 404나 403이 나오면 certbot도 똑같이 실패합니다.
실패 시 나오는 메시지는 대개 이렇습니다.
Challenge failed for domain 내주소
Type: unauthorized
Detail: Invalid response from http://내주소/.well-known/acme-challenge/xxxx: 404
원인은 -w로 준 경로가 실제 문서 루트가 아니거나, .htaccess가 점으로 시작하는 경로를 막고 있거나, 워드프레스 리라이트 규칙이 모든 요청을 index.php로 넘기는 경우입니다. 앞에서 본 RewriteRule ^\.well-known/acme-challenge/ - [L] 예외를 규칙 맨 위에 넣습니다.
인증서 파일 4개의 차이
발급이 성공하면 /etc/letsencrypt/live/내주소/ 아래에 파일이 생깁니다. 이름이 비슷해서 헷갈리는데, 실제로 쓰는 건 두 개뿐입니다.
| 파일 | 내용 | 웹서버 설정에 쓰나 |
|---|---|---|
cert.pem | 내 도메인 인증서만 | 잘 안 씀 |
chain.pem | 중간 인증서만 | 아파치 구버전에서 별도 지정 |
fullchain.pem | cert + chain 합본 | 거의 항상 이걸 씀 |
privkey.pem | 개인 키 | 필수. 절대 외부 노출 금지 |
fullchain.pem 대신 cert.pem을 넣으면 브라우저에서는 잘 뜨는데 모바일 앱이나 일부 클라이언트에서 체인 오류가 납니다. 중간 인증서가 빠졌기 때문입니다. 이걸 incomplete chain이라고 합니다.
nginx 최소 설정은 이렇습니다.
server {
listen 443 ssl;
server_name 내주소;
ssl_certificate /etc/letsencrypt/live/내주소/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/내주소/privkey.pem;
root /home/계정/public_html;
index index.php index.html;
}
아파치라면 이렇습니다.
<VirtualHost *:443>
ServerName 내주소
DocumentRoot /home/계정/public_html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/내주소/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/내주소/privkey.pem
</VirtualHost>
설정을 고쳤으면 문법부터 검사합니다. nginx는 sudo nginx -t, 아파치는 sudo apachectl configtest입니다. syntax is ok가 나온 뒤에 재시작하세요. 검사 없이 재시작했다가 웹서버가 안 올라오면 사이트가 통째로 죽습니다. 서비스 제어가 헷갈리면 systemctl 서비스 시작·종료·부팅 자동실행 정리를 참고하세요.
갱신 자동화 확인
Let’s Encrypt 인증서는 90일짜리입니다. 갱신을 자동화하지 않으면 석 달 뒤에 사이트가 경고 화면으로 바뀝니다. 먼저 예행 연습부터 합니다.
sudo certbot renew --dry-run
이건 실제로 갱신하지 않고 과정만 흉내 냅니다. Congratulations, all simulated renewals succeeded가 나오면 됩니다. 실패하면 그 자리에서 원인이 찍히니 만료 직전에 당황할 일이 없습니다.
certbot을 패키지로 설치했으면 systemd 타이머가 자동 등록됩니다. 확인은 이렇게 합니다.
systemctl list-timers | grep certbot
타이머가 없으면 cron에 직접 넣습니다.
0 3 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
--post-hook은 갱신이 실제로 일어났을 때만 웹서버를 리로드합니다. 갱신했는데 리로드를 안 하면 옛 인증서를 계속 물고 있으니 빼먹으면 안 됩니다. cron이 등록됐는데도 안 도는 경우가 흔한데, 그 이유는 crontab 작성법 정리, 등록해도 안 돌아가는 이유까지에 정리해 뒀습니다.
자물쇠가 안 뜰 때, 혼합 콘텐츠 잡기
인증서까지 붙였는데 자물쇠가 회색이거나 느낌표가 붙는다. 여기까지 왔다면 십중팔구 혼합 콘텐츠(mixed content) 문제입니다. 페이지 자체는 https로 왔는데, 그 안의 이미지·CSS·JS 중 일부를 http 주소로 불러오는 상태입니다.
브라우저 개발자도구(F12) 콘솔을 열면 이런 메시지가 그대로 찍힙니다.
Mixed Content: The page at 'https://myname.hosting.co.kr/' was loaded over HTTPS,
but requested an insecure resource 'http://myname.hosting.co.kr/wp-content/uploads/2026/01/photo.jpg'.
This content should also be served over HTTPS.
콘솔에서 범인 파일 찾기
메시지 끝에 적힌 URL이 곧 범인입니다. 저 주소를 보면 어디를 고쳐야 하는지 바로 나옵니다. wp-content/uploads 아래면 DB에 저장된 이미지 주소 문제고, wp-content/themes 아래면 테마 파일에 하드코딩된 겁니다.
이미지나 CSS는 브라우저가 경고만 하고 로드는 해줍니다. 반면 스크립트(<script src="http://...">)는 아예 차단합니다. 그래서 “레이아웃이 갑자기 깨졌다”, “슬라이더가 안 움직인다” 같은 증상이 https 전환 직후에 나타납니다.
정적 사이트라면 소스에서 직접 찾습니다.
grep -rn "http://" ./ --include="*.html" --include="*.css" --include="*.js"
외부 사이트 링크(<a href>)까지 다 걸리니 src= 나 href= 중 리소스를 부르는 것만 골라 보세요. grep 옵션을 더 세밀하게 쓰고 싶으면 grep으로 로그에서 원하는 줄만 뽑기, 실전 옵션 정리가 도움이 됩니다.
워드프레스 URL 일괄 변경 순서
워드프레스는 순서를 지켜야 합니다. 순서가 틀리면 관리자에서 튕겨 나옵니다.
시작하기 전에 반드시 백업부터 뜨세요. DB를 건드리는 작업이라 되돌릴 수단이 없으면 곤란해집니다. 워드프레스 백업, 파일과 DB 둘 다 챙기는 실전 순서를 먼저 보고 오시는 걸 권합니다.
1단계. 관리자 → 설정 → 일반에서 워드프레스 주소(URL)와 사이트 주소(URL) 두 곳을 https로 바꿉니다. 저장하면 자동 로그아웃되고 https 주소로 다시 로그인하게 됩니다.
2단계. DB 안에 남은 http://내주소 문자열을 바꿉니다. 여기가 함정 구간입니다. phpMyAdmin에서 SQL로 REPLACE()를 돌리거나 덤프 파일에 sed를 쓰면 안 됩니다. 워드프레스는 위젯 설정이나 플러그인 옵션을 직렬화(serialize)된 문자열로 저장하는데, 그 안에 문자열 길이가 숫자로 박혀 있습니다. http://(7자)를 https://(8자)로 바꾸면 길이 값이 안 맞아서 해당 옵션이 통째로 깨집니다.
그래서 직렬화를 이해하는 도구를 써야 합니다. WP-CLI가 있으면 이렇게 합니다.
wp search-replace 'http://내주소' 'https://내주소' --dry-run
--dry-run은 실제로 바꾸지 않고 “몇 개 테이블에서 몇 건이 바뀔 예정”만 보여줍니다. 숫자를 확인한 뒤 --dry-run을 빼고 다시 실행합니다. WP-CLI가 없으면 Better Search Replace 플러그인이 같은 일을 합니다. 이쪽도 “테스트 실행” 체크박스가 있습니다.
3단계. wp-config.php에 관리자 강제 HTTPS를 넣습니다.
define('FORCE_SSL_ADMIN', true);
Cloudflare나 로드밸런서 뒤에 있으면 워드프레스가 자기가 http로 서비스되는 줄 착각합니다. 그럴 땐 위 줄보다 먼저 이 코드를 넣습니다.
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
이 블록은 require_once ABSPATH . 'wp-settings.php'; 줄보다 위에 있어야 합니다. wp-config.php에 넣어두면 좋은 다른 설정들은 wp-config.php 필수 설정 12가지, 보안과 성능 한 번에 점검하기에 모아뒀습니다.
http 접속을 https로 넘기기
혼합 콘텐츠까지 정리했으면 남은 건 하나입니다. 아직도 http로 들어오는 방문자와 검색엔진 크롤러를 https로 넘기는 일입니다.
작업 전에 .htaccess를 복사해 두세요. 이 파일 하나 잘못 건드리면 사이트 전체가 500 에러나 리다이렉트 루프에 빠집니다. 되돌릴 백업이 없으면 FTP로 접속해 파일을 지울 때까지 사이트가 안 열립니다.
cp .htaccess .htaccess.bak
아파치라면 .htaccess 파일 맨 위, 워드프레스가 자동 생성한 # BEGIN WordPress 블록보다 위쪽에 넣습니다. 아래에 넣으면 워드프레스 규칙이 먼저 걸려서 리다이렉트가 동작하지 않습니다.
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Cloudflare나 다른 프록시 뒤에 있으면 위 규칙이 무한 루프를 만듭니다. 프록시가 서버에 http로 전달하니 %{HTTPS}는 영원히 off이기 때문입니다. 이럴 땐 조건을 바꿉니다.
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
nginx는 80 포트 서버 블록에서 한 줄이면 됩니다.
server {
listen 80;
server_name 내주소;
return 301 https://$host$request_uri;
}
curl로 리다이렉트 확인
규칙을 넣었으면 브라우저 말고 curl로 확인하세요. 브라우저는 캐시 때문에 옛 결과를 보여줄 수 있습니다.
curl -I http://내주소
기대하는 출력입니다.
HTTP/1.1 301 Moved Permanently
Location: https://내주소/
301과 Location 헤더의 https가 둘 다 보이면 성공입니다. ERR_TOO_MANY_REDIRECTS가 브라우저에 뜨거나 curl에서 같은 301이 반복되면 앞에서 말한 프록시 조합 문제입니다. .htaccess.bak으로 즉시 되돌리고 X-Forwarded-Proto 버전으로 바꾸세요.
HSTS는 나중에
HSTS(HTTP Strict Transport Security)는 “이 도메인은 앞으로 무조건 https로만 접속해라”를 브라우저에 각인시키는 헤더입니다. 보안상 권장되는 설정이지만, 무료 호스팅에서는 서두르면 위험합니다.
한번 max-age=31536000으로 심어두면 브라우저가 1년 동안 그 도메인에 http 접속을 아예 시도하지 않습니다. 그런데 인증서 갱신이 실패해 https가 깨지면 어떻게 될까요. 사용자는 http로도 못 들어오고, 경고 화면에서 “무시하고 진행” 버튼조차 안 보입니다. 사이트가 완전히 잠깁니다.
그래서 순서는 이렇습니다. 자동 갱신이 최소 한 사이클(90일 인증서라면 두 달쯤 뒤 갱신) 정상 동작하는 걸 확인한 다음, max-age=300 같은 짧은 값으로 시작해 서서히 늘립니다. preload 목록 등록은 그보다 훨씬 뒤 얘기입니다.
자주 묻는 질문
앞에서 다룬 상황 중 반복해서 받는 질문만 모았습니다.
무료 호스팅이 준 서브도메인에도 Let’s Encrypt가 발급되나요
원리상으로는 가능합니다. Let’s Encrypt는 도메인 소유권이 아니라 제어권을 봅니다. http://myname.hosting.co.kr/.well-known/acme-challenge/ 경로에 파일을 놓을 수 있으면 HTTP-01 검증을 통과합니다. 다만 호스팅사가 이 경로를 막아두거나, 상위 도메인의 주간 발급 한도를 관리하느라 제한을 거는 경우가 있습니다. 실제로 되는지는 앞에서 소개한 .well-known 테스트 파일로 5분이면 확인됩니다.
Cloudflare Flexible 모드만 켜도 되나요
방문자 눈에는 자물쇠가 보입니다. 하지만 Cloudflare에서 내 서버로 가는 구간은 여전히 평문입니다. 로그인 폼이 있는 사이트에는 권장하지 않습니다. 정적인 홍보 페이지 정도면 임시로 쓸 수 있지만, 앞서 본 무한 리다이렉트 문제도 이 모드에서 가장 자주 납니다. 서버에 Origin Certificate를 깔고 Full(strict)로 가는 게 몇 분 더 들이고 제대로 하는 길입니다.
인증서가 만료되면 사이트가 아예 안 열리나요
완전히 차단되지는 않습니다. NET::ERR_CERT_DATE_INVALID 경고 화면이 뜨고, 사용자가 “고급” → “안전하지 않음(계속)”을 눌러야 들어옵니다. 문제는 그 버튼을 누르는 방문자가 거의 없다는 점입니다. 사실상 접속 차단과 같습니다. 앞서 말한 대로 HSTS까지 켜져 있으면 그 버튼조차 사라집니다.
자물쇠는 떴는데 특정 페이지만 경고가 뜹니다
그 페이지에만 http 리소스가 남은 겁니다. 대개 예전에 작성한 글에 이미지 주소를 직접 붙여넣었거나, 외부 사이트 이미지를 http로 링크한 경우입니다. 해당 페이지에서 F12 콘솔을 열면 어떤 URL이 문제인지 그대로 찍힙니다. 외부 이미지라면 그 사이트가 https를 지원하는지 확인하고, 안 되면 파일을 내 서버로 옮겨오는 게 확실합니다.
주소를 https로 바꿨더니 관리자 로그인이 안 됩니다
설정 화면에서 주소를 바꿨는데 서버에 인증서가 제대로 안 붙어 있으면 이 상황이 됩니다. wp-config.php에 상수를 임시로 박으면 DB 값과 상관없이 그 주소가 우선합니다.
define('WP_HOME', 'http://내주소');
define('WP_SITEURL', 'http://내주소');
이걸로 일단 http 관리자에 들어가 원인을 고친 뒤, 인증서가 정상이 되면 값을 https로 바꾸거나 두 줄을 지우면 됩니다. FTP나 SSH로 파일을 편집해야 하는데, 서버에서 파일 편집이 익숙하지 않으면 vi 편집기, 딱 이 10개 명령만 알면 서버에서 안 막힙니다를 참고하세요.
무료 SSL과 유료 SSL은 암호화 강도가 다른가요
암호화 자체는 같습니다. 같은 TLS 프로토콜과 같은 암호화 스위트를 씁니다. 차이는 검증 수준과 보증입니다. 무료 인증서는 도메인 소유만 확인하는 DV(Domain Validation)이고, 유료 중에는 기업 실체를 확인하는 OV/EV가 있습니다. 개인 블로그나 소규모 사이트에서 브라우저에 보이는 차이는 사실상 없습니다.
적용 후 점검 체크리스트
다 됐다고 생각될 때 아래를 순서대로 확인하면 빠뜨린 게 걸립니다.
- [ ] 브라우저에서 자물쇠가 회색 실선으로 뜨는지, 느낌표나 사선이 없는지
- [ ] F12 콘솔에
Mixed Content경고가 한 줄도 없는지 (메인, 글 상세, 로그인 페이지 각각) - [ ]
curl -I http://내주소가301과 httpsLocation헤더를 반환하는지 - [ ]
curl -vI https://내주소 2>&1 | grep -i 'issuer\|expire'로 발급자와 만료일 확인 - [ ] 만료일 30일 전으로 캘린더 알림 등록 (자동 갱신이 있어도 보험으로)
- [ ]
sudo certbot renew --dry-run이 성공하는지 (직접 발급한 경우) - [ ] SSL Labs 같은 외부 진단으로 체인 누락(incomplete chain)이 없는지 확인
- [ ] 워드프레스라면 설정→일반의 두 주소, 그리고 업로드 이미지 URL까지 세 곳 재확인
- [ ] sitemap.xml 안의 주소와 서치 콘솔 등록 속성을 https로 갱신
- [ ] 갱신 실패를 알아챌 수단 하나 마련 (외부 모니터링 서비스나 cron 실패 메일)
마지막 항목이 의외로 중요합니다. 인증서는 조용히 만료됩니다. 어느 날 접속자 수가 뚝 떨어져서 들어가 보니 경고 화면이 떠 있는 상황을 겪지 않으려면, 알림 하나는 걸어두는 게 좋습니다.
