Before you buy or install a FiveM script, test it like a QA lead: run it in an isolated Docker “Test City”, work through the acceptance checklist, score the risk from 0-100, and vet the vendor before money changes hands. This guide gives server owners and developers the full workflow — a copy-paste FXServer + MariaDB docker compose stack, resmon performance limits, security checks, and a maintenance playbook for after you ship.
TL;DR
- Opstarten Teststad (Docker) om elk script veilig te isoleren en te benchmarken.
- Voer de Acceptatielijst voordat er een cent van eigenaar wisselt.
- Gebruik de Risicoscore (0–100) om te beslissen verzenden/houden/afwijzen.
- Controleer verkopers met de Leveranciersrubriek (sla dit niet over).
- Als je koopt, geef dan de voorkeur aan gerenommeerde winkels — zie onze keuzes: Beste Tebex Winkels.
Deel 1 — “Teststad” (Docker) voor veilige, herhaalbare scriptkwaliteitscontrole
Wat je krijgt
- Gecontaineriseerde FXServer + MariaDB (+ Adminer)
- Schoon server.cfg met
oxmysqlen basisbronnen - Bind-gemonteerd
resources/customwaar je het te testen script plaatst - Deterministische netwerknamen/poorten voor eenvoudige DB-strings
Download test-city.zip (Github)
Hoe te gebruiken:
- Uitpakken →
cd test-city - Kopiëren
.env.examplenaar.enven stel je inLICENSE_KEY(en DB-gegevens als je wilt). - Plaats
oxmysqlinserver-data/resources/[standalone]/oxmysql/. - Plaats het te testen script in
server-data/resources/custom/<scriptname>/en voeg toeensure <scriptname>naarserver.cfg. docker compose build && docker compose up -d→ verbind via Direct Connect metlocalhost:30120.
Vereisten: Docker + Docker Compose, een cfx-licentiesleutel en een
oxmysqlresource kopie (plaats inserver-data/resources/[standalone]/oxmysql).
Mapindeling
test-city/ ├─ docker-compose.yml ├─ fxserver/ │ ├─ Dockerfile │ └─ entrypoint.sh ├─ server-data/ │ ├─ server.cfg │ └─ resources/ │ ├─ [standalone]/oxmysql/ # place oxmysql here │ └─ custom/ # put the script under test here (e.g., myscript/) └─ .env
.env (voorbeeld)
LICENSE_KEY=changeme_cfx_license_key MYSQL_DATABASE=fivem MYSQL_USER=fivem MYSQL_PASSWORD=fivempw MYSQL_ROOT_PASSWORD=rootpw FX_ARTIFACT_URL=https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/LATEST.tar.xz # Tip: replace with a specific artifact URL you trust for reproducibility.
docker-compose.yml
version: "3.9"
networks:
testcity:
volumes:
db_data:
services:
db:
image: mariadb:10.11
restart: unless-stopped
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
command: >
--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
--innodb_buffer_pool_size=256M
volumes:
- db_data:/var/lib/mysql
networks: [testcity]
adminer:
image: adminer:4
restart: unless-stopped
ports:
- "8080:8080"
networks: [testcity]
depends_on: [db]
fxserver:
build:
context: ./fxserver
args:
FX_ARTIFACT_URL: ${FX_ARTIFACT_URL}
restart: unless-stopped
environment:
LICENSE_KEY: ${LICENSE_KEY}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
depends_on: [db]
networks: [testcity]
ports:
- "30120:30120/udp"
- "30120:30120/tcp"
- "40120:40120/tcp" # txAdmin (optional)
volumes:
- ./server-data:/opt/fivem/server-data
fxserver/Dockerfile
FROM debian:bookworm-slim ARG FX_ARTIFACT_URL ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends xz-utils curl ca-certificates tini bash && rm -rf /var/lib/apt/lists/* # Fetch & extract FXServer artifact (URL provided via build-arg) RUN mkdir -p /opt/fivem && curl -fsSL "$FX_ARTIFACT_URL" -o /opt/fivem/fx.tar.xz && tar -xJf /opt/fivem/fx.tar.xz -C /opt/fivem && rm -f /opt/fivem/fx.tar.xz # Non-root RUN useradd -ms /bin/bash fivem USER fivem WORKDIR /opt/fivem COPY --chown=fivem:fivem ../server-data /opt/fivem/server-data COPY --chown=fivem:fivem entrypoint.sh /entrypoint.sh ENTRYPOINT ["/usr/bin/tini","--"] CMD ["/bin/bash","/entrypoint.sh"]
fxserver/entrypoint.sh
#!/usr/bin/env bash set -euo pipefail # Provide DB string for oxmysql via server.cfg (already set there), # just ensure the DB is reachable before boot to avoid spam errors. echo "Waiting for database..." until nc -z db 3306; do sleep 1; done echo "DB ready." # Run FXServer with our server.cfg # Most Linux artifacts ship a run.sh in the artifact root. exec bash /opt/fivem/run.sh +exec /opt/fivem/server-data/server.cfg
Als je artifact een ander launcher-pad gebruikt, pas dan de laatste regel aan (bijv.,
/opt/fivem/alpine/opt/cfx-server/run.sh).
server-data/server.cfg (lean, test-klaar)
# ---------- Identity ---------- sv_licenseKey "%LICENSE_KEY%" # injected by env in entrypoint command or replace manually sv_hostname "Test City — Script QA" sets tags "qa,testing,fivemx" sv_maxclients 2 onesync on sv_scriptHookAllowed 0 sv_enforceGameBuild 3095 # ---------- Networking ---------- endpoint_add_tcp "0.0.0.0:30120" endpoint_add_udp "0.0.0.0:30120" # ---------- Database (oxmysql) ---------- set mysql_connection_string "mysql://%MYSQL_USER%:%MYSQL_PASSWORD%@db:3306/%MYSQL_DATABASE%?charset=utf8mb4" # ---------- Core / Base resources ---------- ensure mapmanager ensure chat ensure spawnmanager ensure sessionmanager ensure hardcap ensure baseevents # ---------- Datastore ---------- ensure oxmysql # ---------- Under test ---------- # Drop your script folder into resources/custom/<scriptname> and enable here: # ensure myscript # ---------- QA helpers ---------- # Verbose logging in dev setr con_minSeverity info # Enable txAdmin panel (optional) setr txAdminPort 40120
Schakel je script in: kopieer het naar
server-data/resources/custom/myscript/en voeg toeensure myscriptnaar het onderste blok.
Voer het uit
cd test-city docker compose build docker compose up -d # Adminer at http://localhost:8080 (server: db, user: fivem, pass: fivempw) # Connect FiveM client → Direct Connect: your-docker-host:30120
Deel 2 — Scriptacceptatiecontrolelijst (Niet Overslaan)
Gebruik dit elke keer. Kopieer naar je tracker en vink items af.
A. Pre-flight (vóór installatie)
- Brontype: Open source / gedeeltelijk open / escrow-only.
- Afhankelijkheden vermeld: framework (ESX/QBCore/QBOX),
ox_lib,oxmysql,PolyZone, enz. toe. - fxmanifest.lua:
lua54 'yes', correctgame 'gta5',fx_versionniet oud. - Docs: installatiestappen, configuratievoorbeelden, machtigingen, lokalisaties, bekende conflicten.
- Licentie\/Algemene voorwaarden: gebruiksrechten, restitutiebeleid, updates, ondersteuningskanaal.
B. Installeerbaarheid
- Geen consolefouten bij
ensure: nul stacktraces of 'asset missing' spam. - Nee
deprecated nativesspam. - Config laadt schoon: geen JSON\/Lua syntaxfouten.
- DB-migraties: tabellen eenmalig aanmaken; herstarts passen niet opnieuw toe of breken niet.
C. Functioneel
- Core flows werken: happy path getest (bijv. aankoop, job flow, crafting).
- Randgevallen: verkeerde invoer, ontbrekende perms, hoeveelheden buiten bereik.
- Lokalisatie: geen hard-coded strings als lokalisaties zijn beloofd.
- Machtigingen: staff\/admin commando's afgeschermd; geen vrije toegang client-side.
D. Prestaties (client & server)
resmon: inactief ≤ 0.10ms, actief ≤ 0.50ms (client).- Server tick health: geen lange haperingen bij normaal gebruik.
- DB-queries: geen strakke loops; prepared statements gebruikt; minimale N+1.
E. Beveiliging
- Server-side validatie: elke server event valideert
source, permissies en invoertypen. - Geen vertrouwen in client: geld/inventaris veranderingen alleen vanuit serverlogica.
- Geen eval/
loadstring/remote code patronen. - Anti-misbruik: rate limits/throttles op spammy endpoints.
- Escrow-integriteit: geen backdoors in niet-versleutelde configuratieladers.
Goed event patroon (voorbeeld):
RegisterNetEvent('myscript:buy', function(item, amount)
local src = source
if type(item) ~= 'string' or type(amount) ~= 'number' or amount < 1 then return end
if not HasPermission(src, 'shop.buy') then return end
local xPlayer = GetPlayer(src) -- framework adapter
if not xPlayer then return end
-- validate price server-side, check inventory limits, do DB in a transaction
end)
F. Compatibiliteit & Netheid
- Framework adapters aanwezig (ESX/QBCore/QBOX) of duidelijk niet ondersteund verklaard.
- Geen globals lekkage, unieke gebeurtenisnamen, geen aannames over resourcenaam.
- Opschonen bij verwijderen: het verwijderen van de resource breekt anderen niet.
Deel 3 — Kwantitatief Risicoscoresysteem (0–100)
Gebruik dit om te beslissen “verzenden/vasthouden/afwijzen”. Lager is beter.
| Factor | Gewicht | Hoe te scoren (0=goed → 5=slecht) |
|---|---|---|
| Prestaties | 0.20 | resmon idle: 0=≤0.10ms, 1=≤0.20, 3=≤0.50, 5=>0.50; spikes voegen +1 toe |
| Beveiliging | 0.25 | 0=alle server-geverifieerde + snelheidslimieten; 3=enkele hiaten; 5=vertrouwt client / onveilige gebeurtenissen |
| Stabiliteit | 0.15 | 0=geen fouten; 3=af en toe waarschuwingen; 5=frequente fouten/haperingen |
| Compatibiliteit | 0.10 | 0=adapters/tests; 3=slechts één framework; 5=breekt veelvoorkomende afhankelijkheden |
| Onderhoudbaarheid | 0.10 | 0=docs/changelog/semantische versies; 5=geen docs/verlaten |
| Toeleveringsketen/Leverancier | 0.20 | 0=gerenommeerd, geschiedenis, terugbetalingen; 5=onbekend, geen beleid |
Formule
RiskScore = 100 * Σ(weight_i * (score_i / 5))
Bands & Acties
- 0–24 (Laag): Verzenden naar staging, monitoren.
- 25–49 (Gemiddeld): Reparaties vereist voor livegang.
- 50–74 (Hoog): Vasthouden; leverancierspatches aanvragen of vervangen.
- 75–100 (Kritiek): Afwijzen.
Voorbeeld
- Perf=1, Sec=3, Stability=1, Compat=1, Maint=2, Vendor=1
- Risico = 100*(.2*.2 + .25*.6 + .15*.2 + .1*.2 + .1*.4 + .2*.2) = 34 → Gemiddeld
Deel 4 — Leveranciersbeoordelingsrubriek (beoordeel elk 0-5, hoger is beter)
| Criterion | Wat “goed” eruitziet | Notities |
|---|---|---|
| Identiteit & Track Record | Duidelijk merk, actieve jaren, consistente gebruikersnaam | Vermijd wegwerp winkels |
| Documentatie | Installatie + configuratie + permissies + probleemoplossing | Screenshots/gifs helpen |
| Update Cadans | Wijzigingslogboek, semantische versies, recente commits/releases | Per kwartaal+ is prima |
| Kwaliteit van ondersteuning | Ticket/Discord SLA's, reproduceerbare fixes, niet alleen “herstarten” | Voorbeeld reacties |
| Transparantie van problemen | Publieke bekende problemen & roadmap | Eerlijkheid > perfectie |
| Duidelijkheid over restitutie/algemene voorwaarden | Restitutieperiode, voorwaarden, licentievoorwaarden | Geen donkere patronen |
| Testbewijs | Staging video, prestatie metrics, framework lijst | Nog beter: demo server |
| Beveiligingshygiëne | Vermeldt server-side controles, geen gevoelige sleutels, geen eval | Vraag naar audits |
| Compatibiliteitsbeleid | ESX/QBCore/QBOX vermeld, adapters, versie matrix | Ondersteunde builds van de staat |
| Prijsstelling & Waarde | Eerlijk voor complexiteit, geen betaalmuren voor afhankelijkheden | Pas op voor upsell-vallen |
Rubriekscore (0–50):
- 40–50: Sterk — voorkeursleverancier
- 30–39: Acceptabel — controleren
- 20–29: Zwak — ga voorzichtig te werk
- <20: Vermijd
Pro tip: Kruisverwijzing met gerenommeerde marktplaatsen. Begin hier: Beste Tebex Winkels.
Deel 5 — Onderhoudshandboek (Nadat u hebt verzonden)
- Versie vastzetten: vergrendel script releases + afhankelijkheidsversies (bijv.,
oxmysql,ox_lib). - Eerst staging: alle updates komen binnen Teststad; voer de acceptatiechecklist opnieuw uit.
- Back-ups en rollback: DB snapshot + resourcebestanden vóór elke update. Bewaar een Rollback.md met exacte stappen.
- CI smoke test (optioneel, aanbevolen): headless client connect + commandomacro om de belangrijkste flows te raken; serverconsole parsen op fouten.
- Operationele statistieken: houd een eenvoudig logboek per script bij: gemiddelde resmon (idle/actief), fouten per sessie, incidentnotities.
- Changelog discipline: vereis leverancierswijzigingslogboeken; onderhoud je eigen integratie-aantekeningen.
- Risico's van geplande gebeurtenissen verminderen: update buiten piekuren; kondig onderhoudsvensters aan.
Deel 6 — Sjablonen Die U Kunt Kopiëren
A. Testplan (per script)
# Script Test Plan — <name> <version> ## Context Framework(s): ESX/QBCore/QBOX Dependencies: oxmysql vX, ox_lib vY, PolyZone vZ DB Migrations: yes/no Escrow: yes/no ## Functional Cases - [ ] Case 1: - [ ] Case 2: - [ ] Negative 1: ## Performance resmon idle: ____ ms resmon active: ____ ms (scenario: ______) ## Security Checks - [ ] All server events validate source/perm/input - [ ] Rate limits present - [ ] No client-trusted money/inventory mutations ## Logs & Errors Paste snippet (server + F8): ## Result Pass/Fail + Notes
B. Rollback.md (skelet)
# Rollback — <date> <script> <from→to> 1) Disable script: `stop <resource>` 2) Restore resource files from backup: <path> 3) Restore DB snapshot: <path/command> 4) Restart FXServer 5) Verify: console clean, perf normal, flows ok
C. Sjabloon voor problemen
**Summary** What happened vs expected, with timestamps. **Repro Steps** 1) ... 2) ... **Env** Artifact build: Framework & versions: Script version: Other deps: **Logs** Server console: F8: **Attachments** Screens/video if possible.
Hoe u deze gids efficiënt kunt gebruiken
- Bootstrap Test Stad één keer, houd het schoon.
- Voor elk kandidaatscript:
- Plaats in
resources/custom/, inschakelen inserver.cfg. - Voer de Acceptatielijst.
- Bereken de Risicoscore.
- Vet de verkoper met de Leveranciersrubriek.
- Plaats in
- Als het slaagt, merge naar staging; zo niet, vraag om fixes of geef het op.
Meer testgidsen nodig? Learn how to measure script performance with Resmon in FiveM, fix server thread hitch warnings, and build the Part 1 test server with Docker for FiveM.
After the test workflow is ready, compare the exact framework, dependencies, delivered files and setup notes in the FiveM scripts marketplace.
