Przejdź do treści

Ustawienia cookies

Poniżej wypisujemy nazwa po nazwie, co ta strona zapisuje w Twojej przeglądarce. Możesz tu wrócić w każdej chwili. Odnośnik „Ustawienia cookies” stoi w stopce każdej strony.

Polityka prywatności §7
isbre
Blog · PHP i aplikacje

Jak uruchomić aplikację Node.js na hostingu współdzielonym (bez VPS-a): systemd, port, domena

Krok po kroku: plik startowy i port, zależności przez SSH, dodanie aplikacji w panelu, domena z HTTPS. Co robi za Ciebie system, a co zostaje po Twojej stronie.

· Zespół administratorów Isbre

Zaktualizowano

  • Node.js
  • aplikacje
  • systemd
  • SSH

Chcesz uruchomić aplikację w Node.js, ale nie masz ochoty na VPS z własną zaporą, certyfikatami i aktualizacjami systemu? U nas aplikacja jest zwykłym procesem w Twoim kontenerze. Pilnuje go systemd, a pod Twoją domenę wystawia go serwer WWW Apache. Zapory ani certyfikatów nie konfigurujesz: wgrywasz kod i dodajesz aplikację w panelu. Poniżej cała droga od git clone do strony pod Twoją domeną po HTTPS. Po drodze mówimy też, czego u nas nie zrobisz.

Czego potrzebujesz, zanim zaczniesz

Najpierw pakiet, bo od niego zależy, czy w ogóle zainstalujesz zależności.

  1. Pakiet z powłoką SSH. Node zaczyna się u nas od pakietu Standard. Powód jest techniczny: zależności instalujesz komendą npm ci na serwerze, a Start ma tylko SFTP. Gotowy katalog node_modules da się wgrać przez SFTP, tylko że każda zmiana zależności oznacza wtedy wysyłkę całego katalogu od nowa. Nie polecamy.
  2. Kod, który nasłuchuje na porcie ze zmiennej PORT. To jedyny warunek po stronie aplikacji. Skąd bierze się ten port, wyjaśnia krok 1.

Domena może poczekać. Aplikację dodasz też bez niej, do testów, i będzie wtedy działać tylko wewnętrznie.

Node jest w każdym kontenerze, w liniach 20, 22 i 24 z obrazu serwera. Domyślna to 22. Wersję wybierasz w panelu osobno dla każdej aplikacji, a lista do wyboru jest czytana z Twojego kontenera, więc nie wybierzesz wersji, której tam nie ma.

Krok 1: plik startowy i port

Tu obowiązuje konwencja, bez pól do wypełniania. Kod leży w katalogu ~/apps/<nazwa>, plik startowy to server.js, a aplikacja nasłuchuje na porcie z process.env.PORT, na adresie lokalnym. Numeru portu nie wybierasz: przydzielamy go przy dodawaniu aplikacji z puli od 3001 do 3099 na Twoim kontenerze i wpisujemy do środowiska procesu. Serwer WWW kieruje na ten port ruch z domeny.

Najkrótszy server.js, który spełnia oba warunki:

import { createServer } from 'node:http';

const port = Number(process.env.PORT);

createServer((req, res) => {
  res.setHeader('content-type', 'text/plain; charset=utf-8');
  res.end('Działa: ' + req.url);
}).listen(port, '127.0.0.1', () => {
  console.log('nasłuchuję na porcie ' + port);
});

Z Expressem mieści się to w jednej linii: app.listen(process.env.PORT, '127.0.0.1'). Frameworki, które same czytają PORT (Next.js, Fastify z konfiguracją, Nest), wymagają tylko tego, żeby skrypt startowy nazywał się server.js albo żeby server.js je uruchamiał.

Dwie pułapki z pierwszych dni:

  • Port wpisany na sztywno (listen(3000)). Aplikacja wstanie, ale serwer WWW szuka jej na porcie z puli, więc pod domeną zobaczysz błąd bramy. Zawsze process.env.PORT.
  • Nasłuch na wszystkich interfejsach (0.0.0.0). Niepotrzebny: ruch wchodzi do aplikacji wyłącznie przez serwer WWW w tym samym kontenerze, po 127.0.0.1.

Krok 2: wgranie kodu i instalacja zależności przez SSH

Adres serwera, port i login znajdziesz w panelu, w sekcji SFTP swojej usługi. Tam też włączasz powłokę, jeśli jeszcze jej nie masz. Logujesz się hasłem albo kluczem, działają oba sposoby. W kontenerze czekają git, rsync, tmux i sqlite3, więc kod pobierzesz wprost z repozytorium:

