fixed installer

This commit is contained in:
Frank Harris 2026-06-20 21:19:11 -05:00
parent 05b7d2e464
commit 3d93d01cd1
27 changed files with 996 additions and 1665 deletions

View file

@ -1,19 +1,20 @@
%Cfg::Config = (
logfile => '/home/gameserver/OGP/ogp_agent.log',
listen_port => '12679',
listen_ip => '0.0.0.0',
version => 'v1.4',
key => 'Mvemjsu9p',
steam_license => 'Accept',
sudo_password => 'Inc0rrect!',
web_admin_api_key => '{your_admin_ogp_web_api_key_here}',
web_api_url => '{your_url_to_ogp_api.php}',
steam_dl_limit => '0',
# Resource stats database configuration
stats_db_host => 'mysql.iaregamer.com',
stats_db_user => 'remoteuser',
stats_db_pass => 'Pkloyn7yvpht!',
stats_db_name => 'panel',
stats_table_prefix => 'gsp_',
stats_frequency_minutes => '5',
);
logfile => '/home/gameserver/GSP/gsp_agent.log',
listen_port => '12679',
listen_ip => '0.0.0.0',
version => 'v1.4',
key => 'CHANGE_ME_PANEL_AGENT_KEY',
steam_license => 'Accept',
sudo_password => '',
web_admin_api_key => '',
web_api_url => '',
agent_event_url => '',
remote_server_id => '',
steam_dl_limit => '0',
stats_db_host => '',
stats_db_user => '',
stats_db_pass => '',
stats_db_name => '',
stats_table_prefix => 'gsp_',
stats_frequency_minutes => '5',
);

20
Cfg/Config.pm.default Normal file
View file

@ -0,0 +1,20 @@
%Cfg::Config = (
logfile => '/home/gameserver/GSP/gsp_agent.log',
listen_port => '12679',
listen_ip => '0.0.0.0',
version => 'v1.4',
key => 'CHANGE_ME_PANEL_AGENT_KEY',
steam_license => 'Accept',
sudo_password => '',
web_admin_api_key => '',
web_api_url => '',
agent_event_url => '',
remote_server_id => '',
steam_dl_limit => '0',
stats_db_host => '',
stats_db_user => '',
stats_db_pass => '',
stats_db_name => '',
stats_table_prefix => 'gsp_',
stats_frequency_minutes => '5',
);

View file

@ -1,9 +1,14 @@
%Cfg::Preferences = (
screen_log_local => '1',
delete_logs_after => '30',
gsp_manages_ftp => '1',
ogp_manages_ftp => '1',
ftp_method => 'PureFTPd',
gsp_autorestart_server => '1',
ogp_autorestart_server => '1',
protocol_shutdown_waittime => '10',
linux_user_per_game_server => '1',
PortValidationEnabled => '1',
StartupValidationTimeoutSeconds => '180',
PortCheckIntervalSeconds => '5',
);

View file

@ -0,0 +1,14 @@
%Cfg::Preferences = (
screen_log_local => '1',
delete_logs_after => '30',
gsp_manages_ftp => '1',
ogp_manages_ftp => '1',
ftp_method => 'PureFTPd',
gsp_autorestart_server => '1',
ogp_autorestart_server => '1',
protocol_shutdown_waittime => '10',
linux_user_per_game_server => '1',
PortValidationEnabled => '1',
StartupValidationTimeoutSeconds => '180',
PortCheckIntervalSeconds => '5',
);

View file

@ -0,0 +1,8 @@
agent_auto_update=0
agent_update_repo_url=http://forge.runlevelsystems.com/dev/GSP.git
agent_update_branch=Panel-unstable
agent_update_raw_url=http://forge.runlevelsystems.com/dev/GSP/raw/branch/Panel-unstable/Agent-Linux/ogp_agent.pl
run_pureftpd=1
ftp_port=21
ftp_ip=0.0.0.0
ftp_pasv_range=

View file

@ -1,6 +1,5 @@
OGP Agent NOTES:
GSP Agent NOTES:
Before committing code it is recommended to execute perltidy:
$ perltidy -b -gnu ogp_agent.pl

View file

