Kartik Scripts

Database Backup Setup

Conflict Resolver includes a built-in automated and manual database backup system. It is designed to safely capture full SQL schema and data dumps, keep a history of the last 10 backups, and allow instant recovery/restoration from the dashboard.


⚙️ Convar Configuration

To run the backup and restore utility, the script needs access to your database details and the system's MySQL binaries (mysqldump and mysql).

While the resource attempts to automatically detect your local installation path, it is recommended to explicitly set these variables in your server.cfg.

1. Database Connection String (mysql_connection_string)

Ensure your standard connection string is defined in your server.cfg. Conflict Resolver will automatically parse host, port, user, password, and database parameters from it.

set mysql_connection_string "mysql://root:password@localhost/qbox?charset=utf8mb4"

2. Allow the Database Tools to Run

mysqldump and mysql are separate programs, so FiveM has to allow Conflict Resolver to start them. Add this line to your server.cfg, above your ensure lines, and restart the whole server:

add_unsafe_child_process_permission kartik-conflictresolver

This is the same line used for applying fixes, see Installation. Without it, the backup page reports that the server does not allow the resource to start helper programs.

3. Custom Tool Paths (Optional)

If your server is using a non-standard database location (e.g., custom drives, custom ports, or isolated dockers), Conflict Resolver might fail to automatically locate the MySQL CLI binaries.

You can explicitly set their paths using the following convars. Each one can point at the program itself or at the bin folder it sits in.

mysql_dump_path

Specifies the path to the mysqldump (or mariadb-dump) executable. This tool is used to generate backups.

set mysql_dump_path "C:/xampp/mysql/bin/mysqldump.exe"

mysql_cli_path

Specifies the path to the mysql (or mariadb) executable. This tool is used to restore backups.

set mysql_cli_path "C:/xampp/mysql/bin/mysql.exe"

mysql_bin_path

Optional. A folder that holds both tools, used when the two convars above are not set.

set mysql_bin_path "C:/Program Files/MariaDB 12.2/bin"

[!TIP] Forward slashes work on Windows too. If the path is set but the tool is still not found, the server console prints a line naming the path it checked, so you can spot a typo or a wrong version folder.


🔍 Automatic Detection Paths

If the custom path convars are not defined, Conflict Resolver first tries the tools on your system PATH, then searches the standard install folders for your Operating System:

🪟 Windows

  • C:\Program Files\MySQL\MySQL Server X.Y\bin\
  • C:\Program Files\MariaDB X.Y\bin\
  • C:\xampp\mysql\bin\
  • C:\laragon\bin\mysql\<version>\bin\
  • C:\wamp64\bin\mysql\<version>\bin\ and C:\wamp64\bin\mariadb\<version>\bin\

The same folders on the D: drive are checked too.

🐧 Linux

  • /usr/bin, /usr/local/bin, /usr/local/mysql/bin, /usr/local/mariadb/bin, /opt/mysql/bin, /opt/mariadb/bin, /snap/bin

[!IMPORTANT] If you are running the server on a Linux container (e.g., Docker, Pterodactyl) or the tools are installed somewhere else, set the convars above explicitly.

[!NOTE] The search runs these checks through a helper program, so it never reads folders outside your resources directly. You should not see Filesystem permission check ... no device found warnings from Conflict Resolver. If you still see one, make sure you are on the latest version and that the add_unsafe_child_process_permission line above is in place.


💾 Storage Type

Where backups are stored is controlled in shared/server_config.lua:

-- 'local' : Save backups only locally on the server (under backups/db)
-- 'drive' : Upload backups only to Google Drive (the local file is deleted after upload)
-- 'both'  : Save backups locally AND upload them to Google Drive
Config.StorageType = 'local'
  • local: no extra setup required; backups stay on the server disk.
  • drive / both, require the Google Drive credentials below.

☁️ Google Drive Setup (OAuth)

Backups upload to Google Drive using OAuth 2.0 with your own Google Account, so files land in your Drive under your storage quota.

[!IMPORTANT] Service Account credentials are not supported. A service account has zero storage quota, so files.create fails with storageQuotaExceeded, and Google no longer lets a service account transfer ownership to a personal @gmail.com. Use the OAuth flow below.

You need four values under Config.GoogleDrive in shared/server_config.lua:

Config.GoogleDrive = {
    FolderId     = "",   -- (optional) which Drive folder to upload into
    ClientId     = "",   -- from Google Cloud Console
    ClientSecret = "",   -- from Google Cloud Console
    RefreshToken = "",   -- from the OAuth Playground
}

The steps below walk through obtaining each one. Budget about 5–10 minutes the first time.


Step 1, Create a Google Cloud Project

  1. Open the Google Cloud Console and sign in with the Google account whose Drive you want the backups to live in.
  2. In the top bar, click the project dropdown (left of the search bar) → New Project.
  3. Give it any name (e.g. FiveM Backups) → Create.
  4. Once it's created, make sure that project is selected in the top bar before continuing.