mkdir -p ~/apps && cd ~/apps
git clone ADRES_REPOZYTORIUM sklep
cd sklep
node -v            # 22.x, domyślna linia z obrazu
npm ci --omit=dev  # zależności produkcyjne z package-lock.json
npm run build      # jeśli projekt ma krok budowania

Chcesz budować inną linią niż domyślna? Binarki wszystkich linii leżą w /opt/nodejs: /opt/nodejs/24/bin/npm ci zainstaluje zależności pod Node 24. Proces uruchomi potem ta sama wersja, którą wybierzesz w panelu, więc paczki natywne (na przykład sharp czy bcrypt) zbudują się pod właściwe ABI.

Automatycznego budowania nie ma: nie reagujemy na wysłanie zmian do repozytorium i nie kompilujemy kodu za Ciebie. Każde wdrożenie to git pull, npm ci, ewentualnie npm run build i restart z panelu. Przy jednej aplikacji i kilku wdrożeniach w miesiącu to trzy, cztery polecenia w terminalu i każde widzisz na ekranie. Wdrażasz kilka razy dziennie? Zamknij te komendy w jednym skrypcie i uruchamiaj go przez SSH. Restart i tak klikasz w panelu.

Krok 3: dodanie aplikacji w panelu

W usłudze otwórz „Aplikacje” i kliknij „Dodaj aplikację”. Formularz ma pięć pól:

Pole Co wpisać
Nazwa małe litery, cyfry, myślnik. To także nazwa katalogu w ~/apps i nazwa procesu, na przykład sklep
Środowisko Node.js
Wersja 22 (zalecana), 20 albo 24
Domena jedna z domen usługi albo „Bez domeny (tylko wewnętrznie)”
Ścieżka / = cała domena albo podścieżka w rodzaju /api

Po zatwierdzeniu panel po kolei przydziela port, zapisuje plik środowiska z PORT i NODE_ENV=production, tworzy usługę systemd redicon-app@sklep, wpina ją w domenę i uruchamia proces. Potem czeka 5 sekund i sprawdza, czy proces się utrzymał. Jeśli nie, dodanie kończy się błędem, a w komunikacie dostajesz ogon logu aplikacji. To jedyny ekran, na którym dowiadujesz się, dlaczego Twój kod nie wstał, więc nie zasłaniamy go zielonym znaczkiem.

Najczęściej przy pierwszym dodaniu brakuje server.js w katalogu albo node_modules (pominięty krok 2). Zdarza się też błąd w kodzie przy starcie, a każdy z tych powodów widać w ogonie logu.

Krok 4: domena, HTTPS i websockety

Przed aplikacją stoi Apache w Twoim kontenerze. Przyjmuje ruch z domeny i przekazuje go na port aplikacji, a odwiedzający widzi zwykłą stronę pod https://. Certyfikat Let’s Encrypt jest ten sam, co dla stron PHP, i odnawia się sam. Wystawić go można dopiero wtedy, gdy domena wskazuje już na nas. Do tego czasu przeglądarka może ostrzegać o certyfikacie, a my przez pierwszą godzinę co pięć minut sprawdzamy, czy domena już do nas trafia.

Websockety przechodzą przez to samo wpięcie, bez osobnej konfiguracji.

Aplikacja może stać pod korzeniem domeny albo pod podścieżką. Przy /api serwer WWW zdejmuje prefiks, więc Twój kod widzi /x, a nie /api/x. Żądanie GET /api bez ukośnika dostaje przekierowanie na /api/. Na jednej domenie zmieści się kilka aplikacji, jeśli stoją na rozłącznych ścieżkach (/api i /panel). Aplikacja pod / zajmuje całą domenę i druga już się nie zmieści. Próba wpięcia nachodzącej ścieżki kończy się odmową z nazwą kolidującej aplikacji.

Co robi systemd, a czego nie robi

Aplikację pilnuje systemd, jak każdą inną usługę systemu. pm2 nie stawiamy, bo robiłby to samo, co system robi już bez niego. Co z tego wynika w dniu, w którym coś padnie:

Wstaje po restarcie serwera i po własnym upadku. Po awarii system podnosi proces z rosnącym odstępem: 2, 4, 8, 15, 30 i wreszcie 60 sekund między próbami. Odstęp rośnie celowo. Przyczyną bywa coś po naszej stronie, na przykład restart wspólnej bazy, i wtedy aplikacja ma wstać sama, gdy tylko baza wróci.