@ -27,7 +27,7 @@ if (file_exists("config.php")) {
include_once 'db_functions.php';
// Did we properly receive the variables from the OGP agent?
// Did we properly receive the variables from the GSP agent?
if (isset($ftp_username) && isset($ftp_pass) && isset($rDir)) {
@ -35,7 +35,7 @@ if (isset($ftp_username) && isset($ftp_pass) && isset($rDir)) {
$errorCount = 0;
$errorInstallInt = 0;
// OGP should be doing this validation... but it's not
// GSP should be doing this validation before calling this helper.
// Custom directory validation

View file

@ -1,7 +1,7 @@
<?php
/*
This FTP addon works with EHCP (www.ehcp.net)
It allows OGP - the open game panel - to manage custom FTP user accounts
It allows GSP - GameServer Panel - to manage custom FTP user accounts
by own3mall
*/
@ -37,7 +37,7 @@ function addToLog($errors) {
$createLog = fopen($logFile, 'a+');
if (!$createLog) {
trigger_error("Unable to create EHCP FTP Integration log file! Please create a file named \"ehcp_ftp_log.txt\" in the ogp_agent install directory under the EHCP folder with permissions of 777", E_USER_NOTICE);
trigger_error("Unable to create EHCP FTP Integration log file! Please create a file named \"ehcp_ftp_log.txt\" in the GSP agent install directory under the EHCP folder with permissions of 777", E_USER_NOTICE);
}
fclose($createLog);
}

View file

@ -1,37 +1,60 @@
# GSP Linux Agent
Perl-based agent that receives signed RPC calls from the GameServer Panel (GSP) and launches customer servers on Linux hosts. It replaces the upstream OGP agent with our service wrappers, stats hooks, and documentation.
Perl-based Linux execution agent for GameServer Panel. The agent receives signed RPC calls from the GSP Panel and launches customer game servers on Linux hosts.
## Features
## Default Layout
- TLS-ready RPC listener (default port 12679/TCP)
- GNU Screen process management + PID tracking
- SteamCMD helpers for installing/updating games
- Optional resource stats reporting to MySQL
- Systemd service definitions and bootstrap scripts
- install directory: `/home/gameserver/GSP`
- run script: `gsp_agent_run`
- legacy run wrapper: `ogp_agent_run`
- systemd service: `gsp_agent.service`
- config directory: `/home/gameserver/GSP/Cfg/`
- main log: `/home/gameserver/GSP/gsp_agent.log`
- screen logs: `/home/gameserver/GSP/screenlogs/`
- server-content runtime: `/home/gameserver/GSP/_gsp_content/`
## Install (Ubuntu example)
Legacy OGP script names are retained only where the Panel or older installs may still expect them.
## Guided Install
```bash
sudo apt update
sudo apt install -y git curl rsync screen perl libxml-parser-perl libpath-class-perl
sudo git clone https://github.com/GameServerPanel/GSP-Agent-Linux.git /opt/gsp-agent
cd /opt/gsp-agent
sudo bash install.sh
sudo bash agent_conf.sh -s "root-password" -u ogp_agent
chmod +x install_agent_prereqs.sh install.sh agent_conf.sh gsp_agent_run ogp_agent_run
sudo ./install_agent_prereqs.sh
sudo ./install.sh
```
After running `agent_conf.sh`, edit `/home/ogp_agent/Cfg/Config.pm` so `listen_ip`, `listen_port`, `key`, and `web_api_url` match the server entry you created inside the GSP web panel.
The installer prompts for the install directory, Linux agent user, service name, agent key/shared secret, listen address, Panel URLs, remote server ID, FTP mode, and whether to install/start the systemd service.
Use the same agent key/shared secret configured in the GSP Panel remote-server record.
## Service Commands
```bash
sudo systemctl status gsp_agent
sudo journalctl -u gsp_agent -f
sudo systemctl restart gsp_agent
tail -f /home/gameserver/GSP/gsp_agent.log
```
## Manual Configuration
```bash
./agent_conf.sh --guided --install-dir /home/gameserver/GSP --agent-user gameserver
```
Generated files:
- `Cfg/Config.pm`
- `Cfg/Preferences.pm`
- `Cfg/bash_prefs.cfg`
## Documentation
Offline instructions, upgrade notes, and troubleshooting tips live under [`documentation/agent-guide.md`](documentation/agent-guide.md). Import that file into your wiki if you need a browsable version.
- [Linux Agent Operations Guide](documentation/agent-guide.md)
- [Panel Integration](docs/PANEL_INTEGRATION.md)
- [Agent Activity Events](docs/AGENT_ACTIVITY_EVENTS.md)
## Related projects
## Related Projects
- [GSP](https://github.com/GameServerPanel/GSP) The web panel that issues commands to this agent.
- [GSP-Agent-Windows](https://github.com/GameServerPanel/GSP-Agent-Windows) Windows counterpart with Task Scheduler wrappers.
## Contributing
Pull requests are welcome. Please keep Perl code formatted with `perltidy`, validate new service files on a staging host, and document behavior changes in `documentation/agent-guide.md`.
- GSP Panel: control plane that sends agent commands
- GSP-Agent-Windows: Windows/Cygwin execution engine

896
agent_conf.sh Normal file → Executable file
View file

@ -1,734 +1,218 @@
#!/bin/bash
#
# OGP - Open Game Panel
# Copyright (C) Copyright (C) 2008 - 2013 The OGP Development Team
#
# http://www.opengamepanel.org/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#!/usr/bin/env bash
####################
# FUNCTIONs #
####################
set -euo pipefail
function indexOf(){
# $1 = search string
# $2 = string or char to find
# Returns -1 if not found
x="${1%%$2*}"
[[ $x = $1 ]] && echo -1 || echo ${#x}
}
DEFAULT_PORT="12679"
DEFAULT_IP="0.0.0.0"
DEFAULT_AGENT_VERSION="v1.4"
DEFAULT_FTP_METHOD="PureFTPd"
DEFAULT_FTP_PORT="21"
DEFAULT_FTP_PASV_RANGE=""
#####################
# CODE ##########
#####################
usage() {
cat <<EOF
GSP Linux Agent configuration helper
if [ $EUID -ne 0 -a "$(uname -o)" != "Cygwin" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
Usage:
./agent_conf.sh --guided
./agent_conf.sh [options]
usage()
{
cat << EOF
Options:
--install-dir PATH Agent install directory. Default: directory containing this script.
--agent-user USER Owner for generated config files.
--key VALUE Agent key/shared secret from the GSP Panel remote-server record.
--listen-ip IP Agent bind IP. Default: ${DEFAULT_IP}
--listen-port PORT Agent bind port. Default: ${DEFAULT_PORT}
--sudo-password VALUE Optional sudo password for legacy sudo_exec flows.
--web-api-url URL Panel ogp_api.php URL.
--agent-event-url URL Panel agent_event_receiver.php URL.
--remote-server-id ID Panel remote server ID.
--ftp-managed 0|1 Whether GSP should manage FTP accounts. Default: 1
--ftp-method NAME FTP backend. Default: ${DEFAULT_FTP_METHOD}
--auto-restart 0|1 Restart crashed game servers. Default: 1
--auto-update 0|1 Restart-time agent auto update. Default: 0
--guided Prompt for missing values.
--help Show this help.
Usage: $0 option
Legacy aliases:
-s VALUE maps to --sudo-password
-u USER maps to --agent-user
OPTIONS:
-s password Set the password for the agent's user (Linux)
-p password Set the password for cyg_server user (Windows)
-u ogpuser Set the username of the ogp user
This script writes:
Cfg/Config.pm
Cfg/Preferences.pm
Cfg/bash_prefs.cfg
EOF
}
while getopts "hs:p:u" OPTION
do
case $OPTION in
s)
sudo_password=$OPTARG
;;
p)
cs_psw=$OPTARG
;;
u)
agent_user=$OPTARG
;;
?)
exit
;;
esac
done
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
install_dir="$script_dir"
agent_user=""
guided=0
key=""
listen_ip="$DEFAULT_IP"
listen_port="$DEFAULT_PORT"
sudo_password=""
web_api_url=""
agent_event_url=""
remote_server_id=""
steam_license="Accept"
ftp_managed="1"
ftp_method="$DEFAULT_FTP_METHOD"
auto_restart="1"
auto_update="0"
screen_log_local="1"
delete_logs_after="30"
linux_user_per_game_server="1"
protocol_shutdown_waittime="10"
ftp_port="$DEFAULT_FTP_PORT"
ftp_ip="$DEFAULT_IP"
ftp_pasv_range="$DEFAULT_FTP_PASV_RANGE"
if [ -z $1 ]
then
usage
exit
fi
if [ "$(uname -o)" == "Cygwin" ]; then
if [ -z $cs_psw ]
then
echo "Must use -p argument instead of -s."
exit
fi
else
if [ -z $sudo_password ]
then
echo "Must use -s argument instead of -p."
exit
fi
fi
readonly DEFAULT_PORT=12679
readonly DEFAULT_IP=0.0.0.0
readonly DEFAULT_FTP_PORT=21
readonly DEFAULT_FTP_PASV_RANGE=40000:50000
readonly AGENT_VERSION='v1.4'
failed()
{
echo "ERROR: ${1}"
exit 1
ask() {
local prompt="$1"
local default_value="$2"
local answer
read -r -p "${prompt} [${default_value}]: " answer
printf '%s' "${answer:-$default_value}"
}
agent_home="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ask_secret() {
local prompt="$1"
local answer
read -r -s -p "${prompt}: " answer
echo
printf '%s' "$answer"
}
cfgfile=${agent_home}/Cfg/Config.pm
prefsfile=${agent_home}/Cfg/Preferences.pm
bashprefsfile=${agent_home}/Cfg/bash_prefs.cfg
require_01() {
local name="$1"
local value="$2"
[[ "$value" =~ ^[01]$ ]] || {
echo "ERROR: ${name} must be 0 or 1." >&2
exit 1
}
}
overwrite_config=1
if [ -e ${cfgfile} ]; then
while [ 1 ]
do
echo "Overwrite old configuration?"
echo -n "(yes/no) [Default yes]: "
read octmp
if [ "$octmp" == "yes" -o -z "$octmp" ]
then
break
elif [ "$octmp" == "no" ]
then
overwrite_config=0
break
else
echo "You need to type 'yes', 'no' or leave empty for default value [yes]."
fi
done
while [ "$#" -gt 0 ]; do
case "$1" in
--install-dir) install_dir="${2:-}"; shift 2 ;;
--agent-user) agent_user="${2:-}"; shift 2 ;;
--key) key="${2:-}"; shift 2 ;;
--listen-ip) listen_ip="${2:-}"; shift 2 ;;
--listen-port) listen_port="${2:-}"; shift 2 ;;
--sudo-password) sudo_password="${2:-}"; shift 2 ;;
--web-api-url) web_api_url="${2:-}"; shift 2 ;;
--agent-event-url) agent_event_url="${2:-}"; shift 2 ;;
--remote-server-id) remote_server_id="${2:-}"; shift 2 ;;
--ftp-managed) ftp_managed="${2:-}"; shift 2 ;;
--ftp-method) ftp_method="${2:-}"; shift 2 ;;
--auto-restart) auto_restart="${2:-}"; shift 2 ;;
--auto-update) auto_update="${2:-}"; shift 2 ;;
--guided) guided=1; shift ;;
-s) sudo_password="${2:-}"; shift 2 ;;
-u) agent_user="${2:-}"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) echo "ERROR: unknown option: $1" >&2; usage; exit 1 ;;
esac
done
install_dir="${install_dir%/}"
cfg_dir="${install_dir}/Cfg"
cfgfile="${cfg_dir}/Config.pm"
prefsfile="${cfg_dir}/Preferences.pm"
bashprefsfile="${cfg_dir}/bash_prefs.cfg"
if [ "$guided" -eq 1 ]; then
echo "GSP Linux Agent configuration"
echo "Use values from Panel -> Administration -> Game Servers for this remote server."
echo
key="${key:-$(ask_secret "Agent key/shared secret")}"
listen_ip="$(ask "Listen IP" "$listen_ip")"
listen_port="$(ask "Listen port" "$listen_port")"
web_api_url="$(ask "Panel API URL, usually https://panel.example.com/ogp_api.php" "$web_api_url")"
agent_event_url="$(ask "Panel event receiver URL, usually https://panel.example.com/agent_event_receiver.php" "$agent_event_url")"
remote_server_id="$(ask "Panel remote server ID" "$remote_server_id")"
ftp_managed="$(ask "Manage FTP accounts? 1=yes, 0=no" "$ftp_managed")"
ftp_method="$(ask "FTP method" "$ftp_method")"
auto_restart="$(ask "Restart crashed game servers? 1=yes, 0=no" "$auto_restart")"
auto_update="$(ask "Restart-time agent auto-update? 1=yes, 0=no" "$auto_update")"
if [ -z "$sudo_password" ]; then
sudo_password="$(ask_secret "Optional sudo password for legacy sudo_exec flows, leave blank if not used")"
fi
fi
if [ "X${overwrite_config}" == "X1" ]
then
if [ -z "$sudo_password" ]; then
if [ -f "$cfgfile" ]; then
sudo_password=`awk '/sudo_password/{print $3}' $cfgfile|sed -e "s#\('\)\(.*\)\(',\)#\2#"`
fi
fi
echo "#######################################################################"
echo ""
echo "OGP agent uses basic encryption to prevent unauthorized users from connecting"
echo "Enter a string of alpha-numeric characters for example 'abcd12345'"
echo "**** NOTE - Use the same key in your Open Game Panel webpage config file - they must match *****"
echo ""
[ -n "$key" ] || key="CHANGE_ME_PANEL_AGENT_KEY"
[[ "$listen_port" =~ ^[0-9]+$ ]] || {
echo "ERROR: listen port must be numeric." >&2
exit 1
}
require_01 "ftp-managed" "$ftp_managed"
require_01 "auto-restart" "$auto_restart"
require_01 "auto-update" "$auto_update"
while [ -z "${key}" ]
do
echo -n "Set encryption key: "
read key
done
mkdir -p "$cfg_dir" "${install_dir}/logs" "${install_dir}/tmp" "${install_dir}/screenlogs" "${install_dir}/_gsp_content/hooks" "${install_dir}/_gsp_content/generated" "${install_dir}/_gsp_content/runtime"
echo
echo "Set the listen port for the agent. The default should be fine for everyone."
echo "However, if you want to change it that can be done here, otherwise just press Enter."
echo -n "Set listen port [Default ${DEFAULT_PORT}]: "
read port
if [ -z "${port}" ]
then
port=$DEFAULT_PORT
fi
echo
echo "Set the listen IP for the agent."
echo "Use ${DEFAULT_IP} to bind on all interfaces."
echo -n "Set listen IP [Default ${DEFAULT_IP}]: "
read ip
if [ -z "${ip}" ]
then
ip=$DEFAULT_IP
fi
while [ 1 ]
do
echo
echo "For some games the OGP panel is using Steam client."
echo "This client has its own license that you need to agree before continuing."
echo "This agreement is available at http://store.steampowered.com/subscriber_agreement/"
echo;
echo "Do you accept the terms of Steam(tm) Subscriber Agreement?"
echo -n "(Accept|Reject): "
read steam_license
if [ "$steam_license" == "Accept" -o "$steam_license" == "Reject" ]
then
break;
fi
echo "You need to type either 'Accept' or 'Reject'."
done
echo "Writing Config file - $cfgfile"
# Prompt for resource stats MySQL settings
echo
echo "Configure Resource Stats MySQL Database Connection:"
echo -n "Stats DB Host [Default 127.0.0.1]: "
read stats_db_host
if [ -z "$stats_db_host" ]; then stats_db_host='127.0.0.1'; fi
echo -n "Stats DB User [Default panel_user]: "
read stats_db_user
if [ -z "$stats_db_user" ]; then stats_db_user='panel_user'; fi
echo -n "Stats DB Password [Default REPLACE_ME]: "
read stats_db_pass
if [ -z "$stats_db_pass" ]; then stats_db_pass='REPLACE_ME'; fi
echo -n "Stats DB Name [Default panel_database]: "
read stats_db_name
if [ -z "$stats_db_name" ]; then stats_db_name='panel_database'; fi
echo -n "Stats Table Prefix [Default gsp_]: "
read stats_table_prefix
if [ -z "$stats_table_prefix" ]; then stats_table_prefix='gsp_'; fi
echo -n "Stats Frequency Minutes [Default 5]: "
read stats_frequency_minutes
if [ -z "$stats_frequency_minutes" ]; then stats_frequency_minutes='5'; fi
echo "%Cfg::Config = (
logfile => '${agent_home}/ogp_agent.log',
listen_port => '${port}',
listen_ip => '${ip}',
version => '${AGENT_VERSION}',
cat > "$cfgfile" <<EOF
%Cfg::Config = (
logfile => '${install_dir}/gsp_agent.log',
listen_port => '${listen_port}',
listen_ip => '${listen_ip}',
version => '${DEFAULT_AGENT_VERSION}',
key => '${key}',
steam_license => '${steam_license}',
sudo_password => '${sudo_password}',
web_admin_api_key => '{your_admin_ogp_web_api_key_here}',
web_api_url => '{your_url_to_ogp_api.php}',
agent_event_url => '{your_url_to_agent_event_receiver.php}',
remote_server_id => '{panel_remote_server_id}',
web_admin_api_key => '',
web_api_url => '${web_api_url}',
agent_event_url => '${agent_event_url}',
remote_server_id => '${remote_server_id}',
steam_dl_limit => '0',
# Resource stats database configuration
stats_db_host => '${stats_db_host}',
stats_db_user => '${stats_db_user}',
stats_db_pass => '${stats_db_pass}',
stats_db_name => '${stats_db_name}',
stats_table_prefix => '${stats_table_prefix}',
stats_frequency_minutes => '${stats_frequency_minutes}',
);" > $cfgfile
if [ $? != 0 ]
then
failed "Failed to write config file."
else
chmod 600 ${cfgfile} || failed "Failed to chmod ${cfgfile} to 600."
fi
stats_db_host => '',
stats_db_user => '',
stats_db_pass => '',
stats_db_name => '',
stats_table_prefix => 'gsp_',
stats_frequency_minutes => '5',
);
EOF
echo;
while [ 1 ]
do
echo "The agent should be updated when the service is restarted or started?"
echo -n "(yes|no) [Default yes]: "
read auto_update
if [ "${auto_update}" == "yes" -o "${auto_update}" == "no" -o -z "${auto_update}" ]
then
if [ "${auto_update}" == "yes" ]
then
autoUpdate=1
elif [ -z "${auto_update}" ]
then
autoUpdate=1
else
autoUpdate=0
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [yes]."
done
cat > "$prefsfile" <<EOF
%Cfg::Preferences = (
screen_log_local => '${screen_log_local}',
delete_logs_after => '${delete_logs_after}',
gsp_manages_ftp => '${ftp_managed}',
ogp_manages_ftp => '${ftp_managed}',
ftp_method => '${ftp_method}',
gsp_autorestart_server => '${auto_restart}',
ogp_autorestart_server => '${auto_restart}',
protocol_shutdown_waittime => '${protocol_shutdown_waittime}',
linux_user_per_game_server => '${linux_user_per_game_server}',
PortValidationEnabled => '1',
StartupValidationTimeoutSeconds => '180',
PortCheckIntervalSeconds => '5',
);
EOF
echo;
while [ 1 ]
do
echo "The agent should backup the server log files in the game server directory?"
echo -n "(yes|no) [Default yes]: "
read log_local_copy
if [ "${log_local_copy}" == "yes" -o "${log_local_copy}" == "no" -o -z "${log_local_copy}" ]
then
if [ "${log_local_copy}" == "yes" ]
then
logLocalCopy=1
elif [ -z "${log_local_copy}" ]
then
logLocalCopy=1
else
logLocalCopy=0
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [yes]."
done
cat > "$bashprefsfile" <<EOF
agent_auto_update=${auto_update}
agent_update_repo_url=http://forge.runlevelsystems.com/dev/GSP.git
agent_update_branch=Panel-unstable
agent_update_raw_url=http://forge.runlevelsystems.com/dev/GSP/raw/branch/Panel-unstable/Agent-Linux/ogp_agent.pl
run_pureftpd=${ftp_managed}
ftp_port=${ftp_port}
ftp_ip=${ftp_ip}
ftp_pasv_range=${ftp_pasv_range}
EOF
echo;
echo "After how many days should be deleted the old backups of server's logs?"
echo -n "[Default 30]: "
read delete_logs_after
case ${delete_logs_after} in
''|*[!0-9]*) deleteLogsAfter=30 ;;
*) deleteLogsAfter=${delete_logs_after} ;;
esac
chmod 600 "$cfgfile"
chmod 644 "$prefsfile" "$bashprefsfile"
echo;
while [ 1 ]
do
echo "The agent should automatically restart game servers if they crash?"
echo -n "(yes|no) [Default yes]: "
read auto_restart
if [ "${auto_restart}" == "yes" -o "${auto_restart}" == "no" -o -z "${auto_restart}" ]
then
if [ "${auto_restart}" == "yes" ]
then
autoRestart=1
elif [ -z "${auto_restart}" ]
then
autoRestart=1
else
autoRestart=0
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [yes]."
done
echo;
while [ 1 ]
do
echo "Should Open Game Panel create and manage FTP accounts?"
echo -n "(yes|no) [Default yes]: "
read manage_ftp
if [ "${manage_ftp}" == "yes" -o "${manage_ftp}" == "no" -o -z "${manage_ftp}" ]
then
if [ "${manage_ftp}" == "yes" ]
then
ogpManagesFTP=1
elif [ -z "${manage_ftp}" ]
then
ogpManagesFTP=1
else
ogpManagesFTP=0
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [yes]."
done
echo;
# Only ask these install questions if users want OGP to manage FTP accounts
if [ "$ogpManagesFTP" == "1" ]
then
if [ "$(uname -o)" != "Cygwin" ]; then
while [ 1 ]
do
echo "If you are running ISPConfig 3 in this machine the agent"
echo "can use it to create FTP accounts instead of using Pure-FTPd."
echo "Would you like to configure this agent to use the API of ISPConfig 3?"
echo -n "(yes|no) [Default no]: "
read IspConfig
if [ "${IspConfig}" == "yes" -o "${IspConfig}" == "no" -o -z "${IspConfig}" ]
then
if [ "${IspConfig}" == "yes" ]
then
ftpMethod="IspConfig"
else
IspConfig="no"
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [no]."
done
if [ "${IspConfig}" == "yes" ]
then
while [ 1 ]
do
echo "Do you use HTTPS to access to your ISPConfig 3 Panel?"
echo -n "(yes|no) [Default no]: "
read https
if [ "${https}" == "yes" -o "${https}" == "no" -o -z "${https}" ]
then
if [ "${https}" == "yes" ]
then
secure="s"
else
secure=""
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [no]."
done
echo -n "What port do you use to connect to your ISPConfig 3 Panel? [Default 8080]: "
read setport
case ${setport} in
''|*[!0-9]*) port=8080 ;;
*) port=${setport} ;;
esac
echo -n "Enter an user name to sing in remotelly (Remote user): "
read remote_login_username
echo -n "Enter password (Remote user): "
read remote_login_password
echo -e "<?php\n\$username = '${remote_login_username}';" > ${agent_home}/IspConfig/soap_config.php
echo "\$password = '${remote_login_password}';" >> ${agent_home}/IspConfig/soap_config.php
echo "\$soap_location = 'http${secure}://127.0.0.1:${port}/remote/index.php';" >> ${agent_home}/IspConfig/soap_config.php
echo -e "\$soap_uri = 'http${secure}://127.0.0.1:${port}/remote/';\n?>" >> ${agent_home}/IspConfig/soap_config.php
else
while [ 1 ]
do
echo;
echo "If you have installed the Easy Hosting Control Panel (EHCP - www.ehcpforce.tk),"
echo "the agent can use it to create FTP accounts instead of using Pure-FTPd."
echo "Would you like to configure this agent to use the API of EHCP?"
echo -n "(yes|no) [Default no]: "
read ehcp
if [ "${ehcp}" == "yes" -o "${ehcp}" == "no" -o -z "${ehcp}" ]
then
if [ "${ehcp}" == "yes" ]
then
ftpMethod="EHCP"
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [no]."
done
if [ "${ehcp}" == "yes" ]
then
echo "Please enter the MySQL database password for the ehcp user"
echo -n "(created during the install of EHCP): "
read ehcpDB
ehcpConf=${agent_home}/EHCP/config.php
sed -i "s/changeme/${ehcpDB}/" $ehcpConf
else
while [ 1 ]
do
echo;
echo "The agent can use ProFTPd to create FTP accounts."
echo "Would you like to configure this agent to use the ProFTPd?"
echo -n "(yes|no) [Default no]: "
read proftpd
if [ "${proftpd}" == "yes" -o "${proftpd}" == "no" -o -z "${proftpd}" ]
then
if [ "${proftpd}" == "yes" ]
then
ftpMethod="proftpd"
fi
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [no]."
done
if [ "${proftpd}" == "yes" ]
then
echo "Please enter the path for proFTPd configuration file"
echo -n "[Default /etc/proftpd/proftpd.conf]: "
read proFTPdConfFile
if [ -z $proFTPdConfFile ]
then
proFTPdConfFile="/etc/proftpd/proftpd.conf"
if [ ! -e "$proFTPdConfFile" ]; then
proFTPdConfFile="/etc/proftpd.conf"
fi
fi
proFTPdConfPath=$(dirname ${proFTPdConfFile})
while [ 1 ]
do
if [ ! -e $proFTPdConfFile ]
then
echo "The file ${proFTPdConfFile} does not exists,"
echo "what you want to do, reenter it or ignore and continue?"
echo "If your answer is 'ignore' is meant that you will install proFTPd later."
echo -n "(reenter|ignore): "
read answer
if [ "${answer}" == "reenter" -o "${answer}" == "ignore" ]
then
if [ "${answer}" == "reenter" ]
then
echo "Reenter proFTPd's configuration file path:"
read proFTPdConfFile
continue
elif [ "${answer}" == "ignore" ]
then
echo "You will need to append this to ${proFTPdConfFile} once you've installed proftpd:"
bold=`tput bold`
normal=`tput sgr0`
echo -e "\n\n${bold}RequireValidShell off\nAuthUserFile ${proFTPdConfPath}/ftpd.passwd\nAuthGroupFile ${proFTPdConfPath}/ftpd.group${normal}\n\n"
break
fi
fi
echo "You need to type 'reenter' or 'ignore'."
else
if egrep -iq "LoadModule\s*mod_auth_file.c" ${proFTPdConfFile}
then
sed -i "s/\s*#\s*LoadModule\s*mod_auth_file.c/LoadModule mod_auth_file.c/g" ${proFTPdConfFile}
else
echo -e "LoadModule mod_auth_file.c" >> ${proFTPdConfFile}
fi
if egrep -iq "^\s*AuthOrder.*" ${proFTPdConfFile}
then
if egrep -iq "^\s*AuthOrder.*mod_auth_file.c" ${proFTPdConfFile}
then
false
else
sed -ri "s/(^\s*AuthOrder.*)/\1 mod_auth_file.c/g" ${proFTPdConfFile}
fi
else
echo -e "AuthOrder mod_auth_file.c" >> ${proFTPdConfFile}
fi
if egrep -iq "RequireValidShell.*" ${proFTPdConfFile}
then
sed -i "s#RequireValidShell.*#RequireValidShell off#g" ${proFTPdConfFile}
else
echo -e "RequireValidShell off" >> ${proFTPdConfFile}
fi
if egrep -iq "AuthUserFile.*" ${proFTPdConfFile}
then
sed -i "s#AuthUserFile.*#AuthUserFile ${proFTPdConfPath}/ftpd.passwd#g" ${proFTPdConfFile}
else
echo -e "AuthUserFile "${proFTPdConfPath}"/ftpd.passwd" >> ${proFTPdConfFile}
fi
if egrep -iq "AuthGroupFile.*" ${proFTPdConfFile}
then
sed -i "s#AuthGroupFile.*#AuthGroupFile ${proFTPdConfPath}/ftpd.group#g" ${proFTPdConfFile}
else
echo -e "AuthGroupFile "${proFTPdConfPath}"/ftpd.group" >> ${proFTPdConfFile}
fi
# Allow global overwrite (http://opengamepanel.org/forum/viewthread.php?thread_id=5202)
if egrep -iq "AllowOverwrite.*" ${proFTPdConfFile}
then
sed -i "s#AllowOverwrite.*#AllowOverwrite yes#g" ${proFTPdConfFile}
else
echo -e "<Global>\nAllowOverwrite yes\n</Global>" >> ${proFTPdConfFile}
fi
if [ ! -e "${proFTPdConfPath}/ftpd.group" ]
then
touch ${proFTPdConfPath}/ftpd.group
fi
if [ ! -e "${proFTPdConfPath}/ftpd.passwd" ]
then
touch ${proFTPdConfPath}/ftpd.passwd
fi
ftpd_user=$(grep -oP '^User\s+\K.+' ${proFTPdConfFile})
ftpd_group=$(grep -oP '^Group\s+\K.+' ${proFTPdConfFile})
if [ -z "$agent_user" ]; then
agent_user=$(grep -oP 'agent_user=\K.+' /etc/init.d/ogp_agent)
fi
if [ ! -z "$ftpd_user" ] && [ ! -z "$ftpd_group" ] && [ ! -z "$agent_user" ]
then
if [ "$(groups $agent_user|grep $ftpd_group)" == "" ]
then
usermod -aG $ftpd_group $agent_user
fi
if [ -e "${proFTPdConfPath}/ftpd.passwd" -a -e "${proFTPdConfPath}/ftpd.group" ]
then
chmod 640 ${proFTPdConfPath}/ftpd.*
chown -f $ftpd_user:$ftpd_group ${proFTPdConfPath}/ftpd.*
fi
fi
break
fi
done
if [ -e "/etc/init.d/proftpd" ]
then
/etc/init.d/proftpd restart
else
echo "If proftpd is running, to apply the changes, you must restart the service."
fi
else
ftpMethod="PureFTPd"
fi
fi
fi
else
if uname -a|grep -q "x86_64"
then
FZ="yes"
else
while [ 1 ]
do
echo;
echo "If you have installed the FileZilla Server,"
echo "the agent can use it to create FTP accounts instead of using Pure-FTPd."
echo "Would you like to configure this agent to use it?"
echo -n "(yes|no) [Default no]: "
read FZ
if [ "${FZ}" == "yes" -o "${FZ}" == "no" -o -z "${FZ}" ]
then
break;
fi
echo "You need to type 'yes', 'no' or leave empty for default value [no].";
done
fi
if [ "${FZ}" == "yes" ]; then
ftpMethod="FZ"
PF=$(cmd /Q /C echo %PROGRAMFILES\(X86\)% | sed 's/\r$//')
if [ "X${PF}" == "X" ];then PF=$(cmd /Q /C echo %PROGRAMFILES% | sed 's/\r$//'); fi
echo;
echo "Please enter the path for FileZilla server executable file"
echo -n "[Default ${PF}\\FileZilla Server\\FileZilla server.exe]: "
read -r FZ_EXE
if [ -z "${FZ_EXE}" ]
then
FZ_EXE="${PF}\\FileZilla Server\\FileZilla server.exe"
fi
echo;
echo "Please enter the path for FileZilla server xml file"
echo -n "[Default ${PF}\\FileZilla Server\\FileZilla Server.xml]: "
read -r FZ_XML
if [ -z "${FZ_XML}" ]
then
FZ_XML="${PF}\\FileZilla Server\\FileZilla server.xml"
fi
FZ_EXE=$(cygpath -u "$FZ_EXE")
FZ_XML=$(cygpath -u "$FZ_XML")
FZconf=${agent_home}/Cfg/FileZilla.pm
echo -e "%Cfg::FileZilla = (\n\tfz_exe => '${FZ_EXE}',\n\tfz_xml => '${FZ_XML}'\n);" > ${FZconf}
if [ $? != 0 ]
then
failed "Failed to write FileZilla configuration file."
fi
if [ ! -z "$cs_psw" ]; then
UD=$(cmd /Q /C echo %USERDOMAIN% | sed 's/\r$//')
net stop "FileZilla Server"
sc config "FileZilla Server" obj= "${UD}\cyg_server" password= "$cs_psw" type= own
net start "FileZilla Server"
fi
else
if uname -a|grep -qv "x86_64"
then
ftpMethod="PureFTPd"
echo;
echo "Set the listen IP for the PureFTPd."
echo "Default is (${DEFAULT_IP}) to bind on all interfaces."
echo -n "Set listen IP [Default ${DEFAULT_IP}]: "
read ftp_ip
if [ -z "${ftp_ip}" ]
then
ftp_ip=$DEFAULT_IP
fi
echo
echo "Set the listen port for PureFTPd. The default should be fine for everyone."
echo "However, if you want to change it that can be done here, otherwise just press Enter."
echo -n "Set listen port [Default ${DEFAULT_FTP_PORT}]: "
read port
if [ -z "${ftp_port}" ]
then
ftp_port=$DEFAULT_FTP_PORT
fi
echo
echo "Passive-mode downloads."
echo "This is especially useful if the server is behind a firewall."
echo -n "Use only ports in the range?(yes|no)[Default no]: "
read passive_ftp
if [ -z "${passive_ftp}" -o "${passive_ftp}" != "yes" ]
then
ftp_pasv_range=""
else
echo "Enter passive ports range separated by colon (<first port>:<last port>)."
echo -n "[Default ${DEFAULT_FTP_PASV_RANGE}]: "
read ftp_pasv_range
if [ -z "${ftp_pasv_range}" ]
then
ftp_pasv_range=$DEFAULT_FTP_PASV_RANGE
fi
fi
fi
fi
fi
fi
if [ "${ftpMethod}" == "PureFTPd" ]
then
run_pureftpd=1
else
run_pureftpd=0
fi
echo "Writing Preferences file - $prefsfile"
prefs="%Cfg::Preferences = (\n"
prefs="${prefs}\tscreen_log_local => '${logLocalCopy}',\n"
prefs="${prefs}\tdelete_logs_after => '${deleteLogsAfter}',\n"
prefs="${prefs}\togp_manages_ftp => '${ogpManagesFTP}',\n"
prefs="${prefs}\tftp_method => '${ftpMethod}',\n"
prefs="${prefs}\togp_autorestart_server => '${autoRestart}',\n"
prefs="${prefs}\tprotocol_shutdown_waittime => '10',\n"
prefs="${prefs}\tlinux_user_per_game_server => '1',\n"
if [ "X${proftpd}" == "Xyes" ]
then
prefs="${prefs}\tproftpd_conf_path => '${proFTPdConfPath}',\n"
fi
prefs="${prefs});"
echo -e $prefs > $prefsfile
if [ $? != 0 ]
then
failed "Failed to write preferences file."
fi
echo "Writing bash script preferences file - $bashprefsfile"
echo -e "agent_auto_update=${autoUpdate}\nrun_pureftpd=${run_pureftpd}\nftp_port=${ftp_port}\nftp_ip=${ftp_ip}\nftp_pasv_range=${ftp_pasv_range}" > $bashprefsfile
if [ $? != 0 ]
then
failed "Failed to write MISC configuration file used by bash scripts."
fi
# Ensure all config files are owned by the installation owner
if [ -n "$agent_user" ]; then
# Ensure agent_user is valid and not root
if id "$agent_user" >/dev/null 2>&1 && [ "$agent_user" != "root" ]; then
chown "$agent_user" "$cfgfile" "$prefsfile" "$bashprefsfile" 2>/dev/null
fi
fi
if [ -n "$agent_user" ] && [ "$(id -u)" -eq 0 ] && id "$agent_user" >/dev/null 2>&1; then
chown "$agent_user:$agent_user" "$cfgfile" "$prefsfile" "$bashprefsfile"
fi
echo "Wrote ${cfgfile}"
echo "Wrote ${prefsfile}"
echo "Wrote ${bashprefsfile}"
echo
echo "Next: ensure the Panel remote-server record uses listen_ip=${listen_ip}, listen_port=${listen_port}, and the same key."