Step 2, Enable the Google Drive API

  1. In the top search bar, type "Google Drive API" and open it.
  2. Click Enable. (If it already says "Manage", it's on, continue.)

This lets your credentials actually talk to Drive. Without it, uploads fail with a "not enabled" error.

  1. Left menu → APIs & Services → OAuth consent screen.
  2. User type: External → Create.
  3. Fill only the required fields:
    • App name: anything, e.g. FiveM Backups
    • User support email: your email
    • Developer contact email (bottom): your email
    • Leave everything else blank → Save and Continue.
  4. Scopes step: don't add anything → Save and Continue.
  5. Test users step: click + Add Users, enter your own Google account email, → Add → Save and Continue.

[!IMPORTANT] Adding yourself as a Test user is mandatory. If you skip it, authorization in Step 5 fails with Error 403: access_denied, and refresh tokens for un-added users expire after 7 days. Leave the app in Testing mode, you do not need to "Publish" or submit for verification for personal use.

Step 4, Create the OAuth Client → ClientId & ClientSecret

  1. Left menu → APIs & Services → Credentials.
  2. + Create Credentials (top) → OAuth client ID.
  3. Application type: Web application.
  4. Under Authorized redirect URIs, click + Add URI and paste exactly this (no trailing slash, no spaces):
    https://developers.google.com/oauthplayground
  5. Click Create. A popup shows:
    • Client ID: looks like 1234567890-abcdef.apps.googleusercontent.com → this is your ClientId.
    • Client secret: looks like GOCSPX-xxxxxxxxxxxx → this is your ClientSecret.
  6. Copy both (you can reopen them any time from the Credentials list).

[!WARNING] A wrong or mistyped redirect URI causes Error 400: redirect_uri_mismatch in the next step. The most common mistakes are a trailing slash, http instead of https, or pasting it into "Authorized JavaScript origins" instead of "Authorized redirect URIs".

Step 5, Get the RefreshToken (OAuth Playground)

  1. Open the Google OAuth Playground.
  2. Click the ⚙ gear icon (top-right) → tick "Use your own OAuth credentials" → paste your ClientId and ClientSecret → close the panel.
  3. On the left, find the box labelled "Input your own scopes" and paste:
    https://www.googleapis.com/auth/drive.file
  4. Click Authorize APIs (blue button).
  5. Sign in with the same Google account you added as a Test user.
  6. You'll see "Google hasn't verified this app", that's expected for your own test app. Click Advanced → Go to FiveM Backups (unsafe) → Continue → Allow.
  7. Back in the Playground, click Exchange authorization code for tokens (Step 2 on the page).
  8. In the response panel, copy the refresh_token value (a long string starting with 1//) → this is your RefreshToken.

[!TIP] If the response only shows an access_token and no refresh_token, revoke access at myaccount.google.com/permissions and repeat from step 4, Google only issues a refresh token on the first authorization.

Step 6 (Optional), Get the FolderId

By default backups upload to the root of your Drive. To keep them tidy in a specific folder:

  1. In Google Drive, create/open the folder you want (e.g. Server Backups).
  2. Look at the URL in your browser:
    https://drive.google.com/drive/folders/1_bSCHKrVFUUSv1T2YBnK8On5RQhbgzYK
                                            └───────────── this part is the FolderId ─────────────┘
  3. Copy everything after /folders/ → this is your FolderId.

Leave FolderId = "" to upload to the Drive root instead.

Step 7, Put It All Together & Restart

  1. Paste the four values into shared/server_config.lua:
    Config.StorageType = 'drive'   -- or 'both' to also keep a local copy
    
    Config.GoogleDrive = {
        FolderId     = "1_bSCHKrVFUUSv1T2YBnK8On5RQhbgzYK",
        ClientId     = "1234567890-abcdef.apps.googleusercontent.com",
        ClientSecret = "GOCSPX-xxxxxxxxxxxxxxxx",
        RefreshToken = "1//xxxxxxxxxxxxxxxxxxxxxxxx",
    }
  2. Restart the resource:
    ensure kartik-conflictresolver
  3. Trigger a backup (or wait for the schedule). A success logs:
    [conflictresolver] Successfully uploaded database backup to Google Drive. File ID: ...
ValueWhere it comes fromExample
ClientIdCloud Console → Credentials (Step 4)1234567890-abc.apps.googleusercontent.com
ClientSecretCloud Console → Credentials (Step 4)GOCSPX-xxxxxxxxxxxx
RefreshTokenOAuth Playground (Step 5)1//04xxxxxxxxxxxxxxxx
FolderIdDrive folder URL (Step 6, optional)1_bSCHKrVFUUSv1T2YBnK8On5RQhbgzYK

[!TIP] With the drive.file scope the resource can only see and manage files it created, the minimal, safest permission. Keep your ClientSecret and RefreshToken private and never commit them to a public repository.

[!NOTE] Uploads are streamed directly from disk to Google Drive, so even large database dumps upload with low memory use and without freezing the server thread.


📅 Automatic Scheduler

  • Backup Interval: Automatic backups are scheduled to run every 12 hours.
  • Liveness Check: The script will postpone any automated backup if players are online to avoid performance hitches. It will retry every 30 minutes until the server is empty.
  • Retention Policy: The server automatically retains the 10 most recent database backups. Any older backups are purged to save disk space.

📁 Backup Location

The index manifest is always stored locally inside the resource directory:

resources/[kartik]/kartik-conflictresolver/backups/db/
  • db_manifest.json: Holds metadata (timestamps, file sizes, manually triggered vs auto-scheduled, author name, and the Google Drive file ID when uploaded).
  • db_backup_<timestamp>.sql: The raw SQL database backup file.

[!NOTE] The .sql file itself is kept here only when Config.StorageType is local or both. With drive, the local file is deleted after a successful upload and the backup lives on Google Drive, restores automatically download it back on demand.


🛡️ Permissions

Since restoring databases is highly sensitive, triggering manually or restoring from the backups page requires Ace permissions:

add_ace group.admin command.conflicts allow

On this page