Compare commits
10 Commits
5ff20429d6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5678844cb5 | |||
| ce2eb8bf4b | |||
| 9029cf09e1 | |||
| dd304c1f31 | |||
| 97bec6a651 | |||
| c920449562 | |||
| b603bfd608 | |||
| b0aac6cbeb | |||
| a5ee8ce5c5 | |||
| be6ac9b0bf |
@@ -1,3 +0,0 @@
|
|||||||
# Documentation only (network_mode: host reads the listen port from nginx.conf).
|
|
||||||
ERROR_PAGE_BIND=127.0.0.1
|
|
||||||
ERROR_PAGE_PORT=4098
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
name: Deploy Main
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
DEPLOY_DIR: /volume1/09_container_manager/14_error-page
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-main:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy on NAS
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
mkdir -p "$DEPLOY_DIR/html"
|
||||||
|
cp docker-compose.yml "$DEPLOY_DIR/docker-compose.yml"
|
||||||
|
cp nginx.conf "$DEPLOY_DIR/nginx.conf"
|
||||||
|
cp upstreams.map "$DEPLOY_DIR/upstreams.map"
|
||||||
|
cp proxy_to_app.conf "$DEPLOY_DIR/proxy_to_app.conf"
|
||||||
|
cp html/index.html "$DEPLOY_DIR/html/index.html"
|
||||||
|
rm -f "$DEPLOY_DIR/html/preview.html"
|
||||||
|
|
||||||
|
cd "$DEPLOY_DIR"
|
||||||
|
docker compose config --quiet
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d --force-recreate
|
||||||
|
docker compose ps
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# error-page
|
# error-page
|
||||||
|
|
||||||
`*.takits.me`가 컨테이너 다운으로 502/503/504가 날 때, DSM 기본 에러창 대신 쓰는 공통 nginx.
|
`*.takits.me`가 컨테이너 다운(502/503/504)이거나 앱이 404/500을 줄 때, DSM 기본 에러창 대신 쓰는 공통 nginx.
|
||||||
|
|
||||||
DSM 리버스 프록시가 **앱 포트에 직접** 붙으면, 그 포트가 닫혀 있을 때 나스가 에러 페이지를 그립니다. 이 컨테이너는 항상 `127.0.0.1:4098`에서 떠 있고, `Host`로 실제 앱에 넘긴 뒤 업스트림이 죽었을 때만 공통 페이지를 보여 줍니다.
|
DSM 리버스 프록시가 **앱 포트에 직접** 붙으면, 그 포트가 닫혀 있을 때 나스가 에러 페이지를 그립니다. 이 컨테이너는 항상 `127.0.0.1:4098`에서 떠 있고, `Host`로 실제 앱에 넘긴 뒤 업스트림이 죽었을 때만 공통 페이지를 보여 줍니다.
|
||||||
|
|
||||||
@@ -9,16 +9,25 @@ DSM 리버스 프록시가 **앱 포트에 직접** 붙으면, 그 포트가 닫
|
|||||||
└─ Host가 takits.me 이면 127.0.0.1:4889
|
└─ Host가 takits.me 이면 127.0.0.1:4889
|
||||||
```
|
```
|
||||||
|
|
||||||
앱의 404/500은 가로채지 않습니다.
|
페이지 404/500과 게이트웨이 502/503/504는 공통 화면을 씁니다. `/api/` 404만 JSON 그대로 둡니다.
|
||||||
|
|
||||||
## 배포
|
## 배포
|
||||||
|
|
||||||
NAS 예: `/volume1/09_container_manager/@error-page`
|
`develop`에서 작업한 뒤 `main`에 머지하면 Gitea Actions가 아래 경로로 파일을 동기화하고 컨테이너를 재생성합니다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
/volume1/09_container_manager/14_error-page
|
||||||
|
```
|
||||||
|
|
||||||
|
수동 실행:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cd /volume1/09_container_manager/14_error-page
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
별도 `.env`는 필요하지 않습니다. 이 서비스에는 비밀값이 없고, 수신 주소와 포트는 `nginx.conf`에서 `127.0.0.1:4098`로 고정합니다.
|
||||||
|
|
||||||
확인:
|
확인:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -48,5 +57,6 @@ docker exec error-page nginx -s reload
|
|||||||
| 파일 | 역할 |
|
| 파일 | 역할 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `upstreams.map` | 호스트별 앱 포트 |
|
| `upstreams.map` | 호스트별 앱 포트 |
|
||||||
| `html/index.html` | 502/503/504 페이지 |
|
| `html/index.html` | 404/500/502/503/504 페이지 |
|
||||||
|
| `proxy_to_app.conf` | 앱으로 넘기는 프록시 설정 |
|
||||||
| `nginx.conf` | 프록시 + 에러 가로채기 |
|
| `nginx.conf` | 프록시 + 에러 가로채기 |
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
- ./upstreams.map:/etc/nginx/upstreams.map:ro
|
- ./upstreams.map:/etc/nginx/upstreams.map:ro
|
||||||
|
- ./proxy_to_app.conf:/etc/nginx/proxy_to_app.conf:ro
|
||||||
- ./html:/usr/share/nginx/html:ro
|
- ./html:/usr/share/nginx/html:ro
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4098/healthz"]
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4098/healthz"]
|
||||||
|
|||||||
+1
-4
@@ -105,10 +105,7 @@
|
|||||||
|
|
||||||
<p class="code">__STATUS__</p>
|
<p class="code">__STATUS__</p>
|
||||||
<h1 class="title">__ERROR_TITLE__</h1>
|
<h1 class="title">__ERROR_TITLE__</h1>
|
||||||
<p class="message">
|
<p class="message">__ERROR_MESSAGE__</p>
|
||||||
We're working to resolve the issue.<br />
|
|
||||||
Please try again shortly.
|
|
||||||
</p>
|
|
||||||
</main>
|
</main>
|
||||||
<footer>© 2026 takitsme. All rights reserved.</footer>
|
<footer>© 2026 takitsme. All rights reserved.</footer>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+16
-20
@@ -20,11 +20,18 @@ http {
|
|||||||
|
|
||||||
map $status $error_title {
|
map $status $error_title {
|
||||||
default "Service Unavailable";
|
default "Service Unavailable";
|
||||||
|
404 "Not Found";
|
||||||
|
500 "Internal Server Error";
|
||||||
502 "Bad Gateway";
|
502 "Bad Gateway";
|
||||||
503 "Service Unavailable";
|
503 "Service Unavailable";
|
||||||
504 "Gateway Timeout";
|
504 "Gateway Timeout";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map $status $error_message {
|
||||||
|
default "We're working to resolve the issue.<br />Please try again shortly.";
|
||||||
|
404 "The page you're looking for could not be found.";
|
||||||
|
}
|
||||||
|
|
||||||
include /etc/nginx/upstreams.map;
|
include /etc/nginx/upstreams.map;
|
||||||
|
|
||||||
server {
|
server {
|
||||||
@@ -40,7 +47,7 @@ http {
|
|||||||
return 200 "ok\n";
|
return 200 "ok\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 502 503 504 /__error/index.html;
|
error_page 404 500 502 503 504 /__error/index.html;
|
||||||
|
|
||||||
location = /__error/index.html {
|
location = /__error/index.html {
|
||||||
internal;
|
internal;
|
||||||
@@ -48,31 +55,20 @@ http {
|
|||||||
sub_filter_types text/html;
|
sub_filter_types text/html;
|
||||||
sub_filter "__STATUS__" $status;
|
sub_filter "__STATUS__" $status;
|
||||||
sub_filter "__ERROR_TITLE__" $error_title;
|
sub_filter "__ERROR_TITLE__" $error_title;
|
||||||
|
sub_filter "__ERROR_MESSAGE__" $error_message;
|
||||||
sub_filter "__HOST__" $host;
|
sub_filter "__HOST__" $host;
|
||||||
add_header Cache-Control "no-store" always;
|
add_header Cache-Control "no-store" always;
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# API 404 stays with the app so JSON clients keep working.
|
||||||
|
location /api/ {
|
||||||
|
error_page 500 502 503 504 /__error/index.html;
|
||||||
|
include /etc/nginx/proxy_to_app.conf;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
if ($app_port = 0) {
|
include /etc/nginx/proxy_to_app.conf;
|
||||||
return 502;
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:$app_port;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
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;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
|
|
||||||
proxy_connect_timeout 3s;
|
|
||||||
proxy_send_timeout 3600s;
|
|
||||||
proxy_read_timeout 3600s;
|
|
||||||
|
|
||||||
# Only replace DSM-style "upstream down" pages. App 404/500 stay as-is.
|
|
||||||
proxy_intercept_errors on;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
if ($app_port = 0) {
|
||||||
|
return 502;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:$app_port;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
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;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_send_timeout 3600s;
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
|
||||||
|
proxy_intercept_errors on;
|
||||||
+4
-3
@@ -11,8 +11,9 @@ map $host $app_port {
|
|||||||
www.takits.me 4889;
|
www.takits.me 4889;
|
||||||
|
|
||||||
fas.takits.me 4885;
|
fas.takits.me 4885;
|
||||||
ops.fas.takits.me 4887;
|
dev-fas.takits.me 4886;
|
||||||
|
android-fas.takits.me 6080;
|
||||||
|
recap.takits.me 4890;
|
||||||
|
|
||||||
# dev-fas.takits.me 80xx;
|
# ops.fas.takits.me 4887;
|
||||||
# android-fas.takits.me 6080;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user