View file

@ -4,8 +4,8 @@
/********** CONFIG (panel DB) **********/
$db = [
'host' => 'localhost',
'user' => 'localuser',
'pass' => 'Pkloyn7yvpht!',
'user' => 'CHANGE_ME_DB_USER',
'pass' => 'CHANGE_ME_DB_PASSWORD',
'name' => 'panel'
];
$TABLE_PREFIX = 'gsp_';

View file

@ -4,7 +4,7 @@ The Linux agent can report meaningful server lifecycle events to the GSP Panel a
## Configuration
Set these values in `Cfg/Config.pm`:
Set these values in `Cfg/Config.pm` under the selected install directory:
```perl
agent_event_url => 'https://panel.example.com/agent_event_receiver.php',
@ -13,6 +13,12 @@ remote_server_id => '1',
If `agent_event_url` is empty, the agent attempts to derive it from `web_api_url`. The `key` value must match the Panel remote server encryption key because it is used to sign event payloads.
Default new install path:
```text
/home/gameserver/GSP/Cfg/Config.pm
```
## Authentication
Events are JSON POST requests signed with HMAC-SHA256:

View file

@ -4,6 +4,17 @@ Workspace reference: [`GSP-WORKSPACE.md`](../../GSP-WORKSPACE.md)
The Panel is authoritative. The Linux agent executes the work the Panel requests.
## Current Install And Config Defaults
New Linux installs default to:
- agent root: `/home/gameserver/GSP`
- run script: `gsp_agent_run`
- service: `gsp_agent.service`
- log file: `/home/gameserver/GSP/gsp_agent.log`
Legacy names such as `ogp_agent_run` remain wrappers or protocol compatibility details only.
## Legacy Workshop RPC
The dedicated Panel `steam_workshop` module still uses the legacy `steam_workshop` XML-RPC call.
@ -17,3 +28,14 @@ Current compatibility rule:
- each record stores mod string, Workshop item ID, title, installed folder/path, Workshop App ID, install status, and timestamps
- the generated job writes `<game_home>/WorkshopInstallStatus.json` as `running`, `completed`, or `failed`
- the generated job prints `GSP_WORKSHOP_INSTALL_COMPLETE` or `GSP_WORKSHOP_INSTALL_FAILED` so the Panel can avoid stale `Update in progress` displays if the generic update screen lingers
## Server Content Hook Runtime
The Linux agent prepares this runtime layout for generated content hooks:
- `_gsp_content/hooks/`
- `_gsp_content/generated/`
- `_gsp_content/runtime/`
- `_gsp_content/runtime/server_content.pids`
During stop/restart, hook watchdog PIDs are cleaned up before hook application PIDs. Main game server watchdog PIDs should not be written to `server_content.pids`.

View file

@ -1,95 +1,199 @@
# Linux Agent Operations Guide
Packaged copy of the instructions we keep in the staff wiki so you can view them offline or import them into any other knowledge base.
This guide covers installation, configuration, service management, and troubleshooting for the GSP Linux Agent.
## Purpose
The Linux agent (`ogp_agent.pl`) exposes the RPC endpoint that allows the GameServer Panel to install, start, stop, and monitor game servers on Linux hosts. Every host that runs customer games must run this service.
The Linux agent exposes the RPC endpoint that allows GameServer Panel to install, start, stop, update, and monitor game servers on Linux hosts.
## Supported platforms
## Supported Platforms
- Ubuntu 20.04/22.04/24.04 LTS
- Debian 11/12
- Rocky/AlmaLinux 8+
- Any modern distribution with Perl 5.30+, GNU Screen, and rsync
- Ubuntu 20.04, 22.04, and 24.04 LTS
- Debian 11 and 12
- other modern Linux distributions with Perl, GNU Screen, rsync, sudo, and systemd or compatible service management
## Installation (Ubuntu example)
## Prerequisites
For Debian and Ubuntu hosts:
```bash
sudo apt update
sudo apt install -y git curl rsync screen perl libxml-parser-perl libpath-class-perl libarchive-zip-perl libhttp-daemon-perl
sudo git clone https://github.com/GameServerPanel/GSP-Agent-Linux.git /opt/gsp-agent
cd /opt/gsp-agent
sudo bash install.sh
sudo bash agent_conf.sh -s "root-password" -u ogp_agent
chmod +x install_agent_prereqs.sh
sudo ./install_agent_prereqs.sh
```
`agent_conf.sh` writes `/home/ogp_agent/Cfg/Config.pm`. Set:
The prerequisite script installs required Perl modules, `screen`, `rsync`, `sudo`, `unzip`, `git`, `curl`, PureFTPd, and related utilities. It no longer attempts obsolete Ubuntu packages such as `libgcc1:i386`, `lib32gcc1`, `libcrypt-xxtea-perl`, or `libfile-basename-perl`.
| Key | Description |
| --- | ----------- |
| `listen_ip` | Interface to bind (use `0.0.0.0` unless you want to restrict access). |
| `listen_port` | TCP port exposed to the panel. Default is `12679`. |
| `key` | Shared secret copied from the panel → Administration → Game Servers. |
| `web_api_url` | HTTPS URL to `ogp_api.php` on the panel. |
| `agent_event_url` | HTTPS URL to `agent_event_receiver.php` on the panel for lifecycle activity-log events. |
| `remote_server_id` | Panel remote server ID for this agent. Required for signed lifecycle event delivery. |
| `stats_db_*` | Optional MySQL credentials for the resource stats cron. |
The script may show normal `needrestart` output about services, kernels, or VM guests. That output comes from the OS package manager and does not mean the GSP agent installer failed.
## Service management
## Guided Installation
```bash
sudo cp systemd/ogp_agent.service /etc/systemd/system/
sudo sed -i "s#{OGP_AGENT_PATH}#/opt/gsp-agent#g" /etc/systemd/system/ogp_agent.service
sudo systemctl daemon-reload
sudo systemctl enable --now ogp_agent
chmod +x install.sh agent_conf.sh gsp_agent_run ogp_agent_run
sudo ./install.sh
```
Logs live next to the binaries (`/opt/gsp-agent/ogp_agent.log`). Individual game servers stream to their own `console.log` files inside each home folder.
Default choices:
## Firewall checklist
- install directory: `/home/gameserver/GSP`
- Linux user: `gameserver`
- service name: `gsp_agent`
- log file: `/home/gameserver/GSP/gsp_agent.log`
1. Allow inbound TCP on the agent port.
2. Allow inbound/outbound UDP/TCP for the games you host.
3. Allow outbound HTTPS to the panel so the agent can talk to `ogp_api.php`.
The installer runs as root from the start. If launched without root and `sudo` is available, it re-executes itself through `sudo` before creating users, copying files, or installing systemd units.
## Upgrades
## Configuration Prompts
1. `cd /opt/gsp-agent && git pull`
2. Stop the service (`sudo systemctl stop ogp_agent`).
3. Re-run `bash install.sh` if new files were added.
4. Start the service (`sudo systemctl start ogp_agent`).
5. Verify the panel shows the agent as “online”.
The installer calls `agent_conf.sh --guided`. The guided configuration asks for the agent key/shared secret, listen IP, listen port, Panel API URL, Panel event receiver URL, remote server ID, FTP management setting, FTP method, game-server autorestart setting, and restart-time agent auto-update setting.
The agent key/shared secret must match the remote-server record in the GSP Panel.
## Configuration Files
Runtime config lives in:
- `/home/gameserver/GSP/Cfg/Config.pm`
- `/home/gameserver/GSP/Cfg/Preferences.pm`
- `/home/gameserver/GSP/Cfg/bash_prefs.cfg`
Important `Config.pm` keys:
- `logfile`
- `listen_ip`
- `listen_port`
- `key`
- `web_api_url`
- `agent_event_url`
- `remote_server_id`
Important `Preferences.pm` keys:
- `gsp_manages_ftp`
- `gsp_autorestart_server`
- `ftp_method`
- `PortValidationEnabled`
- `StartupValidationTimeoutSeconds`
- `PortCheckIntervalSeconds`
Compatibility aliases are still written for older panel/agent paths:
- `ogp_manages_ftp`
- `ogp_autorestart_server`
## Folder Layout
Default runtime folders:
- `Cfg/`
- `logs/`
- `tmp/`
- `screenlogs/`
- `runtime_status/`
- `events/`
- `_gsp_content/hooks/`
- `_gsp_content/generated/`
- `_gsp_content/runtime/`
The `_gsp_content/runtime/server_content.pids` file is reserved for generated server-content hook processes. During stop/restart cleanup, hook watchdog PIDs are stopped before hook application PIDs. The main game server watchdog PID should not be stored in this file.
## systemd Service
New installs use:
- `gsp_agent.service`
Useful commands:
```bash
sudo systemctl status gsp_agent
sudo systemctl restart gsp_agent
sudo systemctl stop gsp_agent
sudo journalctl -u gsp_agent -f
```
The generated unit runs as the selected agent user, sets `WorkingDirectory` to the selected install directory, and starts `gsp_agent_run`.
## Logs
- main agent log: `/home/gameserver/GSP/gsp_agent.log`
- systemd journal: `sudo journalctl -u gsp_agent -f`
- screen logs: `/home/gameserver/GSP/screenlogs/`
- activity event offline queue: `/home/gameserver/GSP/events/pending-events.jsonl`
## Manual Reconfiguration
```bash
cd /home/gameserver/GSP
./agent_conf.sh --guided --install-dir /home/gameserver/GSP --agent-user gameserver
sudo systemctl restart gsp_agent
```
Use noninteractive flags when automating:
```bash
./agent_conf.sh \
--install-dir /home/gameserver/GSP \
--agent-user gameserver \
--key CHANGE_ME \
--listen-ip 0.0.0.0 \
--listen-port 12679 \
--web-api-url https://panel.example.com/ogp_api.php \
--agent-event-url https://panel.example.com/agent_event_receiver.php \
--remote-server-id 1
```
## FTP Configuration
Default FTP mode is PureFTPd-compatible account management:
- `gsp_manages_ftp => '1'`
- `ftp_method => 'PureFTPd'`
Set `gsp_manages_ftp` to `0` if FTP accounts are managed outside the agent.
## Troubleshooting
- `tail -f ogp_agent.log` handshake failures usually mean the encryption key or port mismatches the panel entry.
- `journalctl -u ogp_agent` capture Perl stack traces and missing dependency errors.
- `screen -ls` confirm customer servers are running in screen sessions.
- `nc -vz panel.example.com 12679` from the panel host ensures the agent port is reachable.
Authentication failed or Panel shows agent offline:
## Server lifecycle tracking
- confirm `key` in `Cfg/Config.pm` matches the Panel remote-server key
- confirm `listen_port` is reachable from the Panel host
- check firewall rules
The Linux agent now keeps per-home PID metadata under:
Polkit or systemctl authentication failure:
- `runtime_status/pid-<home_id>.kv`
- run `sudo ./install.sh`
- do not start with a non-root partial install
- inspect `sudo journalctl -u gsp_agent -f`
This metadata is used by stop/restart verification in addition to screen and port checks.
Wrong install path or old `/home/gameserver/OGP` log path:
Stop escalation now verifies all of the following are cleared before success:
- rerun `./agent_conf.sh --guided --install-dir /home/gameserver/GSP`
- confirm `Cfg/Config.pm` has `logfile => '/home/gameserver/GSP/gsp_agent.log'`
- confirm the systemd unit `WorkingDirectory` points to `/home/gameserver/GSP`
1. managed screen session
2. tracked process PID(s)
3. listening game port
Missing packages:
Lifecycle control no longer uses game-home `SERVER_STOPPED` marker files.
- rerun `sudo ./install_agent_prereqs.sh`
- confirm `screen`, `rsync`, `perl`, `git`, `curl`, and required Perl modules are installed
See `docs/AGENT_ACTIVITY_EVENTS.md` for Panel activity-log event delivery, offline queue behavior, and troubleshooting.
Explicit stop intent and autorestart suppression are now controlled through agent-owned runtime status hints (`STOPPING`/`STOPPED`) and verified runtime checks.
Service failed:
Restart remains stop-first and waits 60 seconds, then re-verifies stop completion before starting again to avoid duplicate instances.
- run `sudo systemctl status gsp_agent`
- run `sudo journalctl -u gsp_agent -f`
- run `perl -c /home/gameserver/GSP/ogp_agent.pl`
## Related docs
Config missing or invalid:
- [`GSP/documentation/admin-guide.md`](https://github.com/GameServerPanel/GSP/tree/main/documentation) Panel-side instructions plus XML authoring notes.
- [`GSP-Agent-Windows/documentation/agent-guide.md`](https://github.com/GameServerPanel/GSP-Agent-Windows/tree/main/documentation/agent-guide.md) Windows counterpart.
- run `./agent_conf.sh --guided`
- replace placeholder `CHANGE_ME_PANEL_AGENT_KEY`
- verify `Cfg/Config.pm` is readable by the agent user
## Clean Reinstall
```bash
sudo systemctl stop gsp_agent || true
sudo systemctl disable gsp_agent || true
sudo rm -f /etc/systemd/system/gsp_agent.service
sudo systemctl daemon-reload
```
Only remove `/home/gameserver/GSP` after confirming it does not contain customer server data, logs, SteamCMD data, or local configuration that must be preserved.

60
gsp_agent_run Executable file
View file

@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -euo pipefail
AGENTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
AGENT="${AGENTDIR}/ogp_agent.pl"
PID_FILE=""
TIMEOUT=10
while [ "$#" -gt 0 ]; do
case "$1" in
-pidfile)
PID_FILE="${2:-}"
shift 2
;;
*)
shift
;;
esac
done
mkdir -p "${AGENTDIR}/logs" "${AGENTDIR}/screenlogs" "${AGENTDIR}/tmp" "${AGENTDIR}/_gsp_content/hooks" "${AGENTDIR}/_gsp_content/generated" "${AGENTDIR}/_gsp_content/runtime"
touch "${AGENTDIR}/_gsp_content/runtime/server_content.pids" 2>/dev/null || true
if [ "$(id -u)" -eq 0 ]; then
echo "ERROR: Do not run the GSP agent as root. Run it as the configured agent user." >&2
exit 1
fi
if [ ! -f "${AGENTDIR}/Cfg/Config.pm" ]; then
echo "ERROR: Missing ${AGENTDIR}/Cfg/Config.pm. Run ./agent_conf.sh --guided." >&2
exit 1
fi
if grep -Eq "CHANGE_ME_PANEL_AGENT_KEY|key[[:space:]]*=>[[:space:]]*''" "${AGENTDIR}/Cfg/Config.pm"; then
echo "ERROR: ${AGENTDIR}/Cfg/Config.pm still has a placeholder agent key." >&2
exit 1
fi
if [ ! -x "$AGENT" ]; then
chmod ug+x "$AGENT" 2>/dev/null || true
fi
if [ -n "$PID_FILE" ]; then
echo "$$" > "$PID_FILE"
fi
cd "$AGENTDIR"
while true; do
perl "$AGENT" "$@" || rc=$?
rc="${rc:-0}"
if [ "$rc" -eq 0 ]; then
echo "$(date): GSP Agent stopped cleanly"
exit 0
fi
echo "$(date): GSP Agent exited with status ${rc}; restarting in ${TIMEOUT}s" >&2
sleep "$TIMEOUT"
unset rc
done

View file

@ -7,16 +7,16 @@ agent_user=OGP_USER
# Start function.
start() {
echo "Starting OGP Agent..."
echo "Starting GSP Agent..."
cd $agent_dir
su -c "screen -d -m -t ogp_agent -c ogp_screenrc -S ogp_agent ./ogp_agent_run -pidfile ogp_agent_run.pid" $agent_user &> $agent_dir/ogp_agent.svc &
su -c "screen -d -m -t gsp_agent -c ogp_screenrc -S gsp_agent ./gsp_agent_run -pidfile gsp_agent_run.pid" $agent_user &> $agent_dir/gsp_agent.svc &
echo
}
# Stop function.
stop() {
echo "Stopping OGP Agent..."
kill `cat $agent_dir/ogp_agent_run.pid`
echo "Stopping GSP Agent..."
kill `cat $agent_dir/gsp_agent_run.pid`
}
restart() {
@ -35,7 +35,7 @@ case $1 in
restart
;;
*)
echo "Usage: ogp_agent {start|stop|restart}"
echo "Usage: gsp_agent {start|stop|restart}"
exit 1
;;
esac

View file

@ -8,8 +8,8 @@
# Should-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start and stop the OGP Agent
# Description: Start and stop the OGP Agent
# Short-Description: Start and stop the GSP Agent
# Description: Start and stop the GSP Agent
### END INIT INFO
#
@ -26,9 +26,9 @@ then
fi
start() {
if [ -e "$agent_dir/ogp_agent_run.pid" ]
if [ -e "$agent_dir/gsp_agent_run.pid" ]
then
pid=$(cat $agent_dir/ogp_agent_run.pid)
pid=$(cat $agent_dir/gsp_agent_run.pid)
out=$(kill -0 $pid > /dev/null 2>&1)
if [ $? == 0 ]
then
@ -90,14 +90,14 @@ start() {
fi
cd $agent_dir
out=$(su -c "screen -d -m -t ogp_agent -c ogp_screenrc -S ogp_agent ./ogp_agent_run -pidfile ogp_agent_run.pid" $agent_user >/dev/null 2>&1)
out=$(su -c "screen -d -m -t gsp_agent -c ogp_screenrc -S gsp_agent ./gsp_agent_run -pidfile gsp_agent_run.pid" $agent_user >/dev/null 2>&1)
return 0
}
stop() {
if [ -e "$agent_dir/ogp_agent_run.pid" ]
if [ -e "$agent_dir/gsp_agent_run.pid" ]
then
pid=$(cat $agent_dir/ogp_agent_run.pid)
pid=$(cat $agent_dir/gsp_agent_run.pid)
kill -0 $pid > /dev/null 2>&1
if [ $? == 0 ]
then
@ -126,7 +126,7 @@ case "${1:-''}" in
RETVAL=$?
;;
*)
echo "Usage: service ogp_agent start|stop|restart"
echo "Usage: service gsp_agent start|stop|restart"
exit 1
;;
esac

View file

@ -12,14 +12,13 @@ depend() {
}
start() {
ebegin "Starting OGP Agent"
start-stop-daemon --verbose --chdir $agent_dir --start --background --user $agent_user -e PWD="$agent_dir" --exec screen -d -m -t ogp_agent -c ogp_screenrc -S ogp_agent ./ogp_agent_run -pidfile ogp_agent_run.pid
eend $? "Failed to start OGP Agent"
ebegin "Starting GSP Agent"
start-stop-daemon --verbose --chdir $agent_dir --start --background --user $agent_user -e PWD="$agent_dir" --exec screen -d -m -t gsp_agent -c ogp_screenrc -S gsp_agent ./gsp_agent_run -pidfile gsp_agent_run.pid
eend $? "Failed to start GSP Agent"
}
stop() {
ebegin "Stopping OGP Agent"
start-stop-daemon --stop --quiet --pidfile $agent_dir/ogp_agent_run.pid
eend $? "Failed to stop OGP Agent"
ebegin "Stopping GSP Agent"
start-stop-daemon --stop --quiet --pidfile $agent_dir/gsp_agent_run.pid
eend $? "Failed to stop GSP Agent"
}

View file

@ -1,16 +1,16 @@
#!/bin/sh
#
# Startup/shutdown script for the OGP Agent.
# Startup/shutdown script for the GSP Agent.
#
# Linux chkconfig stuff:
#
# chkconfig: 2345 88 10
# description: Startup/shutdown script for the OGP Agent
# description: Startup/shutdown script for the GSP Agent
agent_dir=OGP_AGENT_DIR
agent_user=OGP_USER
service=ogp_agent
service=gsp_agent
# Source function library.
if [ -f /etc/rc.d/init.d/functions ] ; then
@ -23,7 +23,7 @@ if [ "$( whoami )" != "root" ]
then
if [ -f "/usr/bin/sudo" ] && [ "$( groups $agent_user | grep "\bsudo\b" )" != "" ]
then
sudo /etc/init.d/ogp_agent ${1:-''}
sudo /etc/init.d/gsp_agent ${1:-''}
exit
else
echo "Permission denied."
@ -32,9 +32,9 @@ then
fi
start() {
echo -n "Starting OGP Agent: "
if [ -e "$agent_dir/ogp_agent_run.pid" ]; then
PID=`cat $agent_dir/ogp_agent_run.pid`
echo -n "Starting GSP Agent: "
if [ -e "$agent_dir/gsp_agent_run.pid" ]; then
PID=`cat $agent_dir/gsp_agent_run.pid`
RET=$(kill -s 0 $PID &> /dev/null; echo $?)
if [ $RET -eq 0 ]; then
echo -n "already running."
@ -100,22 +100,22 @@ start() {
fi
cd $agent_dir
su -c "screen -d -m -t ogp_agent -c ogp_screenrc -S ogp_agent ./ogp_agent_run -pidfile ogp_agent_run.pid" $agent_user &> $agent_dir/ogp_agent.svc &
su -c "screen -d -m -t gsp_agent -c ogp_screenrc -S gsp_agent ./gsp_agent_run -pidfile gsp_agent_run.pid" $agent_user &> $agent_dir/gsp_agent.svc &
echo -n "started successfully."
bold=`tput bold`
normal=`tput sgr0`
echo
echo "Use ${bold}sudo su -c 'screen -S ogp_agent -r' $agent_user${normal} to attach the agent screen,"
echo "Use ${bold}sudo su -c 'screen -S gsp_agent -r' $agent_user${normal} to attach the agent screen,"
echo "and ${bold}ctrl+A+D${normal} to detach it."
return 0
}
stop() {
# Stop daemon
echo -n "Stopping OGP Agent: "
if [ -f $agent_dir/ogp_agent_run.pid ]
echo -n "Stopping GSP Agent: "
if [ -f $agent_dir/gsp_agent_run.pid ]
then
PID=`cat $agent_dir/ogp_agent_run.pid`
PID=`cat $agent_dir/gsp_agent_run.pid`
RET=$(kill $PID &> /dev/null; echo $?)
if [ $RET -ne 0 ]; then
echo -n "not running."
@ -123,7 +123,7 @@ stop() {
echo -n "stopped successfully."
fi
else
echo -n "PID file not found ($agent_dir/ogp_agent_run.pid)"
echo -n "PID file not found ($agent_dir/gsp_agent_run.pid)"
fi
echo
return 0
@ -145,7 +145,7 @@ case "$1" in
RETVAL=$?
;;
*)
echo "Usage: service ogp_agent start|stop|restart"
echo "Usage: service gsp_agent start|stop|restart"
RETVAL=1
echo
;;

496
install.sh Normal file → Executable file
View file

@ -1,351 +1,207 @@
#!/bin/bash
#!/usr/bin/env bash
#
# OGP - Open Game Panel
# Copyright (C) Copyright (C) 2008 - 2013 The OGP Development Team
#
# http://www.opengamepanel.org/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
set -euo pipefail
# Parameters can be passed into the install.sh script to automate OGP updates
# $1 = Operation Type (Used as opType)
# $2 = OGP User (Used as ogpAgentUser)
# $3 = OGP User Sudo Pass (Used as ogpUserPass)
# $4 = Install Path (Used as ogpInsPath)
DEFAULT_INSTALL_DIR="/home/gameserver/GSP"
DEFAULT_AGENT_USER="gameserver"
DEFAULT_SERVICE_NAME="gsp_agent"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ORIG_ARGS=("$@")
usage() {
cat <<EOF
GSP Linux Agent guided installer
####################
# FUNCTIONs #
####################
Usage: sudo bash install.sh [options]
detectSystemD(){
# Ops require sudo
initProcessStr=$(ps -p 1 | awk '{print $4}' | tail -n 1)
if [ "$initProcessStr" == "systemd" ]; then
systemdPresent=1
if [ -e "/lib/systemd/system" ]; then
SystemDDir="/lib/systemd/system"
elif [ -e "/etc/systemd/system" ]; then
SystemDDir="/etc/systemd/system"
else
checkDir=$(ps -eaf|grep '[s]ystemd' | head -n 1 | awk '{print $8}' | grep -o ".*systemd/")
if [ -e "${checkDir}system" ]; then
SystemDDir="$checkDir"
else
# Can't find systemd dir
systemdPresent=
SystemDDir=
fi
fi
fi
Options:
--install-dir PATH Install directory. Default: ${DEFAULT_INSTALL_DIR}
--agent-user USER Linux user that runs the agent. Default: ${DEFAULT_AGENT_USER}
--service-name NAME systemd service name. Default: ${DEFAULT_SERVICE_NAME}
--no-service Configure files but do not install a systemd service.
--no-prereqs Do not offer to run install_agent_prereqs.sh.
--help Show this help.
Run install_agent_prereqs.sh first or allow this installer to run it.
EOF
}
copySystemDInit(){
AGENTDIR=${agent_home}
sudoPass=${sudo_password}
if [ -e "${AGENTDIR}/systemd/ogp_agent.service" ]; then
if [ ! -z "$systemdPresent" ] && [ ! -z "$SystemDDir" ]; then
echo -e "systemd detected as the init system with a directory of $SystemDDir. Updating OGP agent to use systemd service init script."
if [ -e "/etc/init.d/ogp_agent" ] && [ ! -e "${AGENTDIR}/ogp_agent_init" ]; then
echo -e "Taking care of existing OGP files."
echo "$sudoPass" | sudo -S -p "" service ogp_agent stop
# Kill any remaining ogp agent process
ogpPID=$(ps -ef | grep -v grep | grep ogp_agent.pl | head -n 1 | awk '{print $3}')
if [ ! -z "$ogpPID" ]; then
echo "$sudoPass" | sudo -S -p "" kill -9 "$ogpPID"
fi
echo "$sudoPass" | sudo -S -p "" cp "/etc/init.d/ogp_agent" "${AGENTDIR}/ogp_agent_init"
echo "$sudoPass" | sudo -S -p "" chmod +x "${AGENTDIR}/ogp_agent_init"
echo "$sudoPass" | sudo -S -p "" update-rc.d ogp_agent disable
echo "$sudoPass" | sudo -S -p "" chkconfig ogp_agent off
echo "$sudoPass" | sudo -S -p "" rm -rf "/etc/init.d/ogp_agent"
fi
if [ ! -e "$SystemDDir/ogp_agent.service" ]; then
echo -e "Copying ogp_agent systemd service file to $SystemDDir"
echo "$sudoPass" | sudo -S -p "" cp "${AGENTDIR}/systemd/ogp_agent.service" "$SystemDDir"
echo "$sudoPass" | sudo -S -p "" sed -i "s#{OGP_AGENT_PATH}#$AGENTDIR#g" "${SystemDDir}/ogp_agent.service"
fi
fi
fi
ask() {
local prompt="$1"
local default_value="$2"
local answer
read -r -p "${prompt} [${default_value}]: " answer
printf '%s' "${answer:-$default_value}"
}
#####################
# CODE ##########
#####################
ask_yes_no() {
local prompt="$1"
local default_value="$2"
local answer
while true; do
read -r -p "${prompt} [${default_value}]: " answer
answer="${answer:-$default_value}"
case "$answer" in
[yY]|[yY][eE][sS]) return 0 ;;
[nN]|[nN][oO]) return 1 ;;
*) echo "Enter yes or no." ;;
esac
done
}
# Parameter notifications
if [ ! -z "$1" ]; then
echo -n "Received operation type of $1 as a parameter."
opType="$1"
fi
if [ ! -z "$2" ]; then
echo -n "Received OGP user of $2 as a parameter."
ogpAgentUser="$2"
fi
if [ ! -z "$3" ]; then
echo -n "Received OGP sudo password of $3 as a parameter."
ogpUserPass="$3"
fi
if [ ! -z "$4" ]; then
echo -n "Received OGP agent path of $4 as a parameter."
ogpInsPath="$4"
fi
failed()
{
echo "ERROR: ${1}"
fail() {
echo "ERROR: $*" >&2
exit 1
}
if [ "X`which screen &> /dev/null;echo $?`" != "X0" ]; then
failed "You need to install software called 'screen', before you can install OGP agent.";
fi
if [ "X`which sed &> /dev/null;echo $?`" != "X0" ]; then
failed "You need to install software called 'sed', before you can install OGP agent.";
fi
echo
clear
echo "#######################################################################"
echo "# OGP Agent installation and configuration"
echo "# This program will:"
echo "# Create ${DEFAULT_AGENT_HOME} or user defined directory"
echo "# Copy ogp_agent files to ${DEFAULT_AGENT_HOME} or user defined dir"
echo "# Copy the ogp_agent init script to /etc/init.d or user defined dir"
echo "# Create an initial configuration file"
echo "# Thank you for using OGP. http://www.opengamepanel.org/"
echo "#######################################################################"
echo
if [ "X`which rsync &> /dev/null;echo $?`" != "X0" ]; then
echo "*** WARNING **** missing rsync client. It is not required, but needed to use the rsync game installer";
fi
if [ "X`whoami`" != "Xroot" ]
then
echo
echo "Detected non-root install..."
username=`whoami`
echo -n "Enter sudo password: ";
read sudo_password;
else
echo "Next you need to type the username of the user that owns the agent homes.";
echo "This user must own (have access to) all the game home directories that you"
echo "want to run with this agent and must to be in sudoers list so it can perform"
echo "administrative tasks.";echo
while [ 1 ]
do
if [ ! -z "$ogpAgentUser" ] ; then
username="$ogpAgentUser"
else
echo -n "Enter user name: ";
read username;
fi
if [ -z "$ogpUserPass" ] ; then
echo -n "Enter user password: ";
read sudo_password;
else
sudo_password="$ogpUserPass"
fi
if [ -z "${username}" ]
then
echo "Username can not be empty.";echo
continue;
fi
if [ "Xroot" == "X${username}" ]
then
echo "'${username}' can not be used as user for agent.";echo
continue;
fi
ID_OF_USER=`id -u ${username} 2> /dev/null`
if [ $? != 0 ]
then
echo "User with entered username (${username}) does not exist.";echo
continue;
fi
break;
done
fi
detectSystemD
readonly AGENT_USER_HOME="`cat /etc/passwd | grep "^${username}:" | cut -d':' -f6`/OGP/"
echo
echo "Next the directory for the agent needs to be chosen. The default directory";
echo "Should be fine in most of the cases."
echo
if [ -z "$ogpInsPath" ]; then
echo "Where do you want to install the agent?"
echo -n "[Default is ${AGENT_USER_HOME}]: "
read agent_home
else
agent_home="$ogpInsPath"
fi
if [ -z "${agent_home}" ]
then
agent_home=$AGENT_USER_HOME
fi
# Try to prevent users from doing damage to their systems.
case ${agent_home} in
/bin*|/boot*|/dev*|/etc*|/lib*|/proc*|/root*|/sbin*|/sys*|/)
failed "The agent home can not be ${agent_home}";
;;
esac
echo "Agent install dir is ${agent_home}"
echo
agent_home=${agent_home%/}
if [ ! -e ${agent_home} ]
then
mkdir -p ${agent_home} || failed "Failed to create the directory (${agent_home}) for agent."
elif [ ! -w ${agent_home} ]
then
failed "You do not have write permissions to the directory you assigned as agent home (${agent_home})."
fi
if [ "X`whoami`" == "Xroot" ];
then
readonly DEFAULT_INIT_DIR="/etc/init.d/"
else
readonly DEFAULT_INIT_DIR="${agent_home}/"
fi
if [ -z "$systemdPresent" ]; then
if [ "X`uname`" != "XLinux" ]
then
echo
echo "Detected non-Linux platform..."
echo "Where do you want to put the init scripts?"
echo -n "[Default ${DEFAULT_INIT_DIR}]: "
read init_dir
require_root() {
if [ "$(id -u)" -eq 0 ]; then
return 0
fi
if [ -z "$opType" ]; then
echo "Where do you want to put the init scripts?"
echo -n "[Default ${DEFAULT_INIT_DIR}]:"
read init_dir
if command -v sudo >/dev/null 2>&1; then
echo "System service installation requires root. Re-running through sudo..."
exec sudo -E bash "$0" "$@"
fi
fail "Run this installer as root: sudo bash install.sh"
}
else
init_dir=${agent_home}
fi
validate_safe_path() {
local path="$1"
case "$path" in
""|"/"|/bin|/bin/*|/boot|/boot/*|/dev|/dev/*|/etc|/etc/*|/lib|/lib/*|/lib64|/lib64/*|/proc|/proc/*|/root|/root/*|/run|/run/*|/sbin|/sbin/*|/sys|/sys/*|/usr|/usr/*|/var|/var/*)
fail "Refusing unsafe install directory: $path"
;;
esac
}
if [ -z "${init_dir}" ]
then
init_dir=${DEFAULT_INIT_DIR}
fi
init_dir=${init_dir%/}
echo "Copying all files and folders to installation directory..."
# Use rsync if available, otherwise fallback to find/cp
if command -v rsync >/dev/null 2>&1; then
rsync -a --exclude install.sh ./ "${agent_home}/" || failed "Failed to copy files with rsync to ${agent_home}."
else
find . -mindepth 1 -not -name install.sh -exec cp -rf --parents {} "${agent_home}/" \;
fi
install_service() {
local install_dir="$1"
local agent_user="$2"
local service_name="$3"
local unit_path="/etc/systemd/system/${service_name}.service"
# Create the directory for configs.
mkdir -p ${agent_home}/Cfg || failed "Failed to create ${agent_home}/Cfg dir."
command -v systemctl >/dev/null 2>&1 || {
echo "systemd was not detected. Skipping service installation."
return 0
}
cp "${install_dir}/systemd/gsp_agent.service" "$unit_path"
sed -i \
-e "s#{GSP_AGENT_PATH}#${install_dir}#g" \
-e "s#{GSP_AGENT_USER}#${agent_user}#g" \
-e "s#{GSP_AGENT_RUN_SCRIPT}#${install_dir}/gsp_agent_run#g" \
-e "s#{GSP_AGENT_PID_FILE}#${install_dir}/gsp_agent_run.pid#g" \
"$unit_path"
systemctl daemon-reload
systemctl enable "$service_name.service"
if ask_yes_no "Start ${service_name}.service now?" "yes"; then
systemctl restart "$service_name.service"
fi
}
INSTALL_DIR=""
AGENT_USER=""
SERVICE_NAME=""
INSTALL_SERVICE=1
OFFER_PREREQS=1
while [ "$#" -gt 0 ]; do
case "$1" in
--install-dir) INSTALL_DIR="${2:-}"; shift 2 ;;
--agent-user) AGENT_USER="${2:-}"; shift 2 ;;
--service-name) SERVICE_NAME="${2:-}"; shift 2 ;;
--no-service) INSTALL_SERVICE=0; shift ;;
--no-prereqs) OFFER_PREREQS=0; shift ;;
--help|-h) usage; exit 0 ;;
*) fail "Unknown option: $1" ;;
esac
done
require_root "${ORIG_ARGS[@]}"
echo "GSP Linux Agent installer"
echo
echo "This installer configures the Linux execution agent for GameServer Panel."
echo "Use the same key/password that is configured for this remote server in the Panel."
echo
if [ -e /etc/gentoo-release ]
then
echo "Copying ogp_agent.init.gentoo to $init_dir - Gentoo Specific Init"
init_file_template='includes/ogp_agent.init.gentoo'
elif [ -e /etc/sysconfig ] && [ ! -e /etc/debian_version ]
then
echo "Copying ogp_agent.init.rh to $init_dir - Redhat Style Init (also SuSE, and Mandrake)"
init_file_template='includes/ogp_agent.init.rh'
elif [ -e /etc/debian_version ]
then
echo "Copying ogp_agent.init.dbn to $init_dir - Debian Style Init"
init_file_template='includes/ogp_agent.init.dbn'
else
echo "Copying the generic init script because I don't know what kind of Linux distro this is"
init_file_template='includes/ogp_agent.init'
if [ "$OFFER_PREREQS" -eq 1 ] && [ -x "${SCRIPT_DIR}/install_agent_prereqs.sh" ]; then
if ask_yes_no "Run install_agent_prereqs.sh before installing?" "yes"; then
bash "${SCRIPT_DIR}/install_agent_prereqs.sh"
fi
elif [ "$OFFER_PREREQS" -eq 1 ]; then
echo "Prerequisite installer is not executable. Run: chmod +x install_agent_prereqs.sh && sudo ./install_agent_prereqs.sh"
fi
init_file=${init_dir}/ogp_agent
INSTALL_DIR="${INSTALL_DIR:-$(ask "Install directory" "$DEFAULT_INSTALL_DIR")}"
AGENT_USER="${AGENT_USER:-$(ask "Agent Linux user" "$DEFAULT_AGENT_USER")}"
SERVICE_NAME="${SERVICE_NAME:-$(ask "systemd service name" "$DEFAULT_SERVICE_NAME")}"
cp -f $init_file_template $init_file || failed "Failed to create init file ($init_file)."
# Next we replace the OGP_AGENT_DIR with the actual dir in init file.
sed -i "s|OGP_AGENT_DIR|${agent_home}|" ${init_file} || failed "Failed to modify init file ($init_file)."
sed -i "s|OGP_USER|${username}|" ${init_file} || failed "Failed to modify init file ($init_file)."
chmod a+x $init_file
validate_safe_path "$INSTALL_DIR"
INSTALL_DIR="${INSTALL_DIR%/}"
if [ "$init_dir" == "$agent_home" ] && [ ! -z "$systemdPresent" ]; then
init_file=${init_dir}/ogp_agent_init
mv ${init_dir}/ogp_agent ${init_dir}/ogp_agent_init
copySystemDInit
if ! id "$AGENT_USER" >/dev/null 2>&1; then
if ask_yes_no "User ${AGENT_USER} does not exist. Create it?" "yes"; then
useradd --create-home --shell /bin/bash "$AGENT_USER"
else
fail "Agent user is required."
fi
fi
echo;
echo "Changing files owner to user ${username}...";
# Group of the files in agent_home can differ from the user so
# lets leave them as they are. So no chown user:group here.
chown --preserve-root -R ${username} ${agent_home} || failed "Failed to chmod the agent_home ${agent_home} for user ${username}."
echo "Setting Permissions on files in ${agent_home}..."
if [ -e "${init_dir}/ogp_agent" ]; then
chmod 750 ${init_dir}/ogp_agent || failed "Failed to chmod ${init_dir}/ogp_agent to 750."
fi
if [ -e "${init_dir}/ogp_agent_init" ]; then
chmod 750 ${init_dir}/ogp_agent_init || failed "Failed to chmod ${init_dir}/ogp_agent_init to 750."
fi
chmod 750 ${agent_home}/ogp_agent.pl || failed "Failed to chmod ${agent_home}/ogp_agent.pl to 750."
chmod 750 ${agent_home}/ogp_agent_run || failed "Failed to chmod ${agent_home}/ogp_agent_run to 750."
echo "Install Successful!"
echo "Now configuring..."
echo ""
# Run the configuration script
chmod +x ${agent_home}/agent_conf.sh
if [ -z "$opType" ]; then
bash ${agent_home}/agent_conf.sh -s $sudo_password -u $username
mkdir -p "$INSTALL_DIR"
if [ "$SCRIPT_DIR" != "$INSTALL_DIR" ]; then
rsync -a --exclude='.git/' --exclude='Cfg/Config.pm' --exclude='Cfg/Preferences.pm' --exclude='Cfg/bash_prefs.cfg' "${SCRIPT_DIR}/" "${INSTALL_DIR}/"
fi
echo "Attempting to start the Open Game Panel (OGP) agent..."
mkdir -p \
"${INSTALL_DIR}/Cfg" \
"${INSTALL_DIR}/logs" \
"${INSTALL_DIR}/tmp" \
"${INSTALL_DIR}/screenlogs" \
"${INSTALL_DIR}/runtime_status" \
"${INSTALL_DIR}/events" \
"${INSTALL_DIR}/_gsp_content/hooks" \
"${INSTALL_DIR}/_gsp_content/generated" \
"${INSTALL_DIR}/_gsp_content/runtime"
systemctl daemon-reload
chkconfig ogp_agent on
rc-update add ogp_agent default
update-rc.d ogp_agent defaults
systemctl enable ogp_agent.service
service ogp_agent restart
touch "${INSTALL_DIR}/_gsp_content/runtime/server_content.pids"
echo;
echo "OGP installation complete!"
echo
chmod +x "${INSTALL_DIR}/gsp_agent_run" "${INSTALL_DIR}/ogp_agent_run" "${INSTALL_DIR}/agent_conf.sh" "${INSTALL_DIR}/install_agent_prereqs.sh" 2>/dev/null || true
chown -R "${AGENT_USER}:${AGENT_USER}" "$INSTALL_DIR"
exit 0
echo
echo "Configuring agent files..."
bash "${INSTALL_DIR}/agent_conf.sh" \
--install-dir "$INSTALL_DIR" \
--agent-user "$AGENT_USER" \
--guided
if [ "$INSTALL_SERVICE" -eq 1 ]; then
install_service "$INSTALL_DIR" "$AGENT_USER" "$SERVICE_NAME"
fi
cat <<EOF
GSP Linux Agent installation complete.
Config files:
${INSTALL_DIR}/Cfg/Config.pm
${INSTALL_DIR}/Cfg/Preferences.pm
${INSTALL_DIR}/Cfg/bash_prefs.cfg
Logs:
${INSTALL_DIR}/gsp_agent.log
${INSTALL_DIR}/screenlogs/
Useful commands:
sudo systemctl status ${SERVICE_NAME}
sudo journalctl -u ${SERVICE_NAME} -f
tail -f ${INSTALL_DIR}/gsp_agent.log
Panel configuration still required:
1. Add or edit the remote server in the GSP Panel.
2. Use listen IP/port from Config.pm.
3. Use the same agent key/shared secret from Config.pm.
4. Open the configured agent port in the firewall.
EOF

132
install_agent_prereqs.sh Normal file → Executable file
View file

@ -1,68 +1,90 @@
#!/bin/bash
# OGP Agent Prerequisites Installer for Ubuntu 22.04+
# This script installs all required packages for running OGP Agent
# Usage: sudo bash install_agent_prereqs.sh
#!/usr/bin/env bash
set -e
set -euo pipefail
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run as root (use sudo)"
exit 1
echo "This script installs OS packages and must be run as root."
echo "Run: sudo ./install_agent_prereqs.sh"
exit 1
fi
# Update package lists
if ! command -v apt-get >/dev/null 2>&1 || ! command -v dpkg >/dev/null 2>&1; then
echo "This prerequisite installer currently supports apt/dpkg systems only."
echo "Install equivalent Perl, screen, rsync, sudo, unzip, git, curl, and FTP packages manually."
exit 1
fi
echo "Installing GSP Linux Agent prerequisites for Debian/Ubuntu."
echo "Package manager output from needrestart about services, VM guests, or kernel state is normal OS maintenance output."
apt-get update
# Install core required packages from original prerequisites
apt-get install -y \
libxml-parser-perl \
libpath-class-perl \
perl-modules \
screen \
rsync \
sudo \
e2fsprogs \
unzip \
subversion \
libarchive-extract-perl \
pure-ftpd \
libarchive-zip-perl \
libc6 \
libgcc1 \
git \
curl \
libhttp-daemon-perl
required_packages=(
perl
libxml-parser-perl
libpath-class-perl
libarchive-extract-perl
libarchive-zip-perl
libhttp-daemon-perl
libfrontier-rpc-perl
libfile-copy-recursive-perl
libschedule-cron-perl
libio-compress-perl
libcompress-raw-zlib-perl
libfile-find-rule-perl
libwww-perl
screen
rsync
sudo
e2fsprogs
unzip
subversion
git
curl
ca-certificates
pure-ftpd
libc6
)
# Install 32-bit compatibility libraries (may fail on some systems, continue anyway)
apt-get install -y libc6-i386 || echo "Warning: Could not install libc6-i386"
apt-get install -y libgcc1:i386 || echo "Warning: Could not install libgcc1:i386"
apt-get install -y lib32gcc1 || echo "Warning: Could not install lib32gcc1"
optional_packages=(
libdbi-perl
libdbd-mysql-perl
libfcgi-perl
apache2
php
php-mysql
)
# Install additional modern packages for current OGP agent
apt-get install -y \
libdbi-perl \
libdbd-mysql-perl \
libfrontier-rpc-perl \
libfile-copy-recursive-perl \
libcrypt-xxtea-perl \
libschedule-cron-perl \
libmime-base64-perl \
libgetopt-long-descriptive-perl \
libio-compress-perl \
libcompress-raw-zlib-perl \
libfile-find-rule-perl \
libfile-basename-perl \
libfcgi-perl \
libwww-perl
apt-get install -y "${required_packages[@]}"
# Optional: For FTP management (pure-ftpd already installed above)
# apt-get install -y proftpd-basic
for pkg in "${optional_packages[@]}"; do
if ! apt-get install -y "$pkg"; then
echo "Warning: optional package ${pkg} could not be installed."
fi
done
# Optional: For web panel integration
apt-get install -y apache2 php php-mysql || echo "Warning: Optional web packages could not be installed"
echo
echo "32-bit compatibility packages are useful for some legacy SteamCMD/game-server binaries."
read -r -p "Enable i386 architecture and install 32-bit compatibility packages? [yes]: " install_i386
install_i386="${install_i386:-yes}"
if [[ "$install_i386" =~ ^[Yy]([Ee][Ss])?$ ]]; then
if ! dpkg --print-foreign-architectures | grep -qx i386; then
dpkg --add-architecture i386
apt-get update
fi
for pkg in libc6-i386 lib32gcc-s1 libgcc-s1:i386; do
if ! apt-get install -y "$pkg"; then
echo "Warning: optional 32-bit package ${pkg} could not be installed."
fi
done
fi
# Done
cat <<'EOF'
echo "All required packages for OGP Agent have been installed."
echo "Note: Some 32-bit compatibility libraries may not be available on all systems."
echo "This is normal for modern 64-bit only distributions."
Prerequisite installation finished.
Notes:
- MIME::Base64, File::Basename, and Getopt::Long are Perl core modules and are not installed as separate apt packages.
- Crypt::XXTEA is bundled in this repository under Crypt/XXTEA.pm, so libcrypt-xxtea-perl is not required from apt.
- needrestart messages about services or VM guests are normal package-manager output after dependency installation.
EOF

View file

@ -1,10 +1,9 @@
#!/usr/bin/perl
#
# OGP - Open Game Panel
# GameServer Panel Linux Agent
# Forked from the Open Game Panel agent.
# Copyright (C) 2008 - 2018 The OGP Development Team
#
# http://www.opengamepanel.org/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
@ -125,6 +124,21 @@ GetOptions(
'log-stdout' => \$log_std_out
);
sub preference_value
{
my ($primary, $legacy, $default) = @_;
return $Cfg::Preferences{$primary} if(defined($Cfg::Preferences{$primary}));
return $Cfg::Preferences{$legacy} if(defined($legacy) && defined($Cfg::Preferences{$legacy}));
return $default;
}
sub preference_enabled
{
my ($primary, $legacy, $default) = @_;
my $value = preference_value($primary, $legacy, $default);
return defined($value) && $value eq "1" ? 1 : 0;
}
# Starting the agent as root user is not supported anymore.
if ($< == 0)
{
@ -188,6 +202,76 @@ sub agent_event_remote_server_id
return "";
}
sub prepare_server_content_runtime_without_decrypt
{
my ($home_path) = @_;
return if(!defined($home_path) || $home_path eq "");
foreach my $dir (
"$home_path/_gsp_content",
"$home_path/_gsp_content/hooks",
"$home_path/_gsp_content/generated",
"$home_path/_gsp_content/runtime"
)
{
mkpath($dir) if(!-d $dir);
}
my $pid_file = "$home_path/_gsp_content/runtime/server_content.pids";
if(!-e $pid_file && open(my $fh, '>', $pid_file))
{
close($fh);
}
}
sub cleanup_server_content_pid_group_without_decrypt
{
my ($pid_file, $wanted_role, $as_user) = @_;
return if(!-f $pid_file);
my @remaining;
if(!open(my $in, '<', $pid_file))
{
logger "Could not read server content PID file $pid_file: $!";
return;
}
while(my $line = <$in>)
{
chomp($line);
my $original = $line;
$line =~ s/^\s+|\s+$//g;
next if($line eq "");
my ($pid) = $line =~ /(?:^|[^\d])(\d{2,})(?:[^\d]|$)/;
my $role = ($line =~ /watchdog/i) ? "watchdog" : "app";
$role = "main_server" if($line =~ /main[_-]?server/i);
if(defined($pid) && $role eq $wanted_role)
{
logger "Stopping server-content $role PID $pid from $pid_file.";
sudo_exec_without_decrypt("kill -TERM $pid >/dev/null 2>&1 || true", $as_user);
sleep 1 if($wanted_role eq "watchdog");
sudo_exec_without_decrypt("kill -KILL $pid >/dev/null 2>&1 || true", $as_user);
next;
}
push(@remaining, $original) if($role ne "watchdog" && $role ne "app");
}
close($in);
if(open(my $out, '>', $pid_file))
{
foreach my $line (@remaining)
{
print $out "$line\n";
}
close($out);
}
}
sub cleanup_server_content_hooks_without_decrypt
{
my ($home_path, $as_user) = @_;
return if(!defined($home_path) || $home_path eq "");
prepare_server_content_runtime_without_decrypt($home_path);
my $pid_file = "$home_path/_gsp_content/runtime/server_content.pids";
cleanup_server_content_pid_group_without_decrypt($pid_file, "watchdog", $as_user);
cleanup_server_content_pid_group_without_decrypt($pid_file, "app", $as_user);
}
sub new_correlation_id
{
return time() . "-" . $$ . "-" . int(rand(1000000000));
@ -565,7 +649,7 @@ open(PID, '>', AGENT_PID_FILE)
print PID "$$\n";
close(PID);
logger "Open Game Panel - Agent started - "
logger "GameServer Panel - Agent started - "
. AGENT_VERSION
. " - port "
. AGENT_PORT
@ -688,7 +772,7 @@ my $d = Frontier::Daemon::OGP::Forking->new(
LocalPort => AGENT_PORT,
LocalAddr => AGENT_IP,
ReuseAddr => '1'
) or die "Couldn't start OGP Agent: $!";
) or die "Couldn't start GSP Agent: $!";
sub backup_home_log
{
@ -1608,6 +1692,7 @@ sub universal_start_without_decrypt
my $cli_bin;
my $command;
my $run_before_start;
prepare_server_content_runtime_without_decrypt($home_path);
# Replace any OGP variables found in the command line
$startup_cmd = replace_OGP_Env_Vars($screen_id, $home_id, $home_path, $startup_cmd, $game_key);
@ -1621,7 +1706,7 @@ sub universal_start_without_decrypt
$command = "taskset -c $cpu wine $server_exe $startup_cmd";
}
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
if(preference_enabled('gsp_autorestart_server', 'ogp_autorestart_server', '1')){
$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, undef, $status_hint_file);
}else{
$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1);
@ -1636,7 +1721,7 @@ sub universal_start_without_decrypt
$command = "taskset -c $cpu $startup_cmd";
}
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
if(preference_enabled('gsp_autorestart_server', 'ogp_autorestart_server', '1')){
$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, undef, $status_hint_file);
}else{
$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1);
@ -1651,7 +1736,7 @@ sub universal_start_without_decrypt
$command = "taskset -c $cpu ./$server_exe $startup_cmd";
}
if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){
if(preference_enabled('gsp_autorestart_server', 'ogp_autorestart_server', '1')){
$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, undef, $status_hint_file);
}else{
$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1);
@ -2093,6 +2178,7 @@ sub stop_server_without_decrypt
my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
my $as_user = find_user_by_screen_id($screen_id);
cleanup_server_content_hooks_without_decrypt($home_path, $as_user);
if ($control_password !~ /^\s*$/ and $control_protocol ne "")
{
@ -4787,7 +4873,7 @@ sub ftp_mgr
$password =~ s/('+)/'\"$1\"'/g;
$home_path =~ s/('+)/'\"$1\"'/g;
if(!defined($Cfg::Preferences{ogp_manages_ftp}) || (defined($Cfg::Preferences{ogp_manages_ftp}) && $Cfg::Preferences{ogp_manages_ftp} eq "1")){
if(preference_enabled('gsp_manages_ftp', 'ogp_manages_ftp', '1')){
if( defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "IspConfig")
{
use constant ISPCONFIG_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'IspConfig');
@ -5487,17 +5573,23 @@ if [ -n "\$POST_UPDATE" ]; then
fi
log "copy complete archive=\$ARCHIVE"
sleep 2
if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files 2>/dev/null | grep -q '^gsp_agent\\.service'; then
systemctl restart gsp_agent.service >> "\$LOG" 2>&1 && exit 0
fi
if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files 2>/dev/null | grep -q '^ogp_agent\\.service'; then
systemctl restart ogp_agent.service >> "\$LOG" 2>&1 && exit 0
fi
cd "\$DEST" || exit 0
if [ -f gsp_agent_run.pid ]; then kill "\$(cat gsp_agent_run.pid)" >/dev/null 2>&1 || true; fi
if [ -f ogp_agent_run.pid ]; then kill "\$(cat ogp_agent_run.pid)" >/dev/null 2>&1 || true; fi
if [ -f ogp_agent.pid ]; then kill "\$(cat ogp_agent.pid)" >/dev/null 2>&1 || true; fi
sleep 2
if [ -f ogp_agent_run ]; then
screen -d -m -t "ogp_agent" -c $screenrc_q -S ogp_agent bash ogp_agent_run -pidfile ogp_agent_run.pid >> "\$LOG" 2>&1 || true
if [ -f gsp_agent_run ]; then
screen -d -m -t "gsp_agent" -c $screenrc_q -S gsp_agent bash gsp_agent_run -pidfile gsp_agent_run.pid >> "\$LOG" 2>&1 || true
elif [ -f ogp_agent_run ]; then
screen -d -m -t "gsp_agent" -c $screenrc_q -S gsp_agent bash ogp_agent_run -pidfile gsp_agent_run.pid >> "\$LOG" 2>&1 || true
else
screen -d -m -t "ogp_agent" -c $screenrc_q -S ogp_agent perl ogp_agent.pl >> "\$LOG" 2>&1 || true
screen -d -m -t "gsp_agent" -c $screenrc_q -S gsp_agent perl ogp_agent.pl >> "\$LOG" 2>&1 || true
fi
log "restart attempted"
rm -rf "\$TMP"
@ -5528,9 +5620,10 @@ sub agent_restart
if ($dec_check eq 'restart')
{
chdir AGENT_RUN_DIR;
if(-e "ogp_agent_run.pid")
if(-e "gsp_agent_run.pid" || -e "ogp_agent_run.pid")
{
my $init_pid = `cat ogp_agent_run.pid`;
my $run_pid_file = -e "gsp_agent_run.pid" ? "gsp_agent_run.pid" : "ogp_agent_run.pid";
my $init_pid = `cat $run_pid_file`;
chomp($init_pid);
if(kill 0, $init_pid)
@ -5549,13 +5642,13 @@ sub agent_restart
}
open (AGENT_RESTART_SCRIPT, '>', 'tmp_restart.sh');
my $restart = "echo -n \"Stopping OGP Agent...\"\n".
my $restart = "echo -n \"Stopping GSP Agent...\"\n".
"kill $init_pid\n".
"while [ -e /proc/$init_pid $or_exist ];do echo -n .;sleep 1;done\n".
"rm -f ogp_agent_run.pid $rm_pid_file\necho \" [OK]\"\n".
"echo -n \"Starting OGP Agent...\"\n".
"screen -d -m -t \"ogp_agent\" -c \"" . SCREENRC_FILE . "\" -S ogp_agent bash ogp_agent_run -pidfile ogp_agent_run.pid\n".
"while [ ! -e ogp_agent_run.pid -o ! -e ogp_agent.pid ];do echo -n .;sleep 1;done\n".
"rm -f gsp_agent_run.pid ogp_agent_run.pid $rm_pid_file\necho \" [OK]\"\n".
"echo -n \"Starting GSP Agent...\"\n".
"screen -d -m -t \"gsp_agent\" -c \"" . SCREENRC_FILE . "\" -S gsp_agent bash gsp_agent_run -pidfile gsp_agent_run.pid\n".
"while [ ! -e gsp_agent_run.pid -o ! -e ogp_agent.pid ];do echo -n .;sleep 1;done\n".
"echo \" [OK]\"\n".
"rm -f tmp_restart.sh\n".
"exit 0\n";

414
ogp_agent_run Normal file → Executable file
View file

@ -1,411 +1,5 @@
#!/bin/bash
#
#
# A wrapper script for the OGP agent perl script.
# Performs auto-restarting of the agent on crash. You can
# extend this to log crashes and more.
#
# The ogp_agent_run script should be at the top level of the agent tree
# Make sure we are in that directory since the script assumes this is the case
#!/usr/bin/env bash
#####################
# Important VARS #
#####################
AGENTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
BASH_PREFS_CONF="$AGENTDIR/Cfg/bash_prefs.cfg"
REPONAME=OGP-Agent-Linux
GitHubUsername="OpenGamePanel"
#####################
# FUNCTIONS #
#####################
setupOGPDirPerms(){
chmod -Rf ug+rw $AGENTDIR 2>/dev/null
if [ -d "$AGENTDIR/steamcmd" ]; then
chmod ug+x $AGENTDIR/steamcmd/linux32/* 2>/dev/null
chmod ug+x $AGENTDIR/steamcmd/*.sh 2>/dev/null
fi
if [ -d "$AGENTDIR/screenlogs" ]; then
chmod -Rf ug=rwx $AGENTDIR/screenlogs
fi
chmod ug+x $AGENTDIR/ogp_agent.pl 2>/dev/null
chmod ug+x $AGENTDIR/ogp_agent_run 2>/dev/null
chmod ug+x $AGENTDIR/agent_conf.sh 2>/dev/null
if test `id -u` -eq 0; then
echo
echo
echo "************** WARNING ***************"
echo "Running OGP's agent as root "
echo "is highly discouraged. It is generally"
echo "unnecessary to use root privileges to "
echo "execute the agent. "
echo "**************************************"
echo
echo
timeout=10
while test $timeout -gt 0; do
echo -n "The agent will continue to launch in $timeout seconds\r"
timeout=`expr $timeout - 1`
sleep 1
done
fi
}
ogpGitCleanup(){
echo "Cleaning up..."
rm -Rf ${REPONAME}-* &> /dev/null
if [ -e "ogp_agent_latest.zip" ]; then
rm -f "ogp_agent_latest.zip"
fi
}
getSudoPassword(){
sudoPass=$(cat "$AGENTDIR/Cfg/Config.pm" | grep -o "sudo_password.*" | grep -ow "[^sudo_password( \)*=>( \)*].*" | grep -o "[^'].*[^',]")
}
detectSystemD(){
replaceSystemDService=false
# Ops require sudo
if [ ! -z "$sudoPass" ]; then
initProcessStr=$(ps -p 1 | awk '{print $4}' | tail -n 1)
if [ "$initProcessStr" == "systemd" ]; then
systemdPresent=1
if [ -e "/lib/systemd/system" ]; then
SystemDDir="/lib/systemd/system"
elif [ -e "/etc/systemd/system" ]; then
SystemDDir="/etc/systemd/system"
else
checkDir=$(ps -eaf|grep '[s]ystemd' | head -n 1 | awk '{print $8}' | grep -o ".*systemd/")
if [ -e "${checkDir}system" ]; then
SystemDDir="$checkDir"
else
# Can't find systemd dir
systemdPresent=
SystemDDir=
fi
fi
fi
if [ -e "${AGENTDIR}/systemd/ogp_agent.service" ]; then
if [ ! -z "$systemdPresent" ] && [ ! -z "$SystemDDir" ]; then
echo -e "systemd detected as the init system with a directory of $SystemDDir."
if [ -e "/etc/init.d/ogp_agent" ] && [ ! -e "${AGENTDIR}/ogp_agent_init" ]; then
echo -e "Taking care of existing OGP files."
# Kill any remaining ogp agent process
ogpPID=$(ps -ef | grep -v grep | grep ogp_agent.pl | head -n 1 | awk '{print $3}')
if [ ! -z "$ogpPID" ]; then
echo "$sudoPass" | sudo -S -p "" kill -9 "$ogpPID"
fi
echo "$sudoPass" | sudo -S -p "" cp "/etc/init.d/ogp_agent" "${AGENTDIR}/ogp_agent_init"
echo "$sudoPass" | sudo -S -p "" chmod +x "${AGENTDIR}/ogp_agent_init"
echo "$sudoPass" | sudo -S -p "" update-rc.d ogp_agent disable
echo "$sudoPass" | sudo -S -p "" chkconfig ogp_agent off
echo "$sudoPass" | sudo -S -p "" rm -rf "/etc/init.d/ogp_agent"
replaceSystemDService=true
fi
# Update service to use oneshot and not forking
if [ -e "$SystemDDir/ogp_agent.service" ]; then
# Check to see if it's using oneshot
usingOneShot=$(echo "$sudoPass" | sudo -S -p "" cat "$SystemDDir/ogp_agent.service" | grep -o "oneshot")
if [ -z "$usingOneShot" ]; then
replaceSystemDService=true
fi
fi
if [ ! -e "$SystemDDir/ogp_agent.service" ] || [ "$replaceSystemDService" = true ]; then
echo -e "Updating OGP agent systemd service init script."
echo -e "Copying ogp_agent systemd service file to $SystemDDir"
echo "$sudoPass" | sudo -S -p "" cp "${AGENTDIR}/systemd/ogp_agent.service" "$SystemDDir"
echo "$sudoPass" | sudo -S -p "" sed -i "s#{OGP_AGENT_PATH}#$AGENTDIR#g" "${SystemDDir}/ogp_agent.service"
echo "$sudoPass" | sudo -S -p "" systemctl daemon-reload
echo "$sudoPass" | sudo -S -p "" systemctl enable ogp_agent.service
echo "$sudoPass" | sudo -S -p "" service ogp_agent restart
exit 0
fi
fi
fi
fi
}
init() {
RESTART="yes"
AGENT="$AGENTDIR/ogp_agent.pl"
TIMEOUT=10 # time to wait after a crash (in seconds)
PID_FILE=""
# Should we perform an automatic update?
if [ -e $BASH_PREFS_CONF ]
then
source "$BASH_PREFS_CONF"
if [ "$agent_auto_update" -eq "1" ]
then
AUTO_UPDATE="yes"
fi
# Use custom github update address
if [ ! -z "$github_update_username" ]; then
REVISIONTest=`curl -s https://github.com/${github_update_username}/${REPONAME}/commits/master.atom | egrep -o "([a-f0-9]{40})" | awk 'NR==1{print $1}'`
if [ ! -z "$REVISIONTest" ]; then
GitHubUsername=${github_update_username}
fi
fi
else
AUTO_UPDATE="yes"
fi
while test $# -gt 0; do
case "$1" in
"-pidfile")
PID_FILE="$2"
PID_FILE_SET=1
echo $$ > $PID_FILE
shift ;;
esac
shift
done
if test ! -f "$AGENT"; then
echo "ERROR: '$AGENT' not found, exiting"
quit 1
elif test ! -x "$AGENT"; then
# Could try chmod but dont know what we will be
# chmoding so just fail.
echo "ERROR: '$AGENT' not executable, exiting"
quit 1
fi
CMD="perl $AGENT"
}
syntax () {
# Prints script syntax
echo "Syntax:"
echo "$0"
}
checkDepends() {
CURL=`which curl 2>/dev/null`
if test "$?" -gt 0; then
echo "WARNING: Failed to locate curl binary."
else
echo "INFO: Located curl: $CURL"
fi
UNZIP=`which unzip 2>/dev/null`
if test "$?" -gt 0; then
echo "WARNING: Failed to locate unzip binary."
else
echo "INFO: Located unzip: $UNZIP"
fi
}
update() {
# Check to see if limited ogpuser exists
generateOGPLimitedUser
# Run the update
if test -n "$AUTO_UPDATE"; then
if [ -z "$CURL" -o -z "$UNZIP" ]; then
checkDepends
fi
if [ -f "$CURL" -a -x "$CURL" ] && [ -f "$UNZIP" -a -x "$UNZIP" ]; then
cd $AGENTDIR
if [ ! -d tmp ]; then
mkdir tmp
fi
cd tmp
REVISION=`curl -s https://github.com/${GitHubUsername}/${REPONAME}/commits/master.atom | egrep -o "([a-f0-9]{40})" | awk 'NR==1{print $1}'`
curl -Os https://raw.githubusercontent.com/${GitHubUsername}/${REPONAME}/${REVISION}/ogp_agent_run
currentOGPAgentRunContent=$(cat "./ogp_agent_run")
# Check to make sure ogp_agent_run downloaded successfully from GitHub before we attempt to replace it.
# This should fix random 404 people have been experiencing
if [ -s "./ogp_agent_run" ] && [ "$(echo "$currentOGPAgentRunContent" | head -n 1)" != "404: Not Found" ] && [ ! -z "$(echo "$currentOGPAgentRunContent" | grep "ogp_agent.pl")" ]; then
diff ./ogp_agent_run $AGENTDIR/ogp_agent_run &>/dev/null
if test $? -ne 0; then
cp -f ./ogp_agent_run $AGENTDIR/ogp_agent_run &> /dev/null
if test $? -eq 0; then
cd $AGENTDIR
chmod ug+x ogp_agent_run 2>/dev/null
echo "`date`: The agent updater has been changed, relaunching..."
rm -Rf tmp
./ogp_agent_run
exit 0
fi
fi
fi
cd $AGENTDIR
CURRENT=$(cat $AGENTDIR/Cfg/Config.pm | grep version | grep -Eo '[0-9a-f]{40}')
if [ "$CURRENT" == "$REVISION" ]; then
echo "The agent is up to date."
else
URL=https://github.com/${GitHubUsername}/${REPONAME}/archive/${REVISION}.zip
HEAD=$(curl -L -s --head -w "%{http_code}" "$URL" -o "ogp_agent_latest.zip")
if [ "$HEAD" == "200" ]; then
echo "Updating agent using curl."
curl -L -s "$URL" -o "ogp_agent_latest.zip"
if test $? -ne 0; then
echo "`date`: curl failed to download the update package."
else
unzip -oq "ogp_agent_latest.zip"
if test $? -ne 0; then
echo "`date`: Unable to unzip the update package."
ogpGitCleanup
else
cd ${REPONAME}-${REVISION}
cp -avf systemd Frontier ArmaBE Minecraft Schedule Time FastDownload php-query ogp_agent.pl ogp_screenrc ogp_screenrc_bk ogp_agent_run agent_conf.sh $AGENTDIR &> /dev/null
if test $? -ne 0; then
echo "`date`: The agent files cannot be overwritten."
cd ..
ogpGitCleanup
echo "Agent update failed."
else
if test ! -d "$AGENTDIR/IspConfig"; then
cp -Rf IspConfig $AGENTDIR/IspConfig &> /dev/null
fi
if test ! -d "$AGENTDIR/EHCP"; then
cp -Rf EHCP $AGENTDIR/EHCP &> /dev/null
fi
if test ! -f "$AGENTDIR/Cfg/Preferences.pm"; then
cp -f Cfg/Preferences.pm $AGENTDIR/Cfg/Preferences.pm &> /dev/null
fi
echo "Fixing permissions..."
chmod ug+x $AGENTDIR/ogp_agent.pl &> /dev/null
chmod ug+x $AGENTDIR/ogp_agent_run &> /dev/null
chmod ug+x $AGENTDIR/agent_conf.sh &> /dev/null
cd ..
ogpGitCleanup
sed -i "s/version.*/version => '${REVISION}',/" $AGENTDIR/Cfg/Config.pm
echo "Agent updated successfully."
fi
fi
fi
else
echo "There is a update available (${REVISION}) but the download source is not ready.";
echo "Try again later."
fi
fi
else
echo "Update failed."
fi
fi
return 0
}
run() {
getSudoPassword
restrictAccess
update
detectSystemD
if test -n "$RESTART" ; then
echo "Agent will auto-restart if there is a crash."
#loop forever
while true
do
# Run
$CMD
echo "`date`: Agent restart in $TIMEOUT seconds"
# don't thrash the hard disk if the agent dies, wait a little
sleep $TIMEOUT
done # while true
else
$CMD
fi
}
quit() {
# Exits with the give error code, 1
# if none specified.
# exit code 2 also prints syntax
exitcode="$1"
# default to failure
if test -z "$exitcode"; then
exitcode=1
fi
case "$exitcode" in
0)
echo "`date`: OGP Agent Quit" ;;
2)
syntax ;;
*)
echo "`date`: OGP Agent Failed" ;;
esac
# Remove pid file
if test -n "$PID_FILE" && test -f "$PID_FILE" ; then
# The specified pid file
rm -f $PID_FILE
fi
# reset SIGINT and then kill ourselves properly
trap - 2
kill -2 $$
}
function generatePassword(){
if [ ! -z "$1" ]; then
PLENGTH="$1"
else
PLENGTH="10"
fi
#rPass=$(date +%s | sha256sum | base64 | head -c "$PLENGTH")
rPass=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 | head -c "$PLENGTH")
}
function generateOGPLimitedUser(){
ogpUSER="ogp_server_runner"
echo "$sudoPass" | sudo -S -p "<prompt>" id -u "$ogpUSER"
if [ $? -eq 1 ]; then
echo "Creating ogp limited user for running servers and additional security..."
echo "$sudoPass" | sudo -S -p "<prompt>" groupdel ${ogpUSER}
echo "$sudoPass" | sudo -S -p "<prompt>" groupadd ${ogpUSER}
generatePassword "15"
ogpPass="$rPass"
echo "$sudoPass" | sudo -S -p "<prompt>" useradd --home "/home/$ogpUSER" -g ${ogpUSER} -m "$ogpUSER"
echo "$sudoPass" | sudo -S -p "<prompt>" sh -c "echo '${ogpUSER}:${ogpPass}' | chpasswd"
# Use /bin/bash shell by default per request from Omano
echo "$sudoPass" | sudo -S -p "<prompt>" usermod -s /bin/bash ${ogpUSER}
echo "$sudoPass" | sudo -S -p "<prompt>" sh -c "echo 'limited_ogp_user=${ogpUSER}
password=${ogpPass}' > /root/ogp_server_runner_info"
agentUser="$(whoami)"
echo "$sudoPass" | sudo -S -p "<prompt>" usermod -a -G "$ogpUSER" "$agentUser"
# Reload perms so we don't have to reboot system for new group to apply right now...
echo "$sudoPass" | sudo -S -p "<prompt>" exec su -l "$agentUser"
fi
# Set servers to run under their own user by default:
hasLinuxUser=$(cat "$AGENTDIR/Cfg/Preferences.pm" | grep -o "linux_user_per_game_server")
if [ -z "$hasLinuxUser" ]; then
sed -i "\$i \\\\tlinux_user_per_game_server => '1'," "$AGENTDIR/Cfg/Preferences.pm"
fi
}
function restrictAccess(){
echo "$sudoPass" | sudo -S -p "<prompt>" chmod 750 "$AGENTDIR/Cfg/Config.pm"
echo "$sudoPass" | sudo -S -p "<prompt>" chmod 750 "$AGENTDIR/Cfg/Preferences.pm"
echo "$sudoPass" | sudo -S -p "<prompt>" chmod 750 "$AGENTDIR/Cfg/bash_prefs.cfg"
}
#####################
# MAIN APP CODE #
#####################
# Setup OGP and Read Preferences
setupOGPDirPerms
# Initialise
init $*
# Run
run
# Quit normally
quit 0
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "ogp_agent_run is a legacy compatibility wrapper. Use gsp_agent_run for new GSP installs." >&2
exec "${SCRIPT_DIR}/gsp_agent_run" "$@"

