Przejdź do treści
Blog

Kopia zapasowa serwera FiveM i bazy danych, z testem

mysqldump dla oxmysql, pliki serwera, szyfrowanie, cotygodniowy test przywracania i jak oddać graczowi ekwipunek bez cofania całego miasta.

Autor: Termi

9 min czytania
  • Backups
  • Database
  • oxmysql
Na tej stronie

Żeby zrobić kopię serwera FiveM, zrzuć bazę MySQL albo MariaDB, z którą łączy się oxmysql, poleceniem mysqldump --single-transaction, spakuj server.cfg, zasoby i txData, zaszyfruj jedno i drugie i skopiuj poza maszynę. Kopia liczy się dopiero wtedy, gdy ją przywrócisz, więc co tydzień wczytuj jedną do bazy testowej. Żeby oddać jednemu graczowi ekwipunek, przywróć kopię do tej bazy testowej i przenieś tylko jego wiersze.

Ten poradnik robi to wszystko ręcznie, darmowymi narzędziami, na Linuksie albo na Windowsie z Git Bash. Nic w nim nie wymaga FiveDocka. Na końcu to samo zrobione za ciebie, razem z Deploy Guard, który robi kopię przed każdym restartem.

Co musi trafić do kopii serwera FiveM

  • Baza danych. Postacie, pieniądze, ekwipunki, pojazdy, domy, wiadomości w telefonie: wszystko, co trzymają ESX, QBCore, Qbox i ox_inventory, jest tutaj. Zmienia się co minutę, więc potrzebuje najczęstszej kopii.
  • server.cfg. Kolejność zasobów, convary, uprawnienia, hasło do bazy i twój sv_licenseKey.
  • resources. Skrypty, mapy i pojazdy, razem z każdą zmianą w kupionych skryptach.
  • txData. Ustawienia txAdmina, admini i historia graczy.

Pomiń cache: FXServer odbuduje go przy następnym starcie, a często to największy folder na dysku. Logi też możesz pominąć.

Znajdź bazę, której używa oxmysql

oxmysql czyta połączenie z server.cfg:

server.cfg
set mysql_connection_string "mysql://fivem:[email protected]/fivem?charset=utf8mb4"

To użytkownik fivem, hasło secret, host 127.0.0.1 i baza fivem. Niektóre serwery używają starszej formy server=127.0.0.1;database=fivem;userid=fivem;password=secret, która zawiera te same cztery wartości.

Zrzuć bazę przez mysqldump

Zapisz dane logowania w pliku, który możesz czytać tylko ty, żeby hasło nie było widać na liście procesów ani w historii powłoki:

bash
cat > "$HOME/.fivem-backup.cnf" <<'EOF'
[client]
user=fivem
password=secret
host=127.0.0.1
EOF
chmod 600 "$HOME/.fivem-backup.cnf"

Potem zrzuć bazę, podczas gdy serwer dalej działa:

bash
mysqldump --defaults-extra-file="$HOME/.fivem-backup.cnf" \
  --single-transaction --quick --no-tablespaces \
  --default-character-set=utf8mb4 --hex-blob \
  fivem | gzip > "fivem-$(date +%F-%H%M).sql.gz"
  • --single-transaction czyta każdą tabelę InnoDB w jednym spójnym snapshocie, bez blokowania, więc gracze dalej grają, a pieniądze w users zgadzają się z przedmiotami w ox_inventory.
  • --quick przesyła wiersze strumieniem zamiast ładować całe tabele do pamięci, co ma znaczenie, gdy tabele logów i telefonu mają miliony wierszy.
  • --no-tablespaces omija błąd uprawnień na MySQL 8 (patrz błędy).
  • --default-character-set=utf8mb4 i --hex-blob zachowują emotki w imionach postaci i kolumny binarne.

Na MariaDB to samo polecenie nazywa się też mariadb-dump i ma te same opcje. Jeśli twoje skrypty używają procedur składowanych, dodaj --routines.

Sprawdź, czy masz tabele MyISAM

Snapshot obejmuje tylko tabele InnoDB. Tabela MyISAM jest czytana w trochę innym momencie niż reszta, więc kopia zrobiona w trakcie wymiany może mieć pieniądze sprzed niej i przedmiot po niej. ALTER TABLE nazwa ENGINE=InnoDB; przerabia jedną.

Zrób kopię plików serwera

bash
tar -czf "files-$(date +%F-%H%M).tar.gz" \
  --exclude='server-data/cache' \
  -C /home/fivem server-data txData

