Building Linux Server from source on Linux

I’m trying to figure out how to build the FXServer on Linux.

Looking at Rockerfile I figured it might be possible without much work (maybe even one line command), but I have a hard time finding any info about “Rocker” or how to use it given how popular “Docker” is and these names differ only by one letter making web searches a headache.

Anyone managed to successfully do this? Sadly I don’t have nearly as much time now as I had in the past for a “deep delve” into this.

I’d also be grateful if someone could list all the components that need to be removed from the server’s components.json (and clarify whether that has to be done before building or doesn’t matter) to make it possible to connect to this server from a client run on WINE using any local ip address like 192.168.x.x not just localhost.

Attempting to use any ready-made server build for this results in:

“Connection rejected by server: No authentication ticket was specified.”

Which is understandable given the warning popup about “some authentication features” being unavailable on WINE.

  • remove "svadhesive"
  • set sv_lan 1 (this convar is a misnomer, anyway, it actually disables ticket checks)

Thanks.

This actually helped and I was able to run and join a server, but after some testing I found out that “some authentication features” that are unavailable apparently include something as basic as reading identifiers (like Rockstar id) with GetPlayerIdentifiers.

Loop over player identifiers actually runs zero iterations, so I have no way to uniquely identify players. In this state it’s kinda useless to me…

Can the server be built in a custom way so it still allows players to join in this insecure mode with all the authentication features, but no anticheat present?

1 Like

Steam should work if enabled on the server using a steam_webApiKey and the client has an available Steam pipe.

I did supply a steam api key in the server config and started steam client on my client machine, but that did not help. Still zero iterations. How do I check if the client has an available Steam pipe?

Or maybe there is another way to obtain something (using natives) that uniquely identifies a player on LAN like IP or MAC address? I’ve tried GetPlayerEndpoint, but that returns nil

Hey ! Could you share your progress ?

I’m also interested in building FXServer from source on Linux and I’m experienced with Docker
Let me know,

Cheers.

I haven’t had much progress on this. Pretty much only looked around the repo and noticed there’s a “Rockerfile” inside code directory that looks almost like a Dockerfile, but not really… it has some additional commands that plain docker does not understand (I actually tried renaming it to Dockerfile and running docker build on it).

It seems to me like it’s adapted to do a cross-compile from Windows or something like that, I think it can be converted to a vanilla Dockerfile and run on native Linux, but I don’t really have time at the moment to get deeper into it.

Is the Rockerfile really what’s used to build the Linux server ?

There also seems to be a gitlab CI action :

build_proot_linux:
  stage: build
  image: mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13
  variables:
    GIT_SUBMODULE_STRATEGY: normal
    # workaround gitlab-ci-multi-runner#2148
    GIT_SSL_CAPATH: /etc/ssl/certs/
    DOCKER_TLS_CERTDIR: ""
  script: 
    - sh code/tools/ci/build_server_proot.sh
  artifacts:
    paths:
      - fx.tar.xz
    expire_in: 1 month
  except:
    - tags
  tags:
    - linux

Which uses code/tools/ci/build_server_proot.sh

Searching "Rockerfile" on a search engine (or another search engine) resulted in this repository by the way, so I’m not sure how web searches become ‘a headache’ with something being one letter off - maybe searching weird terms or other engines than DDG or Google acting weird?

Anyway, it’s not used anymore in the current build tooling, but at the time it was the only tool that had this MOUNT feature to prevent having to copy a huge repository into a Docker build context, which was extremely slow on the ‘Travis CI’ service that existed at the time.

Used google and it was correcting “Rocker” to “Docker” and “Rockerfile” to “Dockerfile”, displaying a plethora of Docker-related hits everytime. The only result I managed to find with an “R” at the start was this and it seems to be something else entirely.

It would be really helpful if this and other scripts and source not used anymore were git rm 'd from the repo. They can easily pull someone not very familiar with the codebase into a deep rabbit hole of futile effort.

Odd. I can’t even replicate this on a private tab.

Yes, this usually already happens when I do come across any leftover stuff when doing other things in the repo, but there’s currently a backlog of around 515 other tasks, of which the ‘code cleanup’ meta-task has 25 subtasks now, including the ‘remove Rockerfile and old Travis CI leftovers’ task.

I’m also not at a PC right now so I cant remove this file trivially either.