Trwała awaria kończy się stanem „nie działa”. Limit to 12 prób w oknie 15 minut. Potem system przestaje podnosić proces, panel pokazuje „nie działa” i ogon logu, a Ty naprawiasz kod i klikasz „Restartuj”. Ten przycisk robi więcej niż systemctl restart: zeruje licznik nieudanych startów i po 5 sekundach sprawdza, czy proces naprawdę stoi.

Pojedynczy proces ma sufit pamięci: 60% RAM kontenera. Reszta zostaje dla serwera WWW i PHP, żeby jedna aplikacja nie położyła strony stojącej obok niej na tym samym koncie. Liczby dla każdego pakietu podaje strona o hostingu Node.js.

Logi procesu masz w panelu. Przycisk „Logi” przy aplikacji pokazuje ostatnie linie wypisane przez proces (console.log, stack trace). Access log i error log Apache są gdzie indziej, na ekranie logów domeny. Potrzebujesz dłuższej historii? Pisz logi aplikacji także do własnego pliku w jej katalogu. To Twój katalog i Twoja rotacja.

Zmienne środowiskowe, klucze API i baza

Plik środowiska usługi (PORT, NODE_ENV) odtwarzamy przy każdej zmianie ustawień aplikacji, więc Twoje dopiski zniknęłyby z niego w najmniej spodziewanym momencie. Własne zmienne trzymaj w pliku swojej aplikacji, na przykład .env w katalogu ~/apps/sklep, wczytywanym na starcie przez dotenv albo process.loadEnvFile(). Katalog jest Twój i poza Tobą nikt do niego nie zagląda.

Bazę zakładasz w panelu, MariaDB albo PostgreSQL do wyboru przy tworzeniu. Z internetu baz nie wystawiamy. Aplikacja łączy się z nimi z Twojego kontenera, a Ty z przeglądarki, przez panel. Dane dostępowe wpisujesz do swojego .env.

Zmiana wersji Node

Przy aplikacji w panelu przycisk „Edytuj” otwiera okno „Zmień środowisko aplikacji”. Przełączasz w nim wersję, a proces startuje na nowo z nowym interpreterem. Paczki natywne w node_modules są skompilowane pod ABI konkretnej linii, więc po zmianie wykonaj przez SSH npm rebuild (albo rm -rf node_modules && /opt/nodejs/24/bin/npm ci). Panel przypomina o tym przed zatwierdzeniem.

Linia 20 zakończyła cykl wsparcia 30 kwietnia 2026 i nie dostaje już poprawek bezpieczeństwa. Trzymamy ją, żeby starsze aplikacje w ogóle wstały. Nową stawiaj na 22 albo 24.

Czego tu nie ma

  • Dockera. Nie uruchamiamy Twojego Dockerfile. Aplikacja startuje jako zwykły proces z katalogu, który wgrywasz.
  • Budowania po wysłaniu zmian do repozytorium. Instalacja i build to Twoje komendy przez SSH.
  • Memcached ani Redisa po TCP. Redisa włączasz w panelu, ale słucha wyłącznie na gnieździe uniksowym w Twoim kontenerze, nie na 127.0.0.1:6379. Biblioteka, która umie tylko TCP, się nie połączy. Memcached nie ma.
  • Wersji Node spoza obrazu w roli runtime. Inną linię zainstalujemy Ci na życzenie w katalogu domowym do pracy przez SSH, ale aplikacja prowadzona z panelu chodzi wyłącznie na wersjach z obrazu (20, 22, 24).

Lista kontrolna przed pierwszym uruchomieniem

  • pakiet z powłoką SSH (Standard albo wyżej), powłoka włączona w panelu,
  • kod w ~/apps/<nazwa>, plik startowy server.js,
  • nasłuch na process.env.PORT i 127.0.0.1,
  • npm ci wykonane tą samą linią Node, którą wybierzesz w panelu,
  • własne zmienne w pliku aplikacji, nie w pliku środowiska usługi,
  • domena podpięta do usługi i wskazująca na nas, jeśli aplikacja ma być publiczna.

Któryś punkt nie pasuje do Twojego projektu? Napisz do nas przed zamówieniem. Odpiszemy, czy i jak to u nas wstanie, a jeśli nie wstanie, powiemy to wprost.

Postaw aplikację tam, gdzie limity są zapisane w cenniku.

Aplikacje w Node.js i Pythonie wdrożysz od pakietu Standard: ma powłokę SSH, a proces trzyma przy życiu system.

Pytania do tego wpisu? Napisz na bok@isbre.pl. Wszystkie wpisy: blog.