Files
servicedesk/install.md
Kacper 13a758779d
Some checks failed
Build and push image / build (push) Failing after 3m17s
v1.0.1
Documentation overhaul (TESTING/CONTRIBUTING/ARCHITECTURE/SECURITY/CLAUDE.md,
CHANGELOG.md, drop unmaintained src/README.md) plus CI-built Docker images:
Gitea Actions now builds and pushes the servicedesk image to the Gitea
container registry on Dockerfile changes, and compose.yaml pulls that image
instead of building locally. No application behavior changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 01:29:43 +02:00

14 KiB

Instalacja / wdrożenie

Dwa sposoby uruchomienia Servicedesk: przez Docker Compose (tak jak działa ten projekt obecnie) albo bezpośrednio na serwerze z Apache/Nginx + PHP-FPM, bez kontenerów.

Zanim zaczniesz, ważne rozróżnienie — w projekcie są dwa różne pliki .env:

Plik Do czego służy
.env (w katalogu głównym repo, obok compose.yaml) Zmienne dla Docker Compose — hasła do MariaDB, nazwa hosta dla Traefika. Czyta go compose.yaml, nie czyta go Laravel.
src/.env (w katalogu aplikacji Laravel) Cała konfiguracja aplikacji — połączenie z bazą, adres URL, klucz szyfrowania, LDAP, SMTP, itd. Czyta go wyłącznie Laravel.

Oba istnieją niezależnie od siebie (nawet w wersji Docker) — wartości DB_* w src/.env muszą odpowiadać wartościom MYSQL_* z głównego .env, ale to dwa osobne pliki, w dwóch różnych miejscach.


1. Wdrożenie przez Docker Compose

Wymagania

  • Docker + wtyczka docker compose.
  • Zewnętrzna sieć Docker traefik_public, jeśli używasz Traefika tak jak w compose.yaml (docker network create traefik_public, jeśli jeszcze nie istnieje). Bez Traefika trzeba samodzielnie zmapować porty serwisu servicedesk na hosta (ports: ["8080:80"]) i obsłużyć TLS inaczej (patrz sekcja 2 niżej, w razie potrzeby reverse-proxy przed kontenerem).

1.1. Pliki compose.yaml i .env w katalogu głównym

Oba są celowo .gitignore'owane (podobnie jak src/.env) — kopiujesz je z szablonów przy pierwszym wdrożeniu, a potem edytujesz lokalnie:

cp compose.yaml.example compose.yaml
cp .env.example .env

.env:

HOSTNAME=servicedesk.twoja-domena.pl
MYSQL_ROOT_PASSWORD=wygeneruj-silne-haslo
MYSQL_DATABASE=servicedesk
MYSQL_USER=servicedesk
MYSQL_PASSWORD=wygeneruj-inne-silne-haslo
# IMAGE_TAG=latest
  • HOSTNAME — domena, pod którą Traefik wystawi aplikację (trafia do reguły Host(...) w etykietach servicedesk).
  • MYSQL_* — dane bazy dla kontenera mariadb; MYSQL_USER/MYSQL_PASSWORD to te same wartości, które za chwilę wpiszesz do src/.env jako DB_USERNAME/ DB_PASSWORD.
  • IMAGE_TAG — który tag obrazu servicedesk wdrożyć (patrz sekcja 1.3a); domyślnie latest, jeśli zmienna nie jest ustawiona.

1.2. Plik src/.env (Laravel)

cp src/.env.example src/.env

Kluczowe wartości do zmiany względem .env.example:

APP_NAME=Servicedesk
APP_ENV=production
APP_DEBUG=false
APP_URL=https://servicedesk.twoja-domena.pl   # to samo co HOSTNAME wyżej, z https://
APP_LOCALE=pl
APP_FALLBACK_LOCALE=pl

AUTHOR_CONTACT=helpdesk@twoja-domena.pl        # widoczne w Admin > O aplikacji
VERSION=1.0.0                                   # rezerwa na przyszłość, jeszcze nigdzie nie wyświetlane