Ustaw -C na folder, w którym leżą server-data i txData. Na Windowsie tar jest w systemie od Windows 10 i przyjmuje te same opcje.

Zaszyfruj, zanim opuści maszynę

Zrzut bazy zawiera identyfikatory każdego gracza, a server.cfg hasło do bazy i twój klucz licencji. Każdy, kto dostanie kopię, przeczyta to wszystko albo uruchomi serwer na twoim kluczu. Szyfruj przez age kluczem publicznym: serwer może szyfrować kopie, ale nie może ich otworzyć, więc przejęty serwer nie oddaje własnych kopii.

Wygeneruj parę kluczy na swoim komputerze, nie na serwerze:

bash
age-keygen -o fivem-backup.key
# Public key: age1q9x...

Trzymaj fivem-backup.key w menedżerze haseł, a serwerowi daj tylko klucz publiczny, który zaczyna się od age1:

bash
age -r age1q9x... -o fivem-2026-10-15-0400.sql.gz.age fivem-2026-10-15-0400.sql.gz

Jeśli zgubisz klucz prywatny, przepadają z nim wszystkie kopie, które zaszyfrował. Trzymaj dwie kopie klucza, w dwóch różnych miejscach.

Trzymaj kopie poza serwerem

Kopia na tym samym dysku znika, gdy dysk padnie, gdy hosting zakończy umowę albo gdy ktoś wyczyści maszynę. Kopiuj każdą kopię do magazynu obiektów, np. Backblaze B2, Cloudflare R2 albo S3, przez rclone. Daj serwerowi klucz, który może wgrywać pliki, ale nie może ich usuwać, żeby ten, kto dostanie się na serwer, nie skasował też kopii.

Uruchamiaj to co noc

Wszystko powyżej w jednym skrypcie:

backup.sh
#!/usr/bin/env bash
set -euo pipefail

STAMP=$(date +%F-%H%M)
OUT=/var/backups/fivem
RECIPIENT=age1q9x...
mkdir -p "$OUT"

mysqldump --defaults-extra-file="$HOME/.fivem-backup.cnf" \
  --single-transaction --quick --no-tablespaces \
  --default-character-set=utf8mb4 --hex-blob \
  fivem | gzip | age -r "$RECIPIENT" > "$OUT/db-$STAMP.sql.gz.age"

tar -czf - --exclude='server-data/cache' -C /home/fivem server-data txData \
  | age -r "$RECIPIENT" > "$OUT/files-$STAMP.tar.gz.age"

rclone copy "$OUT" b2:my-city-backups --include '*.age'
find "$OUT" -name '*.age' -mtime +14 -delete

set -o pipefail ma większe znaczenie, niż się wydaje. Bez niego mysqldump | gzip kończy się sukcesem, kiedy tylko gzip się uda, więc złe hasło zostawia co noc plik 20-bajtowy i log, w którym wszystko działało. Z nim skrypt zatrzymuje się na pierwszym błędzie.

Uruchamiaj go codziennie o 04:00 przez crona:

crontab -e
0 4 * * * /home/fivem/backup.sh >> /var/log/fivem-backup.log 2>&1

Na Windowsie uruchamiaj backup.sh przez Git Bash z Harmonogramu zadań. Przed każdą aktualizacją frameworka albo skryptu ekwipunku zrób dodatkową kopię ręcznie.

Przetestuj przywracanie, inaczej nie masz kopii

Większość rollbacków zawodzi w noc, w którą są potrzebne: zrzut urwał się w połowie, hasło zmieniło się trzy miesiące temu, nikt nie zachował klucza prywatnego. Cotygodniowy test wyłapie wszystkie trzy. Rób go na maszynie, która ma klucz prywatny i MySQL albo MariaDB, np. na swoim komputerze albo serwerze testowym:

bash
age -d -i fivem-backup.key db-2026-10-15-0400.sql.gz.age | gunzip > restore.sql
tail -n 1 restore.sql
# -- Dump completed on 2026-10-15  4:00:03

mysql -e 'DROP DATABASE IF EXISTS restore_test; CREATE DATABASE restore_test'
mysql restore_test < restore.sql

Pełny zrzut kończy się linijką -- Dump completed. Jeśli jej brakuje, zrzut się urwał. Po imporcie porównaj kopię z serwerem na żywo. Na QBCore i Qbox użyj players zamiast users:

SQL
SELECT table_schema, COUNT(*) AS tables
FROM information_schema.tables
WHERE table_schema IN ('fivem', 'restore_test')
GROUP BY table_schema;

