431 lines
18 KiB
HTML
431 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ja">
|
|
<head>
|
|
<!--
|
|
$ curl https://nercone.dev/error-nginx.html
|
|
■ ■ ■■■■■ ■■■■ ■■■■ ■■■ ■ ■ ■■■■■
|
|
■■ ■ ■ ■ ■ ■ ■ ■ ■■ ■ ■
|
|
■■ ■ ■ ■ ■ ■ ■ ■ ■■ ■ ■
|
|
■ ■ ■ ■■■■ ■■■■ ■ ■ ■ ■ ■ ■ ■■■■
|
|
■ ■■ ■ ■ ■ ■ ■ ■ ■ ■■ ■
|
|
■ ■■ ■ ■ ■ ■ ■ ■ ■ ■■ ■
|
|
■ ■ ■■■■■ ■ ■ ■■■■ ■■■ ■ ■ ■■■■■
|
|
|
|
このページは、リバースプロキシとして使用しているNginxが、バックエンドのWebサーバーへの接続に失敗した際に表示されます。
|
|
バックエンドのWebサーバーはUvicorn + FastAPIで動作しており、サブドメインのルーティングとTLSへの対応のためにNginxを間に噛ませています。
|
|
Webサーバーの再起動には約4秒かかります。システムごと再起動する場合、最大5分程度かかります。
|
|
もし5分以上アクセスできない場合、何かしらの問題が発生しているか、サーバーの環境を作り直している可能性があります。
|
|
どちらにせよ、すぐにはアクセスできないので、コーヒーか何かを飲んで待つか、Nerconeを叩き起こして修正させる必要があります。
|
|
さて、このメッセージを見ているということは、少なくともDevToolを知っている人...おそらく技術者でしょう?良ければネッ友になりませんか?
|
|
|
|
P.S. 暇つぶしにソースコードでもいかがですか? https://gitea.nercone.dev/nercone-dev/website/
|
|
-->
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>nercone.dev への接続に失敗しました</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=BIZ+UDGothic&family=Noto+Sans+JP:wght@100..900&family=Noto+Sans+SC:wght@100..900&family=Noto+Sans+TC:wght@100..900&family=Noto+Sans+KR:wght@100..900&display=swap">
|
|
<style>
|
|
:root {
|
|
--color-black: #000000;
|
|
--color-white: #FFFFFF;
|
|
|
|
--color-dark-grey: #1A1A1A;
|
|
--color-dark-grey-alt: #272727;
|
|
--color-light-grey: #E0E0E0;
|
|
--color-light-grey-alt: #939393;
|
|
|
|
--color-red: #A03333;
|
|
--color-green: #00A050;
|
|
}
|
|
|
|
html {
|
|
color: var(--color-light-grey);
|
|
background-color: var(--color-dark-grey);
|
|
margin: 0;
|
|
padding: 0;
|
|
font-family: "Inter", "BIZ UDGothic", "Noto Sans JP", "Noto Sans TC", "Noto Sans SC", sans-serif;
|
|
font-size: 12pt;
|
|
font-optical-sizing: auto;
|
|
font-weight: 400;
|
|
font-style: normal;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 24px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.error-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 80px;
|
|
width: 100%;
|
|
max-width: 1032px;
|
|
}
|
|
|
|
.diagram {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
width: 100%;
|
|
justify-content: center;
|
|
}
|
|
|
|
.node {
|
|
width: 192px;
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.node-body {
|
|
width: 192px;
|
|
height: 192px;
|
|
background-color: var(--color-dark-grey-alt);
|
|
border-radius: 32px 32px 0 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding-top: 48px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.node-icon {
|
|
width: 96px;
|
|
height: 96px;
|
|
color: var(--color-light-grey);
|
|
}
|
|
|
|
.node-icon svg {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: visible;
|
|
}
|
|
|
|
.node-label {
|
|
margin-top: 27px;
|
|
font-size: 12px;
|
|
line-height: 1;
|
|
color: var(--color-light-grey);
|
|
}
|
|
|
|
.node-status {
|
|
width: 192px;
|
|
height: 32px;
|
|
border-radius: 0 0 32px 32px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 16px;
|
|
color: var(--color-white);
|
|
background-color: var(--color-light-grey-alt);
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.node-status.status-normal { background-color: var(--color-green); }
|
|
.node-status.status-error { background-color: var(--color-red); }
|
|
.node-status.status-unknown { background-color: var(--color-light-grey-alt); }
|
|
|
|
.connector {
|
|
flex: 1;
|
|
height: 4px;
|
|
margin-top: 94px;
|
|
min-width: 60px;
|
|
background-repeat: repeat-x;
|
|
background-position: center;
|
|
background-size: 32px 4px;
|
|
transition: background 0.3s ease;
|
|
}
|
|
|
|
.connector.line-solid-green {
|
|
background-color: var(--color-green);
|
|
background-image: none;
|
|
}
|
|
.connector.line-solid-red {
|
|
background-color: var(--color-red);
|
|
background-image: none;
|
|
}
|
|
.connector.line-solid-grey {
|
|
background-color: var(--color-light-grey-alt);
|
|
background-image: none;
|
|
}
|
|
.connector.line-dashed-green {
|
|
background-color: transparent;
|
|
background-image: repeating-linear-gradient(to right,
|
|
var(--color-green) 0, var(--color-green) 16px,
|
|
transparent 16px, transparent 32px);
|
|
}
|
|
.connector.line-dashed-red {
|
|
background-color: transparent;
|
|
background-image: repeating-linear-gradient(to right,
|
|
var(--color-red) 0, var(--color-red) 16px,
|
|
transparent 16px, transparent 32px);
|
|
}
|
|
.connector.line-dashed-grey {
|
|
background-color: transparent;
|
|
background-image: repeating-linear-gradient(to right,
|
|
var(--color-light-grey-alt) 0, var(--color-light-grey-alt) 16px,
|
|
transparent 16px, transparent 32px);
|
|
}
|
|
|
|
.error-text {
|
|
text-align: center;
|
|
}
|
|
.error-title {
|
|
font-size: 32px;
|
|
color: var(--color-light-grey);
|
|
margin: 0 0 16px 0;
|
|
font-weight: 400;
|
|
line-height: 1.3;
|
|
}
|
|
.error-message {
|
|
font-size: 20px;
|
|
color: var(--color-light-grey-alt);
|
|
margin: 0;
|
|
font-weight: 400;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
@media (max-width: 880px) {
|
|
.error-container { gap: 56px; }
|
|
.error-title { font-size: 26px; line-height: 1.35; }
|
|
.error-message { font-size: 16px; }
|
|
|
|
.node, .node-body, .node-status { width: 144px; }
|
|
.node-body {
|
|
height: 144px;
|
|
padding-top: 36px;
|
|
border-radius: 24px 24px 0 0;
|
|
}
|
|
.node-icon { width: 72px; height: 72px; }
|
|
.node-status {
|
|
height: 28px;
|
|
font-size: 14px;
|
|
border-radius: 0 0 24px 24px;
|
|
}
|
|
.node-label { margin-top: 20px; font-size: 11px; }
|
|
.connector {
|
|
margin-top: 70px;
|
|
min-width: 24px;
|
|
background-size: 24px 4px;
|
|
}
|
|
.connector.line-dashed-red,
|
|
.connector.line-dashed-green,
|
|
.connector.line-dashed-grey {
|
|
background-image: repeating-linear-gradient(to right,
|
|
currentColor 0, currentColor 12px,
|
|
transparent 12px, transparent 24px);
|
|
}
|
|
.connector.line-dashed-red { color: var(--color-red); }
|
|
.connector.line-dashed-green { color: var(--color-green); }
|
|
.connector.line-dashed-grey { color: var(--color-light-grey-alt); }
|
|
}
|
|
|
|
@media (max-width: 540px) {
|
|
body { padding: 16px; }
|
|
.error-container { gap: 32px; }
|
|
.error-title { font-size: 20px; line-height: 1.4; }
|
|
.error-message { font-size: 13px; line-height: 1.5; }
|
|
|
|
.node, .node-body, .node-status { width: 96px; }
|
|
.node-body {
|
|
height: 96px;
|
|
padding-top: 24px;
|
|
border-radius: 16px 16px 0 0;
|
|
}
|
|
.node-icon { width: 48px; height: 48px; }
|
|
.node-status {
|
|
height: 24px;
|
|
font-size: 11px;
|
|
border-radius: 0 0 16px 16px;
|
|
}
|
|
.node-label {
|
|
margin-top: 8px;
|
|
font-size: 9px;
|
|
text-align: center;
|
|
padding: 0 2px;
|
|
}
|
|
.connector {
|
|
margin-top: 46px;
|
|
min-width: 12px;
|
|
background-size: 16px 4px;
|
|
}
|
|
.connector.line-dashed-red,
|
|
.connector.line-dashed-green,
|
|
.connector.line-dashed-grey {
|
|
background-image: repeating-linear-gradient(to right,
|
|
currentColor 0, currentColor 8px,
|
|
transparent 8px, transparent 16px);
|
|
}
|
|
}
|
|
|
|
@media (max-width: 360px) {
|
|
body { padding: 8px; }
|
|
.node, .node-body, .node-status { width: 80px; }
|
|
.node-body {
|
|
height: 80px;
|
|
padding-top: 18px;
|
|
}
|
|
.node-icon { width: 44px; height: 44px; }
|
|
.node-status { height: 22px; font-size: 10px; }
|
|
.node-label { margin-top: 6px; font-size: 8px; }
|
|
.connector { margin-top: 38px; min-width: 8px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="error-container">
|
|
<div class="diagram">
|
|
<!-- User Agent -->
|
|
<div class="node">
|
|
<div class="node-body">
|
|
<div class="node-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="1" y="1" width="94" height="94" rx="8" ry="8"/>
|
|
<line x1="1" y1="32" x2="95" y2="32"/>
|
|
</svg>
|
|
</div>
|
|
<div class="node-label">ユーザーエージェント</div>
|
|
</div>
|
|
<div class="node-status" id="status-1">正常</div>
|
|
</div>
|
|
|
|
<div class="connector" id="connector-1"></div>
|
|
|
|
<div class="node">
|
|
<div class="node-body">
|
|
<div class="node-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M41.21,16.39 l-24.83,24.83"/>
|
|
<path d="M79.61,54.79 l-24.83,24.83"/>
|
|
<path d="M19.2,48 h57.6"/>
|
|
<circle cx="48" cy="9.6" r="9.6"/>
|
|
<circle cx="86.4" cy="48" r="9.6"/>
|
|
<circle cx="48" cy="86.4" r="9.6"/>
|
|
<circle cx="9.6" cy="48" r="9.6"/>
|
|
</svg>
|
|
</div>
|
|
<div class="node-label">リバースプロキシ</div>
|
|
</div>
|
|
<div class="node-status" id="status-2">正常</div>
|
|
</div>
|
|
|
|
<div class="connector" id="connector-2"></div>
|
|
|
|
<div class="node">
|
|
<div class="node-body">
|
|
<div class="node-icon" aria-hidden="true">
|
|
<svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square">
|
|
<path d="M24,0 h62.4 c5.3,0 9.6,4.3 9.6,9.6 v19.2 c0,5.3 -4.3,9.6 -9.6,9.6 h-24"/>
|
|
<path d="M38.4,38.4 l-36,-36 c-2.4,-2.4 -2.4,0 -2.4,12 v14.4 c0,5.3 4.3,9.6 9.6,9.6 h28.8 Z"/>
|
|
<path d="M96,72 v-4.8 c0,-5.3 -4.3,-9.6 -9.6,-9.6 h-4.8"/>
|
|
<path d="M9.6,57.6 c-5.3,0 -9.6,4.3 -9.6,9.6 v19.2 c0,5.3 4.3,9.6 9.6,9.6 h79.2 l4.8,-2.4 2.4,2.4 -38.4,-38.4 h-48 Z"/>
|
|
<path d="M19.2,76.8 h.05"/>
|
|
<path d="M0,0 l96,96"/>
|
|
</svg>
|
|
</div>
|
|
<div class="node-label" id="domain-label">nercone.dev</div>
|
|
</div>
|
|
<div class="node-status" id="status-3">応答なし</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="error-text">
|
|
<h1 class="error-title"><span id="domain-text">nercone.dev</span> への接続に失敗しました</h1>
|
|
<p class="error-message">もう少し待ってから接続を再試行してください。HTTPレスポンスステータスコードは<span id="status-code">502</span>です。</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
'use strict';
|
|
|
|
var STAGES = {
|
|
'user-agent': { statusElId: 'status-1', incomingConnectorId: null },
|
|
'reverse-proxy': { statusElId: 'status-2', incomingConnectorId: 'connector-1' },
|
|
'origin': { statusElId: 'status-3', incomingConnectorId: 'connector-2' }
|
|
};
|
|
|
|
var STATUS_DEFS = {
|
|
normal: { className: 'status-normal', label: '正常', line: 'line-solid-green' },
|
|
error: { className: 'status-error', label: '応答なし', line: 'line-dashed-red' },
|
|
unknown: { className: 'status-unknown', label: '不明', line: 'line-dashed-grey' }
|
|
};
|
|
|
|
function setStageStatus(stage, status, label) {
|
|
var stageConfig = STAGES[stage];
|
|
var statusDef = STATUS_DEFS[status];
|
|
if (!stageConfig || !statusDef) return;
|
|
|
|
var statusEl = document.getElementById(stageConfig.statusElId);
|
|
if (statusEl) {
|
|
statusEl.className = 'node-status ' + statusDef.className;
|
|
statusEl.textContent = label != null ? label : statusDef.label;
|
|
}
|
|
|
|
if (stageConfig.incomingConnectorId) {
|
|
var connectorEl = document.getElementById(stageConfig.incomingConnectorId);
|
|
if (connectorEl) {
|
|
connectorEl.className = 'connector ' + statusDef.line;
|
|
}
|
|
}
|
|
}
|
|
|
|
function setStatusCode(code) {
|
|
var el = document.getElementById('status-code');
|
|
if (el) el.textContent = String(code);
|
|
}
|
|
|
|
function setDomain(domain) {
|
|
var labelEl = document.getElementById('domain-label');
|
|
var textEl = document.getElementById('domain-text');
|
|
if (labelEl) labelEl.textContent = domain;
|
|
if (textEl) textEl.textContent = domain;
|
|
}
|
|
|
|
window.ConnectionError = {
|
|
setStageStatus: setStageStatus,
|
|
setStatusCode: setStatusCode,
|
|
setDomain: setDomain
|
|
};
|
|
|
|
setStageStatus('user-agent', 'normal');
|
|
setStageStatus('reverse-proxy', 'normal');
|
|
setStageStatus('origin', 'error');
|
|
|
|
try {
|
|
var host = window.location.hostname;
|
|
if (host) setDomain(host);
|
|
} catch (e) {}
|
|
|
|
try {
|
|
var url = window.location.href;
|
|
var controller = (typeof AbortController !== 'undefined') ? new AbortController() : null;
|
|
if (controller) {
|
|
setTimeout(function () { try { controller.abort(); } catch (e) {} }, 5000);
|
|
}
|
|
fetch(url, {
|
|
method: 'HEAD',
|
|
cache: 'no-store',
|
|
credentials: 'same-origin',
|
|
redirect: 'manual',
|
|
signal: controller ? controller.signal : undefined
|
|
}).then(function (response) {
|
|
if (response && typeof response.status === 'number' && response.status > 0) {
|
|
setStatusCode(response.status);
|
|
}
|
|
}).catch(function () {});
|
|
} catch (e) {}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|