Przygotuj małe, kontrolowane środowisko
Ta procedura dotyczy systemu Linux z systemd, konta administratora, już zainstalowanego środowiska uruchomieniowego Node.js 24 LTS, curl oraz usługi systemowej Caddy'ego z pakietu. Najpierw potwierdź zainstalowane wersje i ścieżki pakietów; strona wydań Node'a wskazuje obsługiwane linie wydań. Instalacja i udostępnianie u dostawcy to osobne zadania. Użyj maszyny, którą kontrolujesz, i utrzymuj przetestowaną sesję SSH oraz ścieżkę odzyskiwania. Nazwy first-api oraz /opt/first-api muszą być nieużywane przed utworzeniem tego przykładu.
Dla HTTPS potrzebujesz także domeny, którą kontrolujesz, poprawnych rekordów A/AAAA i uprawnień do wystawienia ruchu webowego. api.example.com poniżej jest zarezerwowanym przykładem: zastąp go własną nazwą hosta. To API celowo nie zawiera bazy danych, uwierzytelniania ani danych klientów. Demonstruje powtarzalny proces, a nie kompletny produkt ani przetestowane wdrożenie OffVPS.
Zweryfikuj środowisko uruchomieniowe i utwórz jedno wydanie
command -v node &&
readlink -f "$(command -v node)" &&
node --version
Reszta przykładu zakłada, że zweryfikowany wspólny plik wykonywalny to /usr/bin/node. Jeśli Twój się różni, zastąp tę ścieżkę w każdej kontroli oraz w ExecStart. Środowisko uruchomieniowe wewnątrz prywatnego katalogu domowego Twojego użytkownika logowania nie jest automatycznie dostępne dla usługi systemowej. Utwórz konto usługi i katalog wydania należący do roota, zatrzymując się, jeśli zostanie znalezione nieoczekiwane istniejące konto lub ścieżka.
sudo useradd --system --user-group --home-dir /opt/first-api \
--shell /usr/sbin/nologin first-api &&
sudo install -d -o root -g root -m 0755 /opt/first-api/releases/001
Używając swojego edytora z dostępem administracyjnym, zapisz poniższą treść jako /opt/first-api/releases/001/server.mjs, należący do roota i czytelny dla użytkownika usługi. Wydanie zawiera tylko ten plik; nie ma zależności pakietów ani sekretów.
import http from 'node:http';
const port = Number(process.env.PORT || 3000);
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
throw new Error('PORT must be an integer from 1024 to 65535');
}
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.setHeader('Cache-Control', 'no-store');
if (req.method !== 'GET') {
res.writeHead(405, { Allow: 'GET' });
res.end(JSON.stringify({ error: 'method_not_allowed' }));
return;
}
if (req.url === '/healthz') {
res.writeHead(200);
res.end(JSON.stringify({ status: 'ok', release: '001' }));
} else if (req.url === '/api/message') {
res.writeHead(200);
res.end(JSON.stringify({ message: 'A small app, running clearly.' }));
} else {
res.writeHead(404);
res.end(JSON.stringify({ error: 'not_found' }));
}
});
server.requestTimeout = 10000;
server.headersTimeout = 10000;
server.keepAliveTimeout = 5000;
server.listen(port, '127.0.0.1');
process.on('SIGTERM', () => {
server.close(() => process.exit(0));
setTimeout(() => process.exit(1), 10000).unref();
});
Jawny adres loopback utrzymuje nasłuch API na samym serwerze. Caddy będzie jego publicznym punktem wejścia. API HTTP Node'a dokumentuje obsługę żądań, przekroczenia czasu i zamykanie serwera. Sprawdź plik jako konto, które faktycznie go uruchomi:
sudo -u first-api /usr/bin/node --check /opt/first-api/releases/001/server.mjs
Nadaj procesowi definicję usługi
Zapisz /etc/systemd/system/first-api.service z tą treścią:
[Unit]
Description=First API learning release
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=5
[Service]
Type=simple
User=first-api
Group=first-api
WorkingDirectory=/opt/first-api/releases/001
ExecStart=/usr/bin/node /opt/first-api/releases/001/server.mjs
Environment=NODE_ENV=production
Environment=PORT=3000
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.target
Jednostka używa jednego dedykowanego użytkownika, jawnego pliku wykonywalnego i wersjonowanego katalogu roboczego. Automatyczne odtwarzanie jest ograniczane szybkościowo; celowe zatrzymanie usługi nie wyzwala Restart=on-failure. Zobacz systemd.service. Ograniczenia systemu plików pasują do tego API tylko do odczytu; aplikacja, która zapisuje dane, wymaga celowo ograniczonego zapisywalnego magazynu. Sekrety nie należą do tych linii środowiskowych. Zobacz ustawienia wykonawcze systemd.
sudo systemd-analyze verify /etc/systemd/system/first-api.service &&
sudo systemctl daemon-reload &&
sudo systemctl start first-api.service &&
sudo systemctl status first-api.service --no-pager &&
curl --fail --show-error http://127.0.0.1:3000/healthz
Ten && zabezpieczenia zatrzymują wklejoną sekwencję, gdy polecenie zawiedzie. Rozwiąż ostrzeżenia walidacji przed uruchomieniem i nie przechodź do następnego bloku po nieudanej kontroli. Weryfikacja jednostki może wychwycić problemy ze składnią i plikiem wykonywalnym, ale pomyślna kontrola nie jest dowodem działającej aplikacji. Oczekiwana odpowiedź zdrowia to {"status":"ok","release":"001"}. Jeśli zawiedzie, sprawdź sudo journalctl -u first-api.service -n 50 --no-pager przed wielokrotnym restartowaniem.
Dodaj trasę HTTPS po lokalnej kontroli
Zrób kopię zapasową istniejącej konfiguracji Caddy'ego pod nieużywaną nazwą pliku. Dodaj ten blok do /etc/caddy/Caddyfile bez zastępowania niepowiązanych witryn:
api.example.com {
reverse_proxy 127.0.0.1:3000
}
W standardowym przepływie dla domeny publicznej nazwa hosta musi rozwiązywać się do serwera, porty 80/443 muszą docierać do Caddy'ego, a magazyn certyfikatów Caddy'ego musi pozostać zapisywalny i trwały. Sprawdź każdą opublikowaną trasę A/AAAA. Pozostaw dostęp SSH nienaruszony i trzymaj port 3000 prywatny. Te wymagania pochodzą z Automatyczny HTTPS Caddy'ego; składnia upstreamu jest udokumentowana w reverse_proxy.
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile &&
sudo systemctl reload caddy.service
Przeładuj tylko po pomyślnej walidacji; caddy validate sprawdza zaadaptowaną konfigurację. Przepływ pracy usługi z pakietu opisano w przewodniku usługi Caddy'ego. Z osobnego klienta zażądaj https://api.example.com/healthz używając swojej prawdziwej nazwy hosta. Oczekuj zaufanego połączenia TLS i tej samej odpowiedzi wydania, bez omijania kontroli certyfikatów. Następnie zweryfikuj, że /api/message zwraca swój komunikat, a nieznana ścieżka zwraca 404.
Zachowaj znane wydanie i bezpieczny punkt zatrzymania
Po tym, jak obie kontrole zadziałają, włącz API dla przyszłych rozruchów za pomocą sudo systemctl enable first-api.service. Zapisz wersję środowiska uruchomieniowego, plik źródłowy, jednostkę i konfigurację Caddy'ego. W następnym wydaniu utwórz nowy numerowany katalog, sprawdź składnię jako użytkownik usługi, zaktualizuj obie ścieżki jednostki, przeładuj systemd i zrestartuj API. Zachowaj poprzedni katalog, dopóki nowe wydanie nie zostanie zaakceptowane.
Aby zatrzymać ten przykład, użyj sudo systemctl stop first-api.service. Caddy zgłosi awarię upstreamu, dopóki ta trasa pozostaje skonfigurowana; usuń tylko tę trasę i zwaliduj/przeładuj Caddy'ego przy jej wycofywaniu. Wycofaj nieudane wydanie kodu, wybierając poprzednie ścieżki jednostki i powtarzając kontrole. Późniejsza migracja bazy danych wymaga własnego planu odzyskiwania. Kontynuuj z ścieżką żądania od DNS do aplikacji lub znajdowaniem przyczyny zatrzymania aplikacji.
Wykorzystana dokumentacja
Główne źródła dla tej strony. Sprawdź dokumentację wersji zainstalowanej we własnym środowisku.