메인 화면 하나가 woff 폰트만 3MB 넘게 끌어오는데 압축도 캐시 헤더도 없었다. 유선망에서는 티가 안 나지만(같은 폰트 0.15초) 테더링에서는 25초가 걸려 브라우저가 로딩을 끝내지 못하고 "접속 안 됨"처럼 보인다. - mod_deflate: HTML 52,665B → 9,516B (82% 감소) - 폰트 1년 immutable, 이미지 7일, css/js 1시간 캐시 — 재방문 시 3MB 재다운로드 제거 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
83 lines
4.0 KiB
Plaintext
83 lines
4.0 KiB
Plaintext
# csv.wise.ai.kr — arko(문화품앗이) 웹 티어
|
|
# 설치 위치: /etc/httpd/conf.d/csv.wise.ai.kr.conf (이 서버는 Apache httpd 를 쓴다)
|
|
#
|
|
# 경로: 브라우저 → httpd 443 → [SSH 터널] 127.0.0.1:11060 → WAS(27.255.76.2) Tomcat
|
|
# DB(MariaDB)는 WAS 안에서만 접근한다. 이 서버는 DB 에 붙지 않는다.
|
|
#
|
|
# 127.0.0.1:11060 은 arko-was-tunnel.service 가 만들어 준다.
|
|
# 502 가 나면 `systemctl status arko-was-tunnel` 부터 확인할 것.
|
|
|
|
<VirtualHost *:80>
|
|
ServerName csv.wise.ai.kr
|
|
|
|
# 인증서 갱신(webroot)은 리다이렉트보다 먼저 처리되어야 한다
|
|
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
|
|
<Directory "/var/www/html/.well-known/acme-challenge">
|
|
Require all granted
|
|
Options None
|
|
</Directory>
|
|
|
|
RewriteEngine On
|
|
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
|
|
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:443>
|
|
ServerName csv.wise.ai.kr
|
|
|
|
SSLEngine on
|
|
SSLCertificateFile /etc/letsencrypt/live/csv.wise.ai.kr/fullchain.pem
|
|
SSLCertificateKeyFile /etc/letsencrypt/live/csv.wise.ai.kr/privkey.pem
|
|
SSLProtocol -all +TLSv1.2 +TLSv1.3
|
|
SSLCipherSuite HIGH:!aNULL:!MD5
|
|
|
|
# 자원봉사 활동사진·첨부파일 업로드가 있어 기본값으로는 부족하다
|
|
LimitRequestBody 104857600
|
|
|
|
Header always set X-Frame-Options "SAMEORIGIN"
|
|
Header always set X-Content-Type-Options "nosniff"
|
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
# 운영(csv.culture.go.kr)이 따로 있는 검증 환경이므로 색인을 막는다
|
|
Header always set X-Robots-Tag "noindex, nofollow"
|
|
|
|
# Host 를 그대로 넘겨야 WAS 가 csv.wise.ai.kr 기준으로 링크를 만든다
|
|
ProxyPreserveHost On
|
|
# arko 는 첫 요청에서 JSP 를 컴파일하고, 통계·엑셀 다운로드가 오래 걸린다
|
|
ProxyTimeout 300
|
|
|
|
# 접속기록(개인정보보호 SFR-004)이 실제 접속자 IP 를 남겨야 한다.
|
|
# 프록시를 한 단 거치므로 원본 IP 를 헤더로 전달한다.
|
|
RequestHeader set X-Forwarded-Proto "https"
|
|
|
|
|
|
# ── 느린 회선 대응 ───────────────────────────────────────────────────
|
|
# 이 사이트는 메인 화면 하나에 woff 폰트만 3MB 넘게 끌어온다. 사내망에서는
|
|
# 티가 안 나지만 테더링·모바일에서는 로딩이 끝나지 않아 "접속 안 됨"으로 보인다.
|
|
# (실측: 같은 폰트가 유선망 0.15초 / 테더링 25초)
|
|
|
|
# ① 텍스트 자원 압축. HTML 52KB → 약 12KB.
|
|
# woff/woff2·이미지는 이미 압축돼 있어 넣지 않는다(CPU만 쓰고 안 줄어든다).
|
|
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/x-javascript application/json application/xml
|
|
# 압축 여부가 캐시 키에 반영되도록
|
|
Header append Vary Accept-Encoding
|
|
|
|
# ② 정적 자원 캐시. 원래는 매 방문마다 3MB 를 다시 받았다.
|
|
# 폰트는 파일명이 바뀌지 않으므로 길게, css/js 는 배포마다 바뀌므로 짧게 잡는다.
|
|
<LocationMatch "\.(woff2?|ttf|eot|otf)$">
|
|
Header set Cache-Control "public, max-age=31536000, immutable"
|
|
</LocationMatch>
|
|
<LocationMatch "\.(png|jpe?g|gif|ico|svg|webp)$">
|
|
Header set Cache-Control "public, max-age=604800"
|
|
</LocationMatch>
|
|
<LocationMatch "\.(css|js)$">
|
|
Header set Cache-Control "public, max-age=3600"
|
|
</LocationMatch>
|
|
|
|
ProxyPass /.well-known/acme-challenge/ !
|
|
ProxyPass / http://127.0.0.1:11060/
|
|
ProxyPassReverse / http://127.0.0.1:11060/
|
|
|
|
ErrorLog /var/log/httpd/csv_error.log
|
|
CustomLog /var/log/httpd/csv_access.log combined
|
|
</VirtualHost>
|