FiveRP: the server from the hosting account, not the earlier one
Wrong server was published before. This is the one that runs on the hosting account the video was made on: FiveRP - two-step registration (account, then an identity printed onto a passport), login that returns you to your resident, and a loading screen driven by the game's own streaming events. resources/[local]/fiverp-auth NUI + scrypt hashes + oxmysql resources/[local]/fiverp-characters identity, character load, spawn resources/[local]/fiverp-loadscreen loading screen sql/schema.sql accounts, characters docs/DESIGN.md the design system every screen follows docs/screens/ shot from the live server Only our own code is in here. cfx-server-data and oxmysql are fetched by install.sh instead of being vendored, which keeps the repo at 3.7 MB. install.sh does the whole box in one command: recommended FXServer build, cfx-server-data, oxmysql, MariaDB with the schema, resources, server.cfg (mode 600 - it carries the key and the database password), boot entry, then it waits for the Cfx registration. Tested end to end on a spare install root: 29 resources scanned, database and schema created, and it stopped exactly where a wrong licence key should stop it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
71856b15e9
commit
c857979a55
+101
-96
@@ -1,38 +1,40 @@
|
||||
#!/bin/sh
|
||||
# ---------------------------------------------------------------------------
|
||||
# Los Santos RP - installer
|
||||
# FiveRP - installer
|
||||
#
|
||||
# Puts a working server on a clean Ubuntu/Debian box: FXServer artefacts,
|
||||
# MariaDB with the schema, the resources from this repository, the keep-alive
|
||||
# supervisor and a boot entry.
|
||||
# Turns a clean Ubuntu/Debian box into this server: FXServer artefacts,
|
||||
# cfx-server-data, oxmysql, MariaDB with the schema, the FiveRP resources,
|
||||
# a keep-alive supervisor and a boot entry.
|
||||
#
|
||||
# sudo sh install.sh --licence cfxk_xxxxxxxx
|
||||
#
|
||||
# Options
|
||||
# --licence KEY Cfx.re server key from https://keymaster.fivem.net
|
||||
# --dir PATH install root (default /opt/fivem)
|
||||
# --hostname NAME server name shown in the list (default from server.cfg.example)
|
||||
# --port N game port (default 30120)
|
||||
# --name NAME service name, one per server (default fivem)
|
||||
# --db-name NAME database (default rp)
|
||||
# --db-user USER database user (default rp)
|
||||
# --db-pass PASS password for that user (default: generated)
|
||||
# --build ID FXServer build to use (default: latest recommended)
|
||||
# --dir PATH install root (default /opt/fivem)
|
||||
# --hostname NAME server name in the list (default FiveRP)
|
||||
# --port N game port (default 30120)
|
||||
# --name NAME service name, one per server (default fiverp)
|
||||
# --db-name NAME database (default fiverp)
|
||||
# --db-user USER database user (default fiverp)
|
||||
# --db-pass PASS password for that user (default: generated)
|
||||
# --build ID FXServer build (default: latest recommended)
|
||||
# --no-start install everything, do not start the server
|
||||
# ---------------------------------------------------------------------------
|
||||
set -e
|
||||
|
||||
DIR=/opt/fivem
|
||||
LICENCE=""
|
||||
HOSTNAME_=""
|
||||
HOSTNAME_="FiveRP"
|
||||
BUILD=""
|
||||
DB_NAME=fiverp
|
||||
DB_USER=fiverp
|
||||
DB_PASS=""
|
||||
DB_NAME=rp
|
||||
DB_USER=rp
|
||||
PORT=30120
|
||||
SVC=fivem
|
||||
SVC=fiverp
|
||||
START=1
|
||||
ARTIFACTS="https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/"
|
||||
OXMYSQL="https://github.com/overextended/oxmysql/releases/latest/download/oxmysql.zip"
|
||||
SERVER_DATA_REPO="https://github.com/citizenfx/cfx-server-data"
|
||||
SRC=$(cd "$(dirname "$0")" && pwd)
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
@@ -41,33 +43,33 @@ while [ $# -gt 0 ]; do
|
||||
--dir) DIR="$2"; shift 2 ;;
|
||||
--hostname) HOSTNAME_="$2"; shift 2 ;;
|
||||
--build) BUILD="$2"; shift 2 ;;
|
||||
--db-pass) DB_PASS="$2"; shift 2 ;;
|
||||
--db-name) DB_NAME="$2"; shift 2 ;;
|
||||
--db-user) DB_USER="$2"; shift 2 ;;
|
||||
--db-pass) DB_PASS="$2"; shift 2 ;;
|
||||
--port) PORT="$2"; shift 2 ;;
|
||||
--name) SVC="$2"; shift 2 ;;
|
||||
--no-start) START=0; shift ;;
|
||||
-h|--help) sed -n '2,20p' "$0"; exit 0 ;;
|
||||
-h|--help) sed -n '2,25p' "$0"; exit 0 ;;
|
||||
*) echo "unknown option: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
say() { printf '\n\033[1;33m==\033[0m %s\n' "$*"; }
|
||||
ok() { printf ' \033[32mok\033[0m %s\n' "$*"; }
|
||||
die() { printf '\n\033[31mfailed:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
say() { printf '\n\033[1;34m==\033[0m %s\n' "$*"; }
|
||||
ok() { printf ' \033[32mok\033[0m %s\n' "$*"; }
|
||||
die() { printf '\n\033[31mfailed:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
[ "$(id -u)" = 0 ] || die "run as root (sudo sh install.sh ...)"
|
||||
[ -f "$SRC/etc/schema.sql" ] || die "run this from a clone of the repository"
|
||||
[ -f "$SRC/sql/schema.sql" ] || die "run this from a clone of the repository"
|
||||
command -v apt-get >/dev/null || die "this installer is for Debian/Ubuntu"
|
||||
|
||||
# --- 1. packages -----------------------------------------------------------
|
||||
say "Installing packages"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq curl ca-certificates xz-utils mariadb-server >/dev/null
|
||||
ok "curl, xz-utils, mariadb-server"
|
||||
apt-get install -y -qq curl ca-certificates wget xz-utils git unzip mariadb-server >/dev/null
|
||||
ok "curl, git, unzip, xz-utils, mariadb-server"
|
||||
|
||||
# --- 2. FXServer artefacts -------------------------------------------------
|
||||
# --- 2. FXServer -----------------------------------------------------------
|
||||
say "Fetching FXServer"
|
||||
if [ -n "$BUILD" ]; then
|
||||
REL=$(curl -fsSL "$ARTIFACTS" | tr '>' '\n' | grep -oE "\./$BUILD-[0-9a-f]+/fx\.tar\.xz" | head -1)
|
||||
@@ -80,8 +82,8 @@ fi
|
||||
URL="$ARTIFACTS${REL#./}"
|
||||
BUILD_ID=$(echo "$REL" | grep -oE '[0-9]+' | head -1)
|
||||
|
||||
mkdir -p "$DIR/server" "$DIR/data/resources" "$DIR/bin" "$DIR/logs" "$DIR/etc"
|
||||
if [ -x "$DIR/server/run.sh" ] && [ -f "$DIR/server/.build" ] && [ "$(cat "$DIR/server/.build")" = "$BUILD_ID" ]; then
|
||||
mkdir -p "$DIR/server" "$DIR/bin" "$DIR/logs"
|
||||
if [ -x "$DIR/server/run.sh" ] && [ "$(cat "$DIR/server/.build" 2>/dev/null)" = "$BUILD_ID" ]; then
|
||||
ok "build $BUILD_ID already installed"
|
||||
else
|
||||
TMP=$(mktemp -d)
|
||||
@@ -94,11 +96,31 @@ else
|
||||
ok "build $BUILD_ID unpacked into $DIR/server"
|
||||
fi
|
||||
|
||||
# --- 3. database -----------------------------------------------------------
|
||||
say "Preparing the database"
|
||||
if [ ! -f /etc/init.d/mariadb ] && [ ! -d /run/systemd/system ]; then
|
||||
die "no init system found for mariadb"
|
||||
# --- 3. server-data + oxmysql ---------------------------------------------
|
||||
say "Fetching the base resources"
|
||||
if [ -d "$DIR/server-data/resources" ]; then
|
||||
ok "server-data already present"
|
||||
else
|
||||
git clone --depth=1 -q "$SERVER_DATA_REPO" "$DIR/server-data" || die "could not clone cfx-server-data"
|
||||
ok "cfx-server-data cloned (mapmanager, chat, spawnmanager, sessionmanager, hardcap)"
|
||||
fi
|
||||
|
||||
if [ -f "$DIR/server-data/resources/[system]/oxmysql/fxmanifest.lua" ]; then
|
||||
ok "oxmysql already present"
|
||||
else
|
||||
TMP=$(mktemp -d)
|
||||
curl -fsSL "$OXMYSQL" -o "$TMP/oxmysql.zip" || die "could not download oxmysql"
|
||||
mkdir -p "$DIR/server-data/resources/[system]"
|
||||
unzip -q -o "$TMP/oxmysql.zip" -d "$TMP"
|
||||
rm -rf "$DIR/server-data/resources/[system]/oxmysql"
|
||||
mv "$(find "$TMP" -maxdepth 2 -name fxmanifest.lua | head -1 | xargs dirname)" \
|
||||
"$DIR/server-data/resources/[system]/oxmysql"
|
||||
rm -rf "$TMP"
|
||||
ok "oxmysql installed"
|
||||
fi
|
||||
|
||||
# --- 4. database -----------------------------------------------------------
|
||||
say "Preparing the database"
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl enable --now mariadb >/dev/null 2>&1 || true
|
||||
else
|
||||
@@ -111,75 +133,63 @@ while ! mysqladmin ping >/dev/null 2>&1; do
|
||||
done
|
||||
|
||||
if [ -z "$DB_PASS" ]; then
|
||||
if [ -f "$DIR/data/secrets.cfg" ]; then
|
||||
DB_PASS=$(sed -n 's/^set rp_db_pass "\(.*\)"$/\1/p' "$DIR/data/secrets.cfg" | head -1)
|
||||
if [ -f "$DIR/server-data/server.cfg" ]; then
|
||||
DB_PASS=$(sed -n "s|^set mysql_connection_string \"mysql://[^:]*:\([^@]*\)@.*|\1|p" "$DIR/server-data/server.cfg" | head -1)
|
||||
fi
|
||||
[ -n "$DB_PASS" ] || DB_PASS=$(head -c 24 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' | cut -c1-24)
|
||||
fi
|
||||
|
||||
mysql -e "CREATE DATABASE IF NOT EXISTS \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||
mysql -e "CREATE USER IF NOT EXISTS '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';"
|
||||
mysql -e "ALTER USER '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';"
|
||||
mysql -e "GRANT SELECT, INSERT, UPDATE, DELETE ON \`$DB_NAME\`.* TO '$DB_USER'@'127.0.0.1'; FLUSH PRIVILEGES;"
|
||||
mysql "$DB_NAME" < "$SRC/etc/schema.sql"
|
||||
ok "database $DB_NAME, user $DB_USER@127.0.0.1, schema applied"
|
||||
mysql -e "CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
|
||||
mysql -e "ALTER USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
|
||||
mysql -e "GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
|
||||
mysql "$DB_NAME" < "$SRC/sql/schema.sql"
|
||||
ok "database $DB_NAME, user $DB_USER@localhost, schema applied"
|
||||
|
||||
# --- 4. resources and configuration ---------------------------------------
|
||||
say "Installing the server files"
|
||||
rm -rf "$DIR/data/resources/[rp]"
|
||||
mkdir -p "$DIR/data/resources"
|
||||
cp -r "$SRC/resources/[rp]" "$DIR/data/resources/"
|
||||
cp "$SRC/bin/supervise.sh" "$DIR/bin/"
|
||||
sed "s|/run/fivem.stdin|/run/$SVC.stdin|" "$SRC/bin/rcon" > "$DIR/bin/rcon"
|
||||
chmod +x "$DIR/bin/supervise.sh" "$DIR/bin/rcon"
|
||||
cp "$SRC/etc/schema.sql" "$DIR/etc/schema.sql"
|
||||
ln -sf "$DIR/bin/rcon" "/usr/local/bin/$([ "$SVC" = fivem ] && echo rcon || echo "rcon-$SVC")"
|
||||
# --- 5. FiveRP resources and configuration --------------------------------
|
||||
say "Installing FiveRP"
|
||||
mkdir -p "$DIR/server-data/resources/[local]"
|
||||
for r in fiverp-auth fiverp-characters fiverp-loadscreen; do
|
||||
rm -rf "$DIR/server-data/resources/[local]/$r"
|
||||
cp -r "$SRC/resources/[local]/$r" "$DIR/server-data/resources/[local]/"
|
||||
done
|
||||
ok "fiverp-auth, fiverp-characters, fiverp-loadscreen"
|
||||
|
||||
if [ -f "$DIR/data/server.cfg" ]; then
|
||||
ok "server.cfg kept (already present)"
|
||||
else
|
||||
sed -e "s|exec /opt/fivem/data/secrets.cfg|exec $DIR/data/secrets.cfg|" \
|
||||
-e "s|0.0.0.0:30120|0.0.0.0:$PORT|g" \
|
||||
"$SRC/server.cfg.example" > "$DIR/data/server.cfg"
|
||||
[ -n "$HOSTNAME_" ] && sed -i "s|^sv_hostname .*|sv_hostname \"$HOSTNAME_\"|;s|^sets sv_projectName .*|sets sv_projectName \"$HOSTNAME_\"|" "$DIR/data/server.cfg"
|
||||
ok "server.cfg written"
|
||||
cp "$SRC/bin/run-server.sh" "$DIR/bin/"
|
||||
sed "s|/run/fiverp.stdin|/run/$SVC.stdin|" "$SRC/bin/rcon" > "$DIR/bin/rcon"
|
||||
chmod +x "$DIR/bin/run-server.sh" "$DIR/bin/rcon"
|
||||
ln -sf "$DIR/bin/rcon" "/usr/local/bin/$([ "$SVC" = fiverp ] && echo rcon || echo "rcon-$SVC")"
|
||||
|
||||
CFG="$DIR/server-data/server.cfg"
|
||||
if [ -z "$LICENCE" ] && [ -f "$CFG" ]; then
|
||||
LICENCE=$(sed -n 's/^sv_licenseKey "\(.*\)"$/\1/p' "$CFG" | head -1)
|
||||
fi
|
||||
sed -e "s|0.0.0.0:30120|0.0.0.0:$PORT|g" \
|
||||
-e "s|^sv_hostname .*|sv_hostname \"$HOSTNAME_\"|" \
|
||||
-e "s|^sets sv_projectName .*|sets sv_projectName \"$HOSTNAME_\"|" \
|
||||
-e "s|^sv_licenseKey .*|sv_licenseKey \"${LICENCE:-cfxk_your_key_here}\"|" \
|
||||
-e "s|^set mysql_connection_string .*|set mysql_connection_string \"mysql://$DB_USER:$DB_PASS@localhost/$DB_NAME?charset=utf8mb4\"|" \
|
||||
"$SRC/server.cfg.example" > "$CFG"
|
||||
chmod 600 "$CFG"
|
||||
ok "server.cfg written (mode 600 - it holds the key and the password)"
|
||||
|
||||
if [ -z "$LICENCE" ] && [ -f "$DIR/data/secrets.cfg" ]; then
|
||||
LICENCE=$(sed -n 's/^sv_licenseKey "\(.*\)"$/\1/p' "$DIR/data/secrets.cfg" | head -1)
|
||||
fi
|
||||
cat > "$DIR/data/secrets.cfg" <<EOF
|
||||
# Licence key and database credentials. Never commit this file.
|
||||
sv_licenseKey "${LICENCE:-cfxk_your_key_here}"
|
||||
|
||||
set rp_db_host "127.0.0.1"
|
||||
set rp_db_port "3306"
|
||||
set rp_db_user "$DB_USER"
|
||||
set rp_db_pass "$DB_PASS"
|
||||
set rp_db_name "$DB_NAME"
|
||||
EOF
|
||||
chmod 600 "$DIR/data/secrets.cfg"
|
||||
ok "secrets.cfg written (mode 600)"
|
||||
|
||||
# --- 5. boot entry ---------------------------------------------------------
|
||||
# --- 6. boot entry ---------------------------------------------------------
|
||||
say "Setting up start on boot"
|
||||
sed -e "s|^DATA=.*|DATA=$DIR/data|" -e "s|^SERVER=.*|SERVER=$DIR/server|" \
|
||||
-e "s|^LOG=.*|LOG=$DIR/logs/server.log|" -e "s|^NAME=.*|NAME=$SVC|" \
|
||||
-e "s|/opt/fivem/bin/supervise.sh|$DIR/bin/supervise.sh|" \
|
||||
"$SRC/bin/fivem.init" > "/etc/init.d/$SVC"
|
||||
sed -e "s|^NAME=.*|NAME=$SVC|" -e "s|^DIR=.*|DIR=$DIR|" -e "s|^LOG=.*|LOG=$DIR/logs/server.log|" \
|
||||
"$SRC/bin/fiverp.init" > "/etc/init.d/$SVC"
|
||||
chmod +x "/etc/init.d/$SVC"
|
||||
|
||||
if [ -d /run/systemd/system ]; then
|
||||
cat > "/etc/systemd/system/$SVC.service" <<EOF
|
||||
[Unit]
|
||||
Description=Los Santos RP (FXServer)
|
||||
Description=FiveRP (FXServer)
|
||||
After=network-online.target mariadb.service
|
||||
Wants=mariadb.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$DIR/data
|
||||
ExecStart=$DIR/bin/supervise.sh $SVC $DIR/logs/server.log $DIR/server/run.sh +set citizen_dir $DIR/server/alpine/opt/cfx-server/citizen/ +exec $DIR/data/server.cfg
|
||||
WorkingDirectory=$DIR/server-data
|
||||
ExecStart=$DIR/bin/run-server.sh $SVC $DIR $DIR/logs/server.log
|
||||
KillMode=mixed
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
@@ -194,43 +204,38 @@ elif [ -d /etc/redl/enabled ]; then
|
||||
# REDL VDS: no systemd, the platform starts whatever is marked here
|
||||
touch "/etc/redl/enabled/$SVC" /etc/redl/enabled/mariadb
|
||||
ok "marked in /etc/redl/enabled (REDL VDS autostart)"
|
||||
elif [ -f /etc/redl/enabled ]; then
|
||||
grep -qx "$SVC" /etc/redl/enabled || echo "$SVC" >> /etc/redl/enabled
|
||||
grep -qx mariadb /etc/redl/enabled || echo mariadb >> /etc/redl/enabled
|
||||
ok "marked in /etc/redl/enabled (REDL VDS autostart)"
|
||||
else
|
||||
command -v update-rc.d >/dev/null && update-rc.d "$SVC" defaults >/dev/null 2>&1 || true
|
||||
ok "/etc/init.d/$SVC installed"
|
||||
fi
|
||||
|
||||
# --- 6. start --------------------------------------------------------------
|
||||
if [ "$START" = 0 ]; then
|
||||
say "Done (not started, --no-start)"
|
||||
exit 0
|
||||
fi
|
||||
# --- 7. start --------------------------------------------------------------
|
||||
if [ "$START" = 0 ]; then say "Done (not started, --no-start)"; exit 0; fi
|
||||
if [ -z "$LICENCE" ]; then
|
||||
say "Done"
|
||||
echo " No licence key given. Get a free one at https://keymaster.fivem.net,"
|
||||
echo " put it into $DIR/data/secrets.cfg and run: service $SVC start"
|
||||
echo " put it into $CFG and run: service $SVC start"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
say "Starting the server"
|
||||
if [ -d /run/systemd/system ]; then systemctl restart "$SVC"; else service "$SVC" restart >/dev/null; fi
|
||||
|
||||
LOG="$DIR/logs/server.log"
|
||||
i=0
|
||||
while [ $i -lt 90 ]; do
|
||||
if grep -q "Authenticated with cfx.re Nucleus" "$DIR/logs/server.log" 2>/dev/null; then
|
||||
if grep -q "Authenticated with cfx.re Nucleus" "$LOG" 2>/dev/null; then
|
||||
ok "server is up and registered with Cfx"
|
||||
grep -q "\[selftest\] data path OK" "$DIR/logs/server.log" && ok "self-test passed: the data path works"
|
||||
grep -q "fiverp-auth\] server ready" "$LOG" && ok "fiverp-auth ready"
|
||||
grep -q "Database server connection established" "$LOG" && ok "oxmysql connected to the database"
|
||||
IP=$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null || echo "<server ip>")
|
||||
printf '\n connect %s:%s\n logs: tail -f %s\n console: rcon status\n\n' "$IP" "$PORT" "$DIR/logs/server.log"
|
||||
printf '\n connect %s:%s\n logs: tail -f %s\n console: rcon status\n\n' "$IP" "$PORT" "$LOG"
|
||||
exit 0
|
||||
fi
|
||||
if grep -qE "Could not authenticate server license key|invalid license key|Failed to verify" "$DIR/logs/server.log" 2>/dev/null; then
|
||||
if grep -qE "Could not authenticate server license key|invalid license key" "$LOG" 2>/dev/null; then
|
||||
if [ -d /run/systemd/system ]; then systemctl stop "$SVC"; else service "$SVC" stop >/dev/null 2>&1; fi
|
||||
die "the licence key was refused - get one at https://keymaster.fivem.net, put it into $DIR/data/secrets.cfg and run: service $SVC start"
|
||||
die "the licence key was refused - get one at https://keymaster.fivem.net, put it into $CFG and run: service $SVC start"
|
||||
fi
|
||||
i=$((i+1)); sleep 2
|
||||
done
|
||||
die "the server did not come up in 3 minutes - see $DIR/logs/server.log"
|
||||
die "the server did not come up in 3 minutes - see $LOG"
|
||||
|
||||
Reference in New Issue
Block a user