7.0 KiB
TS3 monolith (Go)
Jedna aplikacja zastępująca stare sk.linuxiarz.pl i ts3stats.linuxiarz.pl.
Wygląd dashboardu (topbar + sidebar, karty, panele, jasny/ciemny motyw)
jest celowo spójny ze stylem PostfixAdminRS —
ten sam układ tokenów kolorów, te same komponenty UI.
Funkcjonalność
- wykrycie klienta TeamSpeak po IP widzianym przez HTTP i ServerQuery;
- utworzenie permanentnego kanału z nazwą, tematem, opcjonalnym hasłem,
limitem użytkowników (
channel_maxclients) i jakością kodeka (channel_codec_quality, 1–10); setclientchannelgroupdla wskazanegoclient_database_id;clientmovewskazanegocliddo nowego kanału;- dashboard statystyk: liczba online na żywo (auto-odświeżanie co 60 s przez
GET /stats/live), uptime/wersja/platforma serwera (serverinfo), wykresy RRD: 12h, 24h, 72h, tydzień, miesiąc, rok — w kolorystyce dopasowanej do motywu aplikacji (ciemne tło, akcentowa linia, watermark); - przełącznik jasny/ciemny motyw (zapamiętywany w
localStorage); - formularz pod
/embed/channel, przeznaczony do osadzenia na innej domenie.
Przy jednym kliencie pod danym IP wszystko działa automatycznie. Jeżeli kilka klientów TS3 ma ten sam publiczny IP (NAT), aplikacja prosi o wybór nicku i wysyła 6-cyfrowy kod prywatną wiadomością TS3. Dzięki temu nie przenosi przypadkowej osoby i nie nadaje jej Channel Admina.
Szybki development
cp .env.example .env # uzupełnij sekrety
make quick # najszybszy build (bez testów/trimpath) -> bin/ts3monolith
make dev # quick build + start z lokalnym .env
make test # go test ./...
make build # pełny build produkcyjny (testy + trimpath + bez symboli)
Uruchomienie — Docker
- Skopiuj
.env.exampledo.envi ustaw sekrety oraz dozwoloną domenę iframe. - Zachowaj
data/linuxiarz.rrd(kopia dotychczasowej bazy z archiwum) albo zainicjuj nową bazę — patrz sekcja RRD. - Zapewnij zapis do katalogu
datadla UID 10001:chown -R 10001:10001 data. - Uruchom:
docker compose up -d --build. - Reverse proxy kieruje HTTPS do
127.0.0.1:8080.
Uruchomienie — pakiet .deb + systemd
Alternatywa dla Dockera, zalecana na dedykowanym hoście Debian/Ubuntu:
make deb # scripts/build-deb.sh -> packages/ts3monolith_<wersja>_amd64.deb
sudo dpkg -i packages/ts3monolith_*.deb
sudo nano /etc/default/ts3monolith # APP_SECRET, TS_QUERY_USER, TS_QUERY_PASSWORD, ...
sudo -u ts3monolith /usr/lib/ts3monolith/init-rrd # tylko przy świeżej instalacji, bez starej bazy
sudo systemctl enable --now ts3monolith
scripts/build-deb.sh buduje wszystko w kontenerze Docker — dokładnie tak
samo jak odpowiadający skrypt w PostfixAdminRS — więc host nie potrzebuje
lokalnie zainstalowanego Go ani żadnych zależności poza samym Dockerem.
Wersja obrazu (golang:<wersja z go.mod>-bookworm) jest odczytywana z
go.mod, a sam moduł nie ma żadnych zewnętrznych zależności, więc build jest
w pełni offline po ściągnięciu obrazu. Wynikowy pakiet trafia do packages/.
Pakiet instaluje:
/usr/bin/ts3monolith— binarka;/etc/default/ts3monolith— zmienne środowiskowe (conffile);/lib/systemd/system/ts3monolith.service— jednostka z pełnym hardeningiem (ProtectSystem=strict,NoNewPrivileges,RestrictAddressFamilies,MemoryDenyWriteExecute,SystemCallFilter=@system-service, ...), takim samym duchem jak w PostfixAdminRS;/usr/lib/ts3monolith/init-rrd— jednorazowy skrypt tworzący świeżą bazę RRD z RRA pokrywającymi wszystkie zakresy wykresów (12h…rok), gdy nie ma archiwalnego pliku do skopiowania;- dedykowanego użytkownika systemowego
ts3monolith(bez loginu, bez home).
install.sh z korzenia repo zostaje jako prostszy, ręczny installer bez
budowania pakietu .deb (np. do szybkiego postawienia na hoście bez
uprawnień do dpkg).
Przykład iframe:
<iframe
src="https://app.example.org/embed/channel"
title="Utwórz kanał TeamSpeak"
loading="lazy"
referrerpolicy="no-referrer"
style="width:100%;min-height:620px;border:0">
</iframe>
FRAME_ANCESTORS musi zawierać origin strony nadrzędnej, np. https://www.example.org.
TeamSpeak ServerQuery
Najbezpieczniej uruchamiać aplikację na tym samym hoście lub w prywatnej sieci z TS3 i ustawić TS_QUERY_HOST=127.0.0.1/adres prywatny. Nie wystawiaj portu 10011 publicznie. Query powinien mieć tylko prawa potrzebne do: clientlist -ip -uid, channelcreate, setclientchannelgroup, clientmove, sendtextmessage, channeldelete (rollback), serverinfo (karty uptime/wersji na dashboardzie).
RRD
Aplikacja używa systemowego rrdtool, a nie biblioteki Go, więc istniejący plik RRD pozostaje bez migracji. Co 60 s liczona jest liczba klientów client_type=0 na wybranym virtual serverze i zapisywana do DS online. Błąd ServerQuery nie zapisuje sztucznego zera.
Świeża instalacja bez archiwalnej bazy: packaging/ts3monolith-init-rrd
(instalowany jako /usr/lib/ts3monolith/init-rrd w pakiecie .deb) tworzy
nową bazę rrdtool create z RRA pokrywającymi 12h/24h/72h/tydzień/miesiąc/rok
przy kroku 60 s — ten sam layout logiczny co istniejące wykresy aplikacji.
Wykresy renderowane są w kolorach dopasowanych do motywu dashboardu
(--panel/--field/--accent z internal/web/assets/app.css), z cienkim
wypełnieniem pod linią, watermarkiem z datą generacji i --slope-mode dla
gładszej linii. Każdy zakres jest renderowany dwukrotnie — <zakres>.png
(ciemna paleta) i <zakres>-light.png (jasna paleta) — a front-end
(internal/web/assets/app.js) przełącza src na właściwy wariant przy
zmianie motywu, więc wykresy zawsze dopasowane są do aktywnego trybu
jasny/ciemny.
Jeżeli docelowy serwer ma inną architekturę/endianness niż źródłowy x86_64 little-endian, przenieś RRD przez rrdtool dump/rrdtool restore zamiast kopiowania binarnego pliku.
Bezpieczeństwo / fingerprinting
- brak PHP, frameworków frontendowych, CDN i nagłówka
X-Powered-By; - standardowy
net/httpnie dodaje nagłówkaServer; - CSP z kontrolowanym
frame-ancestors, HSTS,nosniff, restrykcyjne Permissions-Policy,style-src/script-src 'self'(bez inline — cały CSS/JS w plikach statycznych); - nagłówki proxy są ufane wyłącznie z
TRUSTED_PROXIES; - stateless HMAC tokeny formularzy i klientów, sprawdzanie
Origin, limity request body i rate limiting; - sekrety tylko przez środowisko, brak danych dostępowych w repo;
- rollback kanału, jeśli nadanie grupy lub przeniesienie klienta się nie powiedzie;
- kontener non-root,
cap_drop: ALL,no-new-privileges, read-only root filesystem (Docker) albo analogiczny hardening jednostki systemd (pakiet.deb); - build z
-trimpathi usuniętymi symbolami/debug info.
Nie da się zagwarantować, że stos technologiczny będzie całkowicie nierozpoznawalny na podstawie zachowania sieci/TLS. Celem jest brak prostych bannerów, wersji i sygnatur frameworka.