DB_CONNECTION=mysql
DB_HOST=mariadb                                 # nazwa serwisu z compose.yaml, NIE 127.0.0.1
DB_PORT=3306
DB_DATABASE=servicedesk                         # = MYSQL_DATABASE z głównego .env
DB_USERNAME=servicedesk                         # = MYSQL_USER
DB_PASSWORD=wygeneruj-inne-silne-haslo           # = MYSQL_PASSWORD

SESSION_DRIVER=database
QUEUE_CONNECTION=database

APP_KEY wygenerujesz komendą artisan (krok 1.4) — zostaw puste w pliku.

LDAP_* i MAIL_* w src/.env są tylko wartościami startowymi/awaryjnymi. Docelowo LDAP i SMTP konfiguruje się wygodniej z poziomu Admin > Konfiguracja w samej aplikacji (patrz ramka ostrzegawcza w kroku 1.6) — ale jeśli chcesz mieć sensowny fallback zanim ktokolwiek się zaloguje do panelu admina, warto je od razu uzupełnić:

LDAP_HOST=ldap.twoja-domena.pl
LDAP_USERNAME=cn=admin,dc=twoja-domena,dc=pl
LDAP_PASSWORD=haslo-bind-ldap
LDAP_BASE_DN=dc=twoja-domena,dc=pl
LDAP_PORT=389

MAIL_MAILER=smtp
MAIL_HOST=smtp.twoja-domena.pl
MAIL_PORT=587
MAIL_USERNAME=noreply@twoja-domena.pl
MAIL_PASSWORD=haslo-smtp
MAIL_FROM_ADDRESS=noreply@twoja-domena.pl
MAIL_FROM_NAME="${APP_NAME}"

1.3. Start kontenerów

Obraz servicedesk nie jest budowany lokalniecompose.yaml odwołuje się do obrazu zbudowanego przez CI i wypchniętego do rejestru kontenerów Gitea (patrz 1.3a). Uruchomienie stacka to więc zawsze:

docker compose pull
docker compose up -d

Przy zwykłych zmianach w kodzie PHP/Blade nic więcej nie trzeba robić — źródło jest zamontowane z ./src, Laravel odświeża się natychmiast. docker compose pull uruchamiaj ponownie tylko wtedy, gdy chcesz podnieść nowszy tag obrazu (np. po zmianie w Dockerfile i przebudowie przez CI).

1.3a. Automatyczne budowanie obrazu (CI, Gitea Actions)

.gitea/workflows/build.yml buduje i wypycha obraz do wbudowanego rejestru kontenerów Gitea (gitea.kzbikowski.pl/kzbkowski/servicedesk) po każdym pushu na main, który zmienia Dockerfile (celowo nie odpala się na zwykłe zmiany w src/ — obraz nie zawiera kodu aplikacji, tylko PHP/Apache/rozszerzenia, więc przebudowa dla samego kodu byłaby marnowaniem czasu CI). Wypycha dwa tagi: latest i <sha commita>.

To tylko build + push — świadomie bez auto-deployu na produkcję. Po tym jak CI skończy, wdrożenie nowego obrazu na serwerze wciąż jest ręcznym krokiem:

cd /ścieżka/do/repo
docker compose pull
docker compose up -d

Zanim to zadziała po raz pierwszy, potrzebne jest jednorazowe zalogowanie hosta produkcyjnego do rejestru Gitea (żeby docker compose pull miał czym autoryzować pobranie obrazu, jeśli repozytorium/paczka nie są publiczne):

docker login gitea.kzbikowski.pl -u <twoja-nazwa-uzytkownika>

Jeśli to zupełnie pierwsze wdrożenie (rejestr jeszcze nie ma żadnego wypchniętego obrazu servicedesk) — poczekaj, aż workflow CI przejdzie choć raz (np. przez push/PR zmieniający Dockerfile, albo ręczne odpalenie z zakładki Actions w Gitea), zanim spróbujesz docker compose pull na serwerze.

1.4. Instalacja aplikacji wewnątrz kontenera

docker compose exec servicedesk composer install --no-dev --optimize-autoloader
docker compose exec servicedesk php artisan key:generate
docker compose exec servicedesk php artisan migrate --seed
docker compose exec servicedesk php artisan storage:link