SELECT
  (SELECT COUNT(*) FROM fivem.users)        AS players_now,
  (SELECT COUNT(*) FROM restore_test.users) AS players_in_backup;

Ta sama liczba tabel i liczba graczy bliska dzisiejszej oznacza, że kopia jest cała. Żeby przetestować też pliki, rozpakuj archiwum obok kopii FXServera, skieruj go na restore_test i uruchom.

Cofnij cały serwer

Użyj tego po exploicie na duplikację, zepsutej ekonomii albo aktualizacji, która uszkodziła bazę. Każdy gracz straci to, co wydarzyło się od kopii, więc najpierw ich uprzedź.

  1. Zatrzymaj serwer w txAdminie. Nie restartuj go: framework zapisuje każdego gracza online z pamięci co jakiś czas i przy wyłączaniu, a to nadpisałoby przywróconą kopię.
  2. Zrób kopię zepsutego stanu, na wypadek gdyby przywracanie pogorszyło sprawę.
  3. Zaimportuj kopię sprzed początku problemu.
  4. Uruchom serwer.
bash
mysqldump --defaults-extra-file="$HOME/.fivem-backup.cnf" \
  --single-transaction --quick --no-tablespaces \
  --default-character-set=utf8mb4 --hex-blob \
  fivem | gzip > before-rollback.sql.gz

age -d -i fivem-backup.key db-2026-10-15-0400.sql.gz.age | gunzip | mysql fivem

Zrzut usuwa i tworzy na nowo każdą tabelę, którą zawiera. Tabela utworzona po kopii zostaje bez zmian.

Przywróć ekwipunek jednego gracza bez cofania wszystkich

Gracz stracił ekwipunek przez błąd albo cheater wyczyścił mu konto. Cofnięcie miasta kosztowałoby wszystkich innych dzień gry. Zamiast tego zaimportuj kopię do restore_test na tym samym serwerze bazy, jak w teście przywracania, i skopiuj z powrotem tylko wiersze tego gracza.

Najpierw znajdź jego identyfikator. W ESX to kolumna identifier w users, a z ox_inventory jego ekwipunek siedzi w tym samym wierszu. W QBCore i Qbox to citizenid w players. Potem wyrzuć gracza i nie wpuszczaj go, dopóki nie skończysz, bo framework przy następnym zapisie nadpisze przywrócone dane jego obecnym stanem.

ESX

SQL
SET FOREIGN_KEY_CHECKS = 0;
START TRANSACTION;

REPLACE INTO fivem.users
  SELECT * FROM restore_test.users WHERE identifier = 'char1:3f2a9c...';

DELETE FROM fivem.owned_vehicles WHERE owner = 'char1:3f2a9c...';
INSERT INTO fivem.owned_vehicles
  SELECT * FROM restore_test.owned_vehicles WHERE owner = 'char1:3f2a9c...';

COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

QBCore i Qbox

SQL
SET FOREIGN_KEY_CHECKS = 0;
START TRANSACTION;

REPLACE INTO fivem.players
  SELECT * FROM restore_test.players WHERE citizenid = 'KX81F2QD';

DELETE FROM fivem.player_vehicles WHERE citizenid = 'KX81F2QD';
INSERT INTO fivem.player_vehicles
  SELECT * FROM restore_test.player_vehicles WHERE citizenid = 'KX81F2QD';

COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

REPLACE nadpisuje wiersz gracza wierszem z kopii: pieniądze, ekwipunek i pozycję. Pojazdy są usuwane i wstawiane od nowa, więc auto kupione po kopii też znika. Jeśli auto zmieniło właściciela od czasu kopii, INSERT zatrzyma się na zduplikowanym kluczu, a transakcja zostawi wszystko bez zmian. Zdecyduj, kto je zatrzymuje, i uruchom ponownie.

Jeśli gracz handlował od czasu kopii, przywrócenie odda mu to, co już komuś przekazał, i przedmiot będzie istniał dwa razy. Sprawdź jego transakcje, zanim przywrócisz kogoś, kto twierdzi, że stracił wszystko.

Błędy, na które pewnie trafisz

Access denied; brak uprawnienia PROCESS

mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces pojawia się na MySQL 8.0.21 i nowszych. Dodaj --no-tablespaces. Baza FiveM nie ma tablespace’ów, które warto zrzucać.

Access denied przy LOCK TABLES

