Homepage->Blog index
Self-hosting a Phantasy Star Online server with Sylverant + GC/DC crossplay
Date written: 2024/02/22

So you want to host your own Phantasy Star Online server?

Well, if you're like 90% of people and just want to spin something up, then you can stop reading right now and go with newserv instead. It's more modern, well documented, and all that good stuff.
But if you're like me and need to satisfy an edge case like... crossplaying Gamecube, Dreamcast and PC together, then this is the guide for you.

Let's outline the requirements. You'll need:

  1. A system running FreeBSD
  2. A MySQL or MariaDB database server
  3. The server components from Sylverant's github. These are login_server, ship_server, shipgate, libsylverant, libpsoarchive, and optionally patch_server
  4. (for GC) A DNS server
  5. (for PC) An IP address patcher or hex editor
  6. (for DC) A hex editor (this will not be documented as I am not playing on DC)


Our FreeBSD system will be the host for login_server, ship_server and shipgate. DNS can be handled by any OS of your choice, although I'll be using a separate VM for it.
The reason we are using FreeBSD is that Sylverant's software stack is developed with it specifically in mind. I wasn't able to make libtool, one of the dependencies, usable under Linux.

As of January 2024, the latest version of FreeBSD is 14.0, and it will work with this, so nab it and install it (keep lib32 and ports enabled).

Since for me the network will be behind a 192.168.32.1 gateway, I'll set the ethernet interface with an IPv4 address of 192.168.32.104.

As the server programs require it, we will create a user named pso and do whatever we can under it. Invite the user to wheel.

Several packages will need to be installed on your first login. These are:


Start the mysql-service, perform a mysql_secure_installation if needed, and set a port you'd like to use (I went with 5905).

Log into the mysql/mariadb shell, add a user named 'pso', and grant it all privileges.

To allow remote connections to the database, type ``sysrc mysql_args="--bind-address=0.0.0.0"`` and ``service mysql-server restart``.

Log into the database with your newly created 'pso' user and create a database named 'pso', of type utf8mb4_general_ci.

Once created, import the following file: pso.sql
It will create the necessary tables needed for hosting a server for DCv1, DCv2/PC, and GC/Xbox.

Next you want to fetch all of the Sylverant server components and compile them. Git clone the following:


First compile libsylverant by going into it's directory and typing:

autoreconf --install
./configure
make all
sudo make install

Do the same for libpsoarchive.

Now you're ready to build the server binaries. Go to login_server and type the following:

