#Configuration
Everything lives in config.lua. Most values have sensible defaults - this page covers what you'll actually want to change.
The resource runs a self-check when it starts and prints a clear line for anything missing or misconfigured (an absent config key, a database that's too old, a Config.DB table name that doesn't exist, a framework that isn't running). Check your server console after the first start.
#General
Config.ServerName = "Server Name"
Config.ServerDiscord = "discord.gg/discord-link-here" -- used in kick/ban messages
Config.ScreenshotWebhook = "" -- Discord webhook for the /screenshot action (requires discord-screenshot)
Config.LogsWebhook = "" -- Discord webhook every admin action gets mirrored to
Config.EnableAdminPanelCommand = true
Config.AdminPanelCommand = "admin"
Config.AdminPanelKey = "0" -- keybind, in addition to the command
Admin-action logs are batched before being sent to Config.LogsWebhook (Discord rate-limits webhooks at roughly 30 requests a minute, and a busy server will otherwise have real moderation entries dropped).
#Privacy
Config.ShowIPInIdentifiers = false
Whether admins see players' raw IP addresses in the Players list. Off by default. An IP is personal data, it's rarely what you need to moderate someone, and once enabled it also flows through the web API to the dashboard. Bans record the IP either way - this only controls what's displayed.
#Database table names
Config.DB.CharactersTable = "players" -- players (QBCore) | users (ESX)
Config.DB.VehiclesTable = "player_vehicles" -- player_vehicles (QBCore) | owned_vehicles (ESX)
Config.DB.BansTable = "bans"
#Integrations
Config.FuelScript = "LegacyFuel" -- resource used by the "Fill fuel" developer tool
Config.ESXSkin = "" -- set to "AK" if you use ak47_clothing (ESX only)
Config.FuelScript should match whichever fuel resource your server runs (LegacyFuel, ps-fuel, cdn-fuel, ox_fuel...). Leave it blank to disable the tool rather than have it error.
#Retention
Config.LogRetentionDays = 90
Config.ResolvedTicketRetentionDays = 30
The audit log and the ticket table are append-only and otherwise grow forever - on a busy server the log alone adds thousands of rows a day, which eventually makes the Audit Log page slow to open. Pruning runs once at startup and daily after that. Set either to 0 to keep everything.
#Protected resources
Config.ProtectedResources = {
"oxmysql", "qb-core", "qbx_core", "es_extended", "chat", "monitor", -- ...
}
Resources an admin can never stop or restart from the Resources page. Stopping the database bridge or the framework core takes the whole server down, and restarting upgrade-admin itself stops the very script that would issue the start. This resource is always protected whether or not it's listed.
#Teleport locations
Named spots that show up as quick-teleport options:
Config.TeleportLocations = {
['legion'] = vector3(195.17, -934.37, 30.69),
['pillbox'] = vector3(310.2, -599.22, 43.29),
-- add your own
}
#Web API
Config.API.Enabled = true
Config.API.TokenGenerationPerm = "manageapitokens" -- permission required to run /apitoken regenerate
Config.API.ServerTokenRole = nil -- see below
Config.API.ActingSignatureToleranceSeconds = 300 -- clock drift allowed on signed identity headers
Config.API.DashboardWebhookUrl = "" -- POSTed to on new admin chat message / new ticket
Config.API.RateLimitPerMinute = 120 -- per acting admin, after authentication
Config.API.RateLimitPerMinutePerAddress = 300 -- per address, before authentication
Config.API.ServerTokenRole should stay nil, and it's worth understanding why. It's the role given to a request that presents only the raw API token with no signed identity. The token is shared by every Discord account the dashboard grants access to, so it identifies a connection, not a person - giving it a role means anyone who obtains it holds that role outright. With nil it can still reach GET /server and GET /me, which is everything the dashboard's health check needs. Real permissions come from each person's own admin_roles row via the signed acting headers instead. If you do set it, it must be a key in Config.Permissions.
The API is reachable at http://your-server-ip:port/upgrade-admin/... - that's FXServer's own routing on the resource's folder name, not something set in config.lua. See Web API for the full endpoint reference.
#Permissions
Config.Permissions maps each role to the list of actions it's allowed to perform - this is the default a role starts with. See Permissions & Users for how individual admins can be given a completely custom set instead of one of the four presets.
Config.Permissions = {
["god"] = { AllowedActions = { "adminmenu", "kick", "ban", --[[ ... ]] } },
["admin"] = { AllowedActions = { "adminmenu", "kick", "ban", --[[ ... ]] } },
["mod"] = { AllowedActions = { "adminmenu", "viewreports", "kick", --[[ ... ]] } },
["helper"] = { AllowedActions = { "adminmenu", "viewreports", "adminchat", "checkwarns" } },
}
Config.PermissionCatalog is the full, categorized list of every permission that exists (Panel, Moderation, Reports & Chat, Economy & Character, World & Server, Vehicles, Self Toggles, Developer Tools) - this is what powers the checkbox grid on the Users page, and what per-admin permission sets are validated against. If you add an action to a role, add it to the catalog too; the startup self-check warns about any that are missing.