Commit 8795dd09 authored by nanahira's avatar nanahira

fix acme drift

parent 202f4043
Pipeline #41770 failed with stages
in 1 minute and 21 seconds
...@@ -7,6 +7,9 @@ import { promisify } from 'util'; ...@@ -7,6 +7,9 @@ import { promisify } from 'util';
const execFile = promisify(_execFile); const execFile = promisify(_execFile);
const DEBUG = process.env.DEBUG === '1';
const NGINX_CONF_PATH = process.env.NGINX_CONF_PATH || '/etc/nginx/nginx.conf';
async function reloadNginx() { async function reloadNginx() {
console.error('[nginx] Reloading...'); console.error('[nginx] Reloading...');
try { try {
...@@ -20,27 +23,57 @@ async function reloadNginx() { ...@@ -20,27 +23,57 @@ async function reloadNginx() {
} }
} }
function renderTemplate(parsed: any): string {
const tpl = fs.readFileSync(
path.join(__dirname, '..', 'views', 'nginx.conf.mustache'),
'utf8',
);
const rendered = Mustache.render(tpl, parsed, undefined, {
escape: (v) => v,
});
return rendered;
}
function writeConfig(rendered: string) {
if (DEBUG) {
// DEBUG=1:和原来一样,直接往 stdout 打
console.error('[render] DEBUG=1, writing config to stdout instead of file');
console.log(rendered);
} else {
fs.writeFileSync(NGINX_CONF_PATH, rendered, 'utf8');
console.error('[render] Nginx config written to', NGINX_CONF_PATH);
}
}
async function main() { async function main() {
try { try {
if (process.argv[2] === 'renewCert') { const mode = process.argv[2];
if (mode === 'renewCert') {
console.error('[acme] Signing start'); console.error('[acme] Signing start');
await getData(process.env as any, 61000); // 带超时的 getData
const parsed = await getData(process.env as any, 61000);
console.error('[acme] Signing done'); console.error('[acme] Signing done');
console.error('[render] Nginx config render start (renewCert)');
const rendered = renderTemplate(parsed);
writeConfig(rendered);
console.error('[render] Nginx config render done (renewCert)');
if (!DEBUG) {
await reloadNginx(); await reloadNginx();
} else {
console.error('[nginx] DEBUG=1, skip reload');
}
} else { } else {
console.error('[render] Nginx config render start'); console.error('[render] Nginx config render start');
const parsed = await getData(process.env as any); const parsed = await getData(process.env as any);
console.error('[render] parsed'); console.error('[render] parsed');
const tpl = fs.readFileSync( const rendered = renderTemplate(parsed);
path.join(__dirname, '..', 'views', 'nginx.conf.mustache'), writeConfig(rendered);
'utf8',
);
const rendered = Mustache.render(tpl, parsed, undefined, {
escape: (v) => v,
});
console.log(rendered);
console.error('[render] Nginx config render done'); console.error('[render] Nginx config render done');
} }
process.exit(0); process.exit(0);
} catch (e) { } catch (e) {
console.error('[main] Error:', e); console.error('[main] Error:', e);
......
...@@ -8,7 +8,7 @@ let email: string; ...@@ -8,7 +8,7 @@ let email: string;
export const domainsToBeSigned: string[] = []; export const domainsToBeSigned: string[] = [];
export async function addSignCert(domains: string[], payload: string) { export async function addSignCert(domains: string[], payload: string) {
const pickedCert = await pickCert(domains); const pickedCert = await pickCert(domains, true);
if (pickedCert) { if (pickedCert) {
return pickedCert; return pickedCert;
} }
......
...@@ -10,12 +10,12 @@ class Cert { ...@@ -10,12 +10,12 @@ class Cert {
); );
constructor(public dir: string) {} constructor(public dir: string) {}
isNotExpired() { isNotExpired(acme = false) {
const now = new Date(); const now = new Date();
const validFrom = new Date(this.cert.validFrom); const validFrom = new Date(this.cert.validFrom);
const validTo = new Date(this.cert.validTo); const validTo = new Date(this.cert.validTo);
if (process.argv[2] === 'renewCert') { if (process.argv[2] === 'renewCert' && acme) {
const threshold = new Date(validTo.getTime() - 7 * 24 * 60 * 60 * 1000); const threshold = new Date(validTo.getTime() - 7 * 24 * 60 * 60 * 1000);
return now > validFrom && now < threshold; return now > validFrom && now < threshold;
} }
...@@ -27,8 +27,8 @@ class Cert { ...@@ -27,8 +27,8 @@ class Cert {
return this.cert.checkHost(domain); return this.cert.checkHost(domain);
} }
isOkWithDomains(domains: string[]) { isOkWithDomains(domains: string[], acme = false) {
return domains.every((domain) => this.isOkWithDomain(domain)); return domains.every((domain) => this.isOkWithDomain(domain, acme));
} }
} }
...@@ -40,8 +40,8 @@ const certs = fs ...@@ -40,8 +40,8 @@ const certs = fs
.map((dir) => new Cert(dir)) .map((dir) => new Cert(dir))
.filter((cert) => cert.isNotExpired()); .filter((cert) => cert.isNotExpired());
export async function pickCert(domains: string[]) { export async function pickCert(domains: string[], acme = false) {
const okCerts = certs.filter((cert) => cert.isOkWithDomains(domains)); const okCerts = certs.filter((cert) => cert.isOkWithDomains(domains, acme));
if (!okCerts.length) { if (!okCerts.length) {
return; return;
} }
......
#!/bin/sh #!/bin/sh
set -e set -e
node dist > /etc/nginx/nginx.conf NGINX_CONF_PATH="${NGINX_CONF_PATH:-/etc/nginx/nginx.conf}"
if grep -q 'acme_required' /etc/nginx/nginx.conf; then node dist
# 检查是否需要 ACME
if grep -q 'acme_required' "$NGINX_CONF_PATH"; then
echo "[entrypoint] ACME required detected, scheduling daily renewCert task" >&2 echo "[entrypoint] ACME required detected, scheduling daily renewCert task" >&2
( (
while true; do while true; do
sleep 86400 # 24h sleep 86400 # 24h
echo "[entrypoint] Running daily cert renewal..." >&2 echo "[entrypoint] Running daily cert renewal..." >&2
node dist renewCert || echo "[entrypoint] renewCert failed" >&2 if ! node dist renewCert; then
echo "[entrypoint] renewCert failed" >&2
fi
echo "[entrypoint] Daily cert renewal finished." >&2 echo "[entrypoint] Daily cert renewal finished." >&2
done done
) & ) &
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment