Some checks failed
Build and push image / build (push) Failing after 3m17s
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>
403 lines
14 KiB
Markdown
403 lines
14 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
cp compose.yaml.example compose.yaml
|
|
cp .env.example .env
|
|
```
|
|
|
|
`.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)
|
|
|
|
```bash
|
|
cp src/.env.example src/.env
|
|
```
|
|
|
|
Kluczowe wartości do zmiany względem `.env.example`:
|
|
|
|
```env
|
|
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ć:
|
|
|
|
```env
|
|
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 lokalnie** — `compose.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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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):
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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**:
|
|
|
|
```cron
|
|
* * * * * 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
|
|
|
|
```bash
|
|
cd /var/www
|
|
git clone <adres-repo> servicedesk
|
|
cd servicedesk/src
|
|
composer install --no-dev --optimize-autoloader
|
|
```
|
|
|
|
### 2.2. Konfiguracja `.env`
|
|
|
|
```bash
|
|
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:
|
|
|
|
```env
|
|
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).
|
|
|
|
```bash
|
|
php artisan key:generate
|
|
php artisan migrate --seed
|
|
php artisan storage:link
|
|
```
|
|
|
|
### 2.3. Budowa zasobów
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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`):
|
|
|
|
```apache
|
|
<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>
|
|
```
|
|
|
|
```bash
|
|
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):
|
|
|
|
```nginx
|
|
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`):
|
|
|
|
```cron
|
|
* * * * * 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)
|
|
|
|
```bash
|
|
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.
|