autoreconf --install
CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ./configure (add --disable-ipv6 if you don't need IPv6 support)
make all
sudo make install

Do the same for shipgate, ship_server and patch_server.

If everything built without errors, you're ready for the next step.

Create a 'sylverant' directory in /usr/local/share/, and then 'config' within /usr/local/share/sylverant/.
This is where all the necessary config files will be stored.
Also within /usr/local/share/sylverant/ create the 'info', 'l10n', 'logs', and 'quests' directories.

I suggest recursively chown-ing the 'sylverant' directory to the 'pso' user.

Within the 'config' directory you will, at the very least, need the following files:

The exact structures are more or less documented at the official Sylverant wiki here: https://code.google.com/archive/p/sylverant/wikis
If you want to properly configure a server for, say, public use, read it carefully.
However, to simply get something off the ground, you can use my XMLs that I use for local deployments and modify them to meet your needs: pso_configs.zip
Unzip these into /usr/local/share/sylverant/config.

You will also need all the quests from a copy of v2. You can get them here: pso_quests
Unzip them to /usr/local/share/sylverant/quests.

Let's do a test run! Try starting login_server by typing `login_server --nodaemon`.

You will most likely get an error that says ``Couldn't open param file: ItemMagEdit.prs``.
This is a Blue Burst related error. We don't really intend on supporting BB here, so let's start patching out code.

In login_server/src/login_server.c, go to line 347, comment out the following lines, and rebuild login_server:

/* Read the Blue Burst param data */
if(load_param_data())
exit(EXIT_FAILURE);

if(load_bb_char_data())
exit(EXIT_FAILURE);

Once this is done, login_server should be able to start and listen for incoming connections.

Note that login_server and ship_server need the following ports open:
9000
9001
9002
9003
9100
9103
9200
9201
9203
9300
9500
10003
12000
12001
12002
12003
12004
12005
12006
12007
12008
12009
12010
12011
12012
12013

If you're behind a firewall, make sure these are open for TCP traffic, and if you're behind a NAT, configure the appropriate forwarding rules.

To allow Gamecube players to connect (NTSC/U v1.02 plus in this example), you will need to set up a DNS server and two A records, one for game01.st-pso.games.sega.net and another for game04.st-pso.games.sega.net that point to your login_server's IP address.

PC and DC players will need to modify their clients to directly connect to the server IP. PC users can use the ippatch.exe tool to do this job: ippatch.exe

At this point, if you try to connect through either PC or GC, you will be rejected due to your serial number not being verified. To resolve this, you will need to do the following:
  1. Create an account in the account_data table
  2. Create and assign a guild card in the guildcards table
  3. Tie the guild card to your game's serial number and access key in the pc_clients and/or gamecube_clients tables

Note that the serial number needs to be represented in hexadecimal form through a string, so either convert it in advance to hex or use the UNHEX function during import.

If on your next connection you see the "Ship Select" and "Download Quest" options, CONGRATULATIONS, you're almost there!

The next steps requires setting up shipgate and ship_server, but for that we first need to set up a CA and sign a X.509 certificate.

We're going to follow the steps outlined in the wiki for this one, to keep things simple.

First, set up the necessary directories:

mkdir /home/pso/sslCA
cd /home/pso/sslCA
mkdir demoCA
cd demoCA
echo 1000 > serial
touch index.txt
mkdir certs private newcerts
cd ..

Then create the shipgate CA. Put a Common Name!

openssl req -new -x509 -days 3650 -extensions v3_ca -keyout demoCA/private/cakey.pem -out demoCA/cacert.pem -config /etc/ssl/openssl.cnf

Perform an SSL request:

openssl req -new -nodes -out sylverant-req.pem -keyout demoCA/private/sylverant-key.pem -config /etc/ssl/openssl.cnf

Sign the cert:

openssl ca -config /etc/ssl/openssl.cnf -out sylverant-cert.pem -infiles sylverant-req.pem

You should have the following files:

sslCA/sylverant-cert.pem (certificate)
sslCA/demoCA/private/sylverant-key.pem (certificate key)
sslCA/demoCA/cacert.pem (CA key)

Edit sylverant_config.xml and ship_config.xml so that they point to those files. If you take my example config, you should only need to change the user directory from 'sylverant' to 'pso'.
If you're getting GNUTLS errors when starting shipgate and ship_server, you likely made a typo, so double check your paths!

Retrieve the SHA1 fingerprint of your cert:

openssl x509 -noout -sha1 -fingerprint -in sylverant-cert.pem

Finally, add the fingerprint to the ship_data table (remove the semicolons). Example:

mysql> INSERT INTO ship_data (ship_number,memo,sha1_fingerprint) VALUES ('1','1','0','Insert memo here',UNHEX('BB34765179347A0823787BE03756AA75B0D9E0CC'));

When you start shipgate, you will likely get an "Error clearing transient_clients" message.
I'm honestly not sure what this table is supposed to handle, as it's not documented anywhere, so let's patch out the code that checks for it.

At line 440 in shipgate/src/shipgate.c comment out the following lines:

if(sylverant_db_query(&conn, "DELETE FROM transient_clients")) {
debug(DBG_ERROR, "Error clearing transient_clients\n");
exit(EXIT_FAILURE);
}

You might also want to comment out the events check right below it. I've done so since I don't know how to configure events.

make then sudo make install once more.

I REPEAT ONCE MORE: If you're getting GNUTLS errors when starting shipgate and ship_server, you likely made a typo, so double check your paths in the configs!

Aaaaaand done. Start login_server, shipgate and ship_server in order (with the --nodaemon parameter if from CLI), and join the server!

"Ok but how do I crossplay GC with DC/PC"


For that you'll need to run /allowgc on the DC/PC side after starting a team, and /showdcpc on the Gamecube side.

By default, these commands are only usable by GMs, so you have two ways of enabling them:
1) Create a valid _gms.xml file and define players in it
2) Make the commands usable by everybody

As I don't know how to set up a GMs file, I'll show you how to patch the privilege checks for them.

In ship_server/src/commands.c, at lines 1572 and 1600, for functions handle_allowgc() and handle_showdcpc(), comment out the following lines:

if(!LOCAL_GM(c)) {
pthread_mutex_unlock(&l->mutex);
return send_txt(c, "%s", __(c, "\tE\tC7Nice try."));
}

You're finally done! You can start your Sylverant server and do very buggy and unstable GC/DC/PC crossplay!