migrate --seed (bez --fresh) na pustej bazie utworzy wszystkie tabele i wypełni dane referencyjne: kategorie/podkategorie, pola dodatkowe, statusy, priorytety/SLA, zespoły, szybkie akcje, szablony odpowiedzi/e-mail, branding oraz jedno konto lokalne admin@example.com / admin — zmień jego hasło od razu po pierwszym zalogowaniu (Admin > Użytkownicy).

1.5. Zbudowanie zasobów front-endowych (CSS/Tailwind)

Ani host, ani kontener servicedesk nie mają zainstalowanego Node.js — buduj przez jednorazowy kontener node:22 zamiast dorzucać Node do obrazu aplikacji:

cd /ścieżka/do/repo
docker run --rm -v "$(pwd)/src":/app -w /app node:22 npm ci
docker run --rm -v "$(pwd)/src":/app -w /app node:22 npm run build

Powtarzaj drugi krok po każdej zmianie w resources/css/ lub resources/js/.

1.6. Zadanie cykliczne (SLA) i kolejka

routes/console.php planuje tickets:check-sla-breaches co 15 minut, ale obraz Dockera nie ma wbudowanego cron/supervisora — bez dodatkowego kroku to zadanie nigdy się nie uruchomi. Najprościej dodać wpis crona na hoście:

* * * * * cd /ścieżka/do/repo && docker compose exec -T servicedesk php artisan schedule:run >> /dev/null 2>&1

Powiadomienia e-mail wysyłają się synchronicznie (nie trafiają do kolejki), więc php artisan queue:work nie jest obowiązkowy — QUEUE_CONNECTION=database w .env wystarcza jako bezpieczny domyślny driver, gdyby coś w przyszłości zaczęło kolejkować zadania.

⚠️ Ważne: LDAP/SMTP z panelu Admina nadpisują .env w locie

AppServiceProvider na starcie żądania sprawdza tabelę settings — jeśli w Admin > Konfiguracja pole host LDAP albo SMTP włączony + host jest ustawione, te wartości wygrywają z .env, bez potrzeby restartu czy redeployu.

Po świeżym migrate --seed te pola zawierają przykładowe placeholdery (ldap.example.com, smtp.example.com, changeme-*-password) — to znaczy, że zaraz po instalacji LDAP/SMTP faktycznie próbują łączyć się z tymi fałszywymi adresami, nawet jeśli w .env wpisałeś prawdziwe dane! Zanim oddasz system do użytku:

  1. Zaloguj się lokalnym kontem admin@example.com / admin.
  2. Wejdź w Admin > Konfiguracja i wpisz prawdziwe dane LDAP/SMTP (albo wyczyść pole hosta LDAP, żeby wrócić do wartości z .env).
  3. Użyj przycisków „Testuj połączenie” przy obu sekcjach, zanim zaczniesz polegać na logowaniu przez katalog.

2. Wdrożenie bezpośrednio na serwerze (Apache/Nginx, bez Dockera)