View file

@ -4,5 +4,4 @@ hardstatus alwayslastline '%{gk}[ %{G}%H %{g}][%= %{wk}%?%-Lw%?%{=b kR}[%{W}%n%f
# Default scroll back 100
defscrollback 100
deflog on
logfile /home/gameserver/OGP/screenlogs/screenlog.%t
logfile $PWD/screenlogs/screenlog.%t

View file

@ -127,6 +127,6 @@ print "To enable it:\n";
print "1. Configure database settings in Cfg/Config.pm\n";
print "2. Import SQL schema files from DB/ directory\n";
print "3. Install DBI and DBD::mysql Perl modules\n";
print "4. Restart the OGP Agent\n";
print "4. Restart the GSP Agent\n";
print "\nThe system will automatically start collecting resource data\n";
print "every " . ($Cfg::Config{stats_frequency_minutes} || '5') . " minutes when enabled.\n";

20
systemd/gsp_agent.service Normal file
View file

@ -0,0 +1,20 @@
# GSP Linux Agent systemd service
[Unit]
Description=GameServer Panel Linux Agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User={GSP_AGENT_USER}
Group={GSP_AGENT_USER}
WorkingDirectory={GSP_AGENT_PATH}
ExecStart={GSP_AGENT_RUN_SCRIPT} -pidfile {GSP_AGENT_PID_FILE}
Restart=on-failure
RestartSec=10
KillSignal=SIGTERM
TimeoutStopSec=60
[Install]
WantedBy=multi-user.target

View file

@ -1,16 +1,18 @@
# ogp_agent systemd Service Script
# Legacy compatibility unit. New installs should use gsp_agent.service.
[Unit]
Description=GameServer Panel (GSP) Daemon www.worlddomination.dev
After=network.target
Description=GameServer Panel Linux Agent legacy service alias
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c "{OGP_AGENT_PATH}/ogp_agent_init start"
ExecStop=/bin/sh -c "{OGP_AGENT_PATH}/ogp_agent_init stop"
RemainAfterExit=yes
PIDFile="{OGP_AGENT_PATH}/ogp_agent_run.pid"
Type=simple
User={GSP_AGENT_USER}
Group={GSP_AGENT_USER}
WorkingDirectory={GSP_AGENT_PATH}
ExecStart={GSP_AGENT_PATH}/gsp_agent_run -pidfile {GSP_AGENT_PATH}/gsp_agent_run.pid
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target