Writing your own txAdmin recipe
Build a txAdmin recipe step by step: an example that installs oxmysql, ox_lib, ox_target, pma-voice and a starter resource, creates a table and writes server.cfg.
Эта документация пока на английском.
A recipe is the best way to make your server reproducible. Your dev server, your test server and a fresh live server can all come from the same file, and new developers on your team get a working setup in two minutes. This page builds a complete example recipe and explains each decision. The task reference is in Recipes explained.
Important
The recipe below is an example written for these docs. The resource URLs are real (they are the same ones the official Qbox and ESX recipes use), but pin versions you have tested before you rely on it.
What we’ll build
A lean, framework free base for a custom game mode:
- the default Cfx resources (mapmanager, spawnmanager, basic-gamemode…),
- oxmysql (database), ox_lib (UI and utilities), ox_target (third eye interactions),
- pma-voice (proximity voice) and bob74_ipl (loads GTA’s online interiors),
- one starter resource of our own, created by the recipe,
- a database with one table,
- a
server.cfgwith everything wired up.
Plan the folder layout
resources/
├─ [cfx-default]/ from citizenfx/cfx-server-data
├─ [ox]/ oxmysql, ox_lib, ox_target
├─ [standalone]/ pma-voice, bob74_ipl
└─ [local]/ my_starter (our own)
server.cfgThe recipe
$engine: 3
$onesync: on
name: My Base
version: 1.0.0
author: YourName
description: |
A lean base with oxmysql, ox_lib, ox_target, pma-voice and a starter resource.
No framework. Example recipe from the fivemad docs.
variables:
dbName: null # let txAdmin create the database with a random name
tasks:
# 1. Database first: the most likely step to fail
- action: connect_database
- action: query_database
query: |
CREATE TABLE IF NOT EXISTS `player_stats` (
`license` VARCHAR(60) NOT NULL PRIMARY KEY,
`playtime` INT UNSIGNED NOT NULL DEFAULT 0,
`last_seen` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 2. Default Cfx resources, minus the old chat (the artifact has a built in one)
- action: download_github
src: https://github.com/citizenfx/cfx-server-data
ref: master
subpath: resources
dest: ./resources/[cfx-default]
- action: remove_path
path: ./resources/[cfx-default]/[gameplay]/chat
# 3. Overextended libraries from their release zips
- action: download_file
url: https://github.com/overextended/oxmysql/releases/latest/download/oxmysql.zip
path: ./tmp/oxmysql.zip
- action: unzip
src: ./tmp/oxmysql.zip
dest: ./resources/[ox]
- action: download_file
url: https://github.com/overextended/ox_lib/releases/latest/download/ox_lib.zip
path: ./tmp/ox_lib.zip
- action: unzip
src: ./tmp/ox_lib.zip
dest: ./resources/[ox]
- action: download_file
url: https://github.com/overextended/ox_target/releases/latest/download/ox_target.zip
path: ./tmp/ox_target.zip
- action: unzip
src: ./tmp/ox_target.zip
dest: ./resources/[ox]
# 4. Standalone resources straight from GitHub
- action: download_github
src: https://github.com/AvarianKnight/pma-voice
dest: ./resources/[standalone]/pma-voice
- action: download_github
src: https://github.com/Bob74/bob74_ipl
dest: ./resources/[standalone]/bob74_ipl
# 5. Our own starter resource, written by the recipe
- action: write_file
file: ./resources/[local]/my_starter/fxmanifest.lua
data: |
fx_version 'cerulean'
game 'gta5'
name 'my_starter'
description 'Starter resource created by the My Base recipe'
version '1.0.0'
shared_script '@ox_lib/init.lua'
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server.lua',
}
client_script 'client.lua'
dependencies { 'oxmysql', 'ox_lib' }
- action: write_file
file: ./resources/[local]/my_starter/server.lua
data: |
AddEventHandler('playerJoining', function()
local src = source
local license = GetPlayerIdentifierByType(src, 'license')
if not license then return end
MySQL.insert('INSERT INTO player_stats (license) VALUES (?) ON DUPLICATE KEY UPDATE last_seen = NOW()', { license })
end)
- action: write_file
file: ./resources/[local]/my_starter/client.lua
data: |
RegisterCommand('hello', function()
lib.notify({ title = 'My Base', description = 'Hello from my_starter!', type = 'success' })
end, false)
# 6. server.cfg with placeholders
- action: write_file
file: ./server.cfg
data: |
## Generated by the My Base recipe
{{serverEndpoints}}
sv_hostname "{{serverName}} | My Base"
sets sv_projectName "{{serverName}}"
sets sv_projectDesc "{{recipeDescription}}"
sets tags "custom, base"
sets locale "en-US"
sv_licenseKey "{{svLicense}}"
sv_maxclients {{maxClients}}
sv_enforceGameBuild 3751
set steam_webApiKey "none"
set resources_useSystemChat true
sv_endpointPrivacy true
set mysql_connection_string "{{dbConnectionString}}"
setr voice_useNativeAudio true
setr voice_useSendingRangeOnly true
ensure mapmanager
ensure chat
ensure spawnmanager
ensure basic-gamemode
ensure hardcap
ensure oxmysql
ensure ox_lib
ensure ox_target
ensure pma-voice
ensure bob74_ipl
ensure [local]
add_ace group.admin command allow
add_ace group.admin command.quit deny
{{addPrincipalsMaster}}
# 7. Fill in every {{placeholder}} in server.cfg
- action: replace_string
mode: all_vars
file: ./server.cfg
# 8. Clean up
- action: remove_path
path: ./tmpWhy it’s built this way
- Database first. The official guidelines say to put database tasks at the start, because they fail most often (wrong password, no MariaDB). Better to fail in the first second than after two minutes of downloads.
dbName: null. The guidelines require recipes to accept txAdmin’s random database name instead of forcing one likees_extended. We never hard code a name: the connection string comes from{{dbConnectionString}}.- Release zips for Overextended. Their GitHub repos hold source code with a web UI that must be built. The release zip contains the built resource. Always use the release for ox_lib, ox_inventory, ox_target.
- Placeholders in server.cfg. The guidelines require
{{maxClients}},{{addPrincipalsMaster}},{{serverEndpoints}}and{{svLicense}}.{{svLicense}}is replaced automatically at the end, the others by ourreplace_stringwithall_vars. - The chat resource is removed from
cfx-server-databecauseset resources_useSystemChat trueuses the artifact’s built in chat, as the official default recipe does. $onesync: ontells txAdmin to set OneSync on. ox_lib, ox_target and pma-voice all assume it.
Pin your versions
releases/latest/download/... and download_github without ref always fetch the newest version. That’s convenient, but a breaking update will break your next deploy. For a recipe you share or use for production:
- action: download_github
src: https://github.com/AvarianKnight/pma-voice
ref: 0123456789abcdef0123456789abcdef01234567 # a commit you tested
dest: ./resources/[standalone]/pma-voice
- action: download_file
url: https://github.com/overextended/ox_lib/releases/download/v3.30.0/ox_lib.zip # a tagged release you tested
path: ./tmp/ox_lib.zipThe version numbers above are placeholders: look up the current release on each project’s Releases page. The guidelines prefer commit hashes over tags, because tags can be moved.
Test it
- Push the YAML to a public GitHub repo (or a gist) and copy the raw URL.
- Start a throwaway txAdmin: a separate
TXHOST_DATA_PATHandTXHOST_TXA_PORTso you don’t touch your main one. - Choose Remote URL Template, paste the URL, deploy.
- Check: the server starts with no red errors,
/helloshows a notification in game,player_statsgets a row when you join.
Or paste the YAML into Custom Template to test without hosting it.
Guidelines if you want your recipe listed
The txAdmin-recipes README lists the rules for recipes in the Popular list. The main ones:
- Start from the CFX Default recipe structure.
- It must “just work”: no editing files before the first start.
- Only open source or sharable resources. No leaked content.
- OneSync compatible,
$onesync: onif supported. - Admins in the
adminACE group must be recognised as admins by your framework. - NUI that opens on Tab must check
IsNuiFocused()so it doesn’t steal focus from the txAdmin menu. - txAdmin menu actions (noclip, god mode, teleport) must not trigger your anticheat, and txAdmin’s Heal should revive downed players (listen to
txAdmin:events:playerHealed). - Good onboarding: a loading screen that explains the framework, plenty of comments in
server.cfg. - Use the same game build as the CFX Default recipes.