Wymagania

  • PHP 8.3+ z rozszerzeniami: curl, mysqli, pdo_mysql, ldap, zip, mbstring, openssl, tokenizer, xml, ctype, bcmath, fileinfo.
  • Composer 2.
  • MariaDB/MySQL (osobny serwer lub lokalny).
  • Node.js 20+ — tylko do jednorazowej (lub przy update'ach) budowy zasobów Tailwind/Vite; niepotrzebny w runtime.
  • Apache z mod_rewrite (+ mod_ssl) lub Nginx + PHP-FPM.

2.1. Pobranie kodu i zależności

cd /var/www
git clone <adres-repo> servicedesk
cd servicedesk/src
composer install --no-dev --optimize-autoloader

2.2. Konfiguracja .env

cp .env.example .env

Te same zmienne co w sekcji 1.2, z jedną różnicą — DB_HOST wskazuje na prawdziwy adres serwera bazy, nie na nazwę serwisu Compose:

APP_NAME=Servicedesk
APP_ENV=production
APP_DEBUG=false
APP_URL=https://servicedesk.twoja-domena.pl
APP_LOCALE=pl
APP_FALLBACK_LOCALE=pl

AUTHOR_CONTACT=helpdesk@twoja-domena.pl
VERSION=1.0.0

DB_CONNECTION=mysql
DB_HOST=127.0.0.1        # albo adres IP/hostname prawdziwego serwera DB
DB_PORT=3306
DB_DATABASE=servicedesk
DB_USERNAME=servicedesk
DB_PASSWORD=wygeneruj-silne-haslo

SESSION_DRIVER=database
QUEUE_CONNECTION=database

Uzupełnij też LDAP_*/MAIL_* jak w sekcji 1.2 (to samo ostrzeżenie o Admin > Konfiguracja nadpisującym te wartości w locie dotyczy tu identycznie).

php artisan key:generate
php artisan migrate --seed
php artisan storage:link

2.3. Budowa zasobów

npm ci
npm run build

(Na maszynie bez Node.js zbuduj public/build/ gdzie indziej i skopiuj cały katalog — to jedyne, co Vite generuje poza źródłem.)

2.4. Uprawnienia plików

chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache

(Zmień www-data na użytkownika, pod którym faktycznie działa Apache/PHP-FPM w Twojej dystrybucji, np. apache na RHEL/CentOS.)

2.5. Konfiguracja serwera WWW

DocumentRoot musi wskazywać na public/, nigdy na katalog główny aplikacji.

Apache (/etc/apache2/sites-available/servicedesk.conf):

<VirtualHost *:443>
    ServerName servicedesk.twoja-domena.pl
    DocumentRoot /var/www/servicedesk/src/public

    <Directory /var/www/servicedesk/src/public>
        AllowOverride All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile      /etc/ssl/certs/servicedesk.crt
    SSLCertificateKeyFile   /etc/ssl/private/servicedesk.key

    ErrorLog  ${APACHE_LOG_DIR}/servicedesk-error.log
    CustomLog ${APACHE_LOG_DIR}/servicedesk-access.log combined
</VirtualHost>
a2enmod rewrite ssl
a2ensite servicedesk
systemctl reload apache2

Jeśli kiedykolwiek dodasz własny katalog public/icons/ — nie rób tego. Stockowy moduł mod_alias Apache definiuje Alias /icons/ "/usr/share/apache2/icons/" (FancyIndexing), który po cichu przechwytuje /icons/* przed dotarciem do Laravela. Ten projekt celowo używa public/pwa-icons/ z tego właśnie powodu.

Nginx (+ PHP-FPM):

server {
    listen 443 ssl http2;
    server_name servicedesk.twoja-domena.pl;
    root /var/www/servicedesk/src/public;

    ssl_certificate     /etc/ssl/certs/servicedesk.crt;
    ssl_certificate_key /etc/ssl/private/servicedesk.key;

    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

2.6. Zadanie cykliczne (SLA) i kolejka

Crontab użytkownika, pod którym stoi aplikacja (np. www-data):

* * * * * cd /var/www/servicedesk/src && php artisan schedule:run >> /dev/null 2>&1

Jak w wersji Docker — kolejka (php artisan queue:work) nie jest obowiązkowa, skoro powiadomienia wysyłają się synchronicznie; zostaw QUEUE_CONNECTION=database jako bezpieczny domyślny driver na przyszłość.

2.7. Pierwsze logowanie i dalsza konfiguracja

Identycznie jak w kroku 1.6 — zaloguj się admin@example.com / admin, zmień hasło, uzupełnij prawdziwe LDAP/SMTP w Admin > Konfiguracja (placeholdery z seeda inaczej realnie próbują łączyć się z fałszywymi adresami), przetestuj oba połączenia przyciskiem „Testuj połączenie”.

2.8. Aktualizacje (bez przestoju)

cd /var/www/servicedesk/src
git pull
composer install --no-dev --optimize-autoloader
php artisan migrate --force
npm ci && npm run build
php artisan config:clear   # tylko jeśli wcześniej użyto config:cache

Nie ma potrzeby restartu Apache/PHP-FPM dla samych zmian w PHP/Blade — restart przyda się tylko po zmianie w .env lub konfiguracji samego serwera WWW.