I had little time to tinker around with this and managed to build something the following way:

$ git clone https://github.com/citizenfx/fivem.git
$ cd fivem
$ docker pull mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13
$ docker run -it -v "$(pwd)":/src mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13 /bin/sh

inside container:

# chmod +x ./src/code/tools/ci/build_server_2.sh
# ./src/code/tools/ci/build_server_2.sh

in /opt/ (in the container) now I have a cfx-server folder, but upon inspecting what’s inside and comparing it with how the official release looks like it seems like the build output is only a very small part.

Official release looks like some sort of “snapshot” of the entire container and the cfx-server folder (from my build output) has a lot of files missing compared to alpine/opt/cfx-server from official release.

Update:

It looks like the server is supposed to be built inside a docker container with a chroot to get the “snapshot-like” structure I noticed in previous post. I’m trying to modify code/tools/ci/build_server_proot.sh script to make it use a volume mounted from the host system containing a cloned git repository instead of whatever weird clone-inside-container thing it’s doing.

Ideally I’d make it so the entire thing runs non-interactively, spitting out the artifacts back to host.

Current version of the script can be found here, but it still fails with the following error:

/usr/bin/npm -> /usr/lib/node_modules/npm/bin/npm-cli.js
/usr/bin/npx -> /usr/lib/node_modules/npm/bin/npx-cli.js
+ npm@7.19.1
added 63 packages from 25 contributors, removed 244 packages and updated 193 packages in 6.461s
npm ERR! The `npm ci` command can only install with an existing package-lock.json or
npm ERR! npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or
npm ERR! later to generate a package-lock.json file, then try again.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2022-05-24T15_23_12_887Z-debug.log

I run it like this (mounting a cloned fivem repo under /fivem on the container with my script palced inside the fivem folder):

$ docker run --privileged -it -v "$(pwd)":/fivem mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13 /bin/sh

then (inside container):

# cd /fivem
# ./build_server_linux.sh

Would be great if someone experienced with building fivem could share some insight on this.

Update:

I had some more time finally, so I went at it again and it seems the error from previous post was really dumb, I forgot to pull git submodules.

I’ve modified the script and almost managed to finish building (it takes pretty long time) and at the end I get the following error:

Linking citizen-server-state-fivesv
cp: can't stat '/usr/lib/mono/4.5/System.Runtime.InteropServices.RuntimeInformation.dll': No such file or directory
Bus error (core dumped)
/src/code/tools/ci/build_server_2.sh: line 213: objcopy: I/O error
/src/code/tools/ci/build_server_2.sh: line 214: rm: I/O error

From what I see, it’s near the end of the build process.

To replicate this, run:

$ git clone https://github.com/citizenfx/fivem.git
$ cd fivem
$ git submodule update --init --recursive
$ wget https://gist.githubusercontent.com/PainedPsyche/eb0470558c41c28ed7e9c3aceeb9131b/raw/ef570044a577929304d1a18883e9f9ddc8e1ff54/build_server_linux.sh
$ chmod +x build_server_linux.sh
$ docker pull mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13
$ docker run --privileged -it -v "$(pwd)":/fivem mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13 /bin/sh

then inside container:

# cd fivem
# ./build_server_linux.sh

Most of the artifacts seem to be there in fivem/alpine folder and there is also some “garbage” that isn’t present in the official release, it might be because the build didn’t really finish and could not clean up properly.

Update 2:

Did some more digging around and noticed that the contents of fivem-private seem to matter, since I was not able find out where it’s supposed to be cloned from (it’s passed via an env variable that isn’t set anywhere), I tried two approaches:

Stubbing out the file like this:

if [ ! -d ../fivem-private ]; then
	mkdir -p ../fivem-private/components
    echo "" > ../fivem-private/components/config.lua
fi

This resulted in the build error above.

I also attempted to copy over contents of code/components in it’s place like this:

if [ ! -d ../fivem-private ]; then
	mkdir -p ../fivem-private
    cp -r ./code/components ../fivem-private/
fi

This resulted in the missing file from the case above to actually be there but there was link errors like this:

ld.lld: error: duplicate symbol: typeinfo name for ComponentInstance
>>> defined at Component.cpp
>>>            obj/Release/conhost-server/Component.o:(typeinfo name for ComponentInstance)
>>> defined at Component.cpp
>>>            obj/Release/conhost-server/Component1.o:(.rodata+0x0)
number_asformat.cpp
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [conhost-server.make:115: ../../../bin/server/linux/release/libconhost-server.so] Error 1

and most artifacts were missing with this approach.

I could really use some clarification on what’s supposed to be in this fivem-private folder and how to properly populate it with correct data.

Update:

Looks like the problem might not be on my side. It seems there is a regression in Clang 14 that results in an error when compiling curl (a dependency of FiveM server).

So far I tried forcing a version by editing code/tools/ci/build_server_2.sh (line 42) and forcing it to use Clang 13 like this (modified clang, clang-dev and clang-libs):

apk add --no-cache --virtual .dev-deps lld curl-dev=7.72.0-r99 clang=13.0.1-r1 clang-dev=13.0.1-r1 build-base linux-headers openssl1.1-compat-dev python2 python3 py3-pip lua5.3 lua5.3-dev mono-reference-assemblies=5.16.1.0-r9991 mono-dev=5.16.1.0-r9991 libmono=5.16.1.0-r9991 mono-corlib=5.16.1.0-r9991 mono=5.16.1.0-r9991 mono-reference-assemblies-4.x=5.16.1.0-r9991 mono-reference-assemblies-facades=5.16.1.0-r9991 mono-csc=5.16.1.0-r9991 mono-runtime=5.16.1.0-r9991 c-ares-dev v8-dev~=9.3 nodejs-current nodejs-current-dev npm yarn clang-libs=13.0.1-r1 git

But this results in a following error:

ERROR: unable to select packages:
  clang-libs-14.0.4-r0:
    breaks: .dev-deps-20220611.185906[clang-libs=13.0.1-r1]
    satisfies: clang-dev-14.0.4-r0[clang-libs=14.0.4-r0] clang-14.0.4-r0[so:libclang-cpp.so.14]
               clang-extra-tools-14.0.4-r0[so:libclang-cpp.so.14] clang-extra-tools-14.0.4-r0[so:libclang.so.13]
  clang-14.0.4-r0:
    breaks: .dev-deps-20220611.185906[clang=13.0.1-r1]
    satisfies: clang-dev-14.0.4-r0[clang=14.0.4-r0]
  clang-dev-14.0.4-r0:
    breaks: .dev-deps-20220611.185906[clang-dev=13.0.1-r1]
  .dev-deps-20220611.185906:
    masked in: cache
    satisfies: world[.dev-deps=20220611.185906]

I will have to find a way to either downgrade alpine linux this build uses or wait until LLVM regression is fixed and FiveM’s build process is updated to use a version of alpine that has the fix. :sob:

Unrelated and rather a recent thing (official builds are also broken by this as of yesterday, indeed).

Your case from the post above - don’t at all make a fivem-private, and instead also don’t have the privates_config.lua exist.

You’re likely getting that ‘duplicate definition’ error since a private tree can also contain an overlay for existing code.

1 Like

Thanks, that helped.

I’m still getting a link error at the end though:

Linking citizen-server-state-fivesv
cp: can't stat '/usr/lib/mono/4.5/System.Runtime.InteropServices.RuntimeInformation.dll': No such file or directory
readelf: Warning: Separate debug info file /usr/lib/debug//lib//ld-musl-x86_64.so.1.debug found, but CRC does not match - ignoring
readelf: Warning: Separate debug info file /usr/lib/debug//lib//ld-musl-x86_64.so.1.debug found, but CRC does not match - ignoring
Bus error (core dumped)
/src/code/tools/ci/build_server_2.sh: line 215: objcopy: I/O error
/src/code/tools/ci/build_server_2.sh: line 216: rm: I/O error