mysqldump: Got error: 1044: Access denied for user 'fivem'@'localhost' to database 'fivem' when using LOCK TABLES znaczy, że zrzut poszedł bez --single-transaction i próbował zablokować każdą tabelę. Dodaj tę opcję. To też dzięki niej zrzut nie zamraża serwera.

Nieznane porównanie utf8mb4_0900_ai_ci

ERROR 1273 (HY000) at line 25: Unknown collation: 'utf8mb4_0900_ai_ci' znaczy, że zrzut z MySQL 8 trafia do MariaDB, która nie zna tego porównania. Podmień je przed importem:

bash
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g' restore.sql

To samo, zrobione przez FiveDocka

Wszystko powyżej robi Time Machine FiveDocka z wnętrza twojego serwera, przez tego samego agenta, który obsługuje resztę FiveDocka. Nie ma skryptu do utrzymania ani crona, o którym można zapomnieć.

  • Szyfrowane twoim kluczem. Agent szyfruje każdą kopię na twojej maszynie kluczem zrobionym dla tego serwera i pokazanym ci raz. Nie możemy czytać twoich kopii, łącznie z nazwami plików, a wyciek server.cfg otwiera tylko kopie tego jednego serwera.
  • Spójne i przyrostowe. Każda tabela jest czytana w jednym spójnym snapshocie, a kopia mówi, które tabele są MyISAM. Wysyłane są tylko zmienione części, a usunięta kopia jest zablokowana przez 30 dni, więc nikt nie wyczyści twojej historii.
  • Testowane co tydzień. FiveDock przywraca kopię do bazy testowej na twoim własnym serwerze i oznacza ją jako przetestowaną, więc o zepsutej kopii dowiadujesz się tygodnie, zanim jej potrzebujesz.
  • Cofnij dokładnie to, co się zepsuło. Cały serwer, bazę, jedną tabelę, jeden zasób, jeden plik albo jednego gracza, z policzeniem, co się zmieni, zanim potwierdzisz, i kopią bezpieczeństwa najpierw. Odmówi przywrócenia gracza, który jest połączony, i przywrócenia bazy, gdy działa ESX, QBCore albo Qbox.
  • Deploy Guard. Kopia przed każdym restartem, werdykt dziesięć minut po nim, który wskazuje zasób, który narobił kłopotów, i jedno kliknięcie, żeby wrócić do stanu sprzed restartu.
  • Kopia, gdy psuje się ekonomia. Gdy odpali alert ekonomii, kopia powstaje w tej samej sekundzie, zanim szkody się rozejdą.

Każdy plan robi codzienną kopię. Przywracanie jednej tabeli albo jednego gracza, cotygodniowe testy, kopie co godzinę i Deploy Guard są w planie Metro. Cennik ma pełną listę, a funkcje pokazują resztę Time Machine.

FAQ

Jak często robić kopię serwera FiveM?

Kopię bazy rób co najmniej raz dziennie i dodatkowo ręcznie przed każdą aktualizacją frameworka albo ekwipunku. Jeśli ekonomia jest ruchliwa, rób ją co godzinę: exploit na duplikację znaleziony o 22:00 przy kopii z 04:00 kosztuje każdego gracza 18 godzin.

Czy mogę robić kopię bazy, gdy serwer działa?

Tak. mysqldump --single-transaction czyta tabele InnoDB w jednym spójnym snapshocie bez blokowania, więc gracze niczego nie zauważą. Poza snapshotem zostają tylko tabele MyISAM.

Czy txAdmin robi kopię mojej bazy?

Nie. txAdmin uruchamia, restartuje i pilnuje serwera, ale nie zrzuca twojej bazy MySQL ani MariaDB. Użyj mysqldump według harmonogramu albo narzędzia, które zrobi to za ciebie.

Jak cofnąć serwer FiveM po exploicie na duplikację?

Zatrzymaj serwer w txAdminie, zrób kopię obecnego stanu, zaimportuj ostatnią kopię sprzed exploita i uruchom serwer. Jeśli skorzystało tylko kilku graczy, przywróć albo wyczyść ich wiersze, zamiast cofać wszystkich.

Jak przywrócić ekwipunek jednego gracza?

Zaimportuj kopię do osobnej bazy na tym samym serwerze, trzymaj gracza offline i skopiuj jego wiersze z users (ESX) albo players (QBCore i Qbox), razem z jego pojazdami, do bazy na żywo w jednej transakcji.

Gdzie jest baza, której używa oxmysql?

W server.cfg, w linijce set mysql_connection_string. Są w niej użytkownik, hasło, host i nazwa bazy, których potrzebuje mysqldump.

Wszystkie artykuły