I did not modify build_server_2.sh file in any way and the folder `/usr/lib/mono does indeed not exist under chrooted environment, however I was able to find this .dll in different locations, for example:

./fivem/data/server_windows/citizen/clr2/lib/mono/4.5/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/usr/lib/mono/4.6-api/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/usr/lib/mono/4.7-api/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/usr/lib/mono/4.5/Facades/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/usr/lib/mono/4.6.2-api/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/usr/lib/mono/4.7.1-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/usr/lib/mono/4.6.1-api/System.Runtime.InteropServices.RuntimeInformation.dll
./fivem/alpine/opt/cfx-server/citizen/clr2/lib/mono/4.5/Facades/System.Runtime.InteropServices.RuntimeInformation.dll

I gather that ./fivem/alpine/usr/lib is what is mounted at /usr/lib during this build step and the paths seem to differ (the file is under one more subdirectory Facades in 4.5)
Looks like I was wrong on this, none of these directories is mounted under /usr/lib

Something is seriously borked here.

I went over the build_server_2.sh again line by line comparing them to what I have in my chrooted system, here’s the problematic lines:

cp -a /etc/mono/4.5/machine.config /opt/cfx-server/citizen/clr2/cfg/mono/4.5/machine.config

Problem: mono directory does not exist under /etc/

cp -a /usr/lib/mono/4.5/Facades/ /opt/cfx-server/citizen/clr2/lib/mono/4.5/Facades/

Problem: mono directory does not exist under /usr/lib/

cp -a /usr/lib/libMonoPosixHelper.so /tmp/libMonoPosixHelper.so
cp -a /usr/lib/libmono-btls-shared.so /tmp/libmono-btls-shared.so

Problem: files libMonoPosixHelper.so and libmono-btls-shared.so do not exist under this path.

What do I do wrong? Is the alpine docker image incorrect? I used mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.13

It seems that what’s directly on the image is not really relevant because of the chroot into alpine, I would trust build_server_2.sh script takes care of those files being there, but will double check.

Update:
It looks like all the .dll files copied by the following loop:

for dll in I18N.CJK.dll I18N.MidEast.dll I18N.Other.dll I18N.Rare.dll I18N.West.dll I18N.dll Microsoft.CSharp.dll Mono.CSharp.dll Mono.Posix.dll Mono.Security.dll System.Collections.Immutable.dll System.ComponentModel.DataAnnotations.dll System.Configuration.dll System.Core.dll System.Data.dll System.Drawing.dll System.EnterpriseServices.dll System.IO.Compression.FileSystem.dll System.IO.Compression.dll System.Management.dll System.Net.Http.WebRequest.dll System.Net.Http.dll System.Net.dll System.Numerics.Vectors.dll System.Numerics.dll System.Reflection.Metadata.dll System.Runtime.InteropServices.RuntimeInformation.dll System.Runtime.Serialization.dll System.ServiceModel.Internals.dll System.ServiceModel.dll System.Transactions.dll System.Web.dll System.Xml.Linq.dll System.Xml.dll System.dll mscorlib.dll; do
	cp /usr/lib/mono/4.5/$dll /opt/cfx-server/citizen/clr2/lib/mono/4.5/ || true
done

are there with the exception of System.Runtime.InteropServices.RuntimeInformation.dll, which can be fixed by adding the following line to build_server_2.sh above the loop:

cp -a ../data/server_windows/citizen/clr2/lib/mono/4.5/System.Runtime.InteropServices.RuntimeInformation.dll /usr/lib/mono/4.5

Only problem that still remains is this:

Linking citizen-server-state-fivesv
readelf: Warning: Separate debug info file /usr/lib/debug//lib//ld-musl-x86_64.so.1.debug found, but CRC does not match - ignoring
readelf: Warning: Separate debug info file /usr/lib/debug//lib//ld-musl-x86_64.so.1.debug found, but CRC does not match - ignoring
Bus error (core dumped)
/src/code/tools/ci/build_server_2.sh: line 217: objcopy: I/O error
/src/code/tools/ci/build_server_2.sh: line 218: rm: I/O error

For now I will try to just cut out this part (it’s some magic binary patching that seems to be something unimportant like some version tagging or something like that, but I can be wrong) and see if the server is actually runnable.

Update 2:

The binary patching might have been important afterall, After trying to run the server, it immediately crashes with an assertion failure:

Assertion failed: IsObject() (../../../../vendor/rapidjson/include/rapidjson/document.h: FindMember: 1249)

Remove the line with "svadhesive" from components.json. It seems ignoring this component automatically was only added for the Win32 loader.

Thanks, that did the trick. I can actually build and run my custom server now. :heart_eyes:

I’m still getting Connection rejected by server: No authentication ticket was specified. when trying to log into it without sv_lan 1, so time to start digging through the source to find the relevant part and fix it.