This example deploys a stack with BF2Statistics ASP
3.x.x
.
Note that the bf2sclone
2.x.x
does not work with BF2Statistics 3.x.x
, and so it is excluded from this example. The community has tried to fix it, but so far none seem to have shared their working changes. Wilson212, the original author of BF2Statistics did mention to be working on it, see here, so we might see it soon. If you want to have a working bf2sclone
, use BF2Statistics 2.x.x
in the meantime.
In this example, we will use the domain name example.com
. In production, you should use your own domain name for traefik
(our TLS-terminating load balancer) to be able to serve HTTPS for the web endpoints: ASP
, and phpmyadmin
.
Add a couple of hostnames to the hosts
file for the web endpoints:
# Since we are testing this stack locally, we need these DNS records in the hosts file
echo '127.0.0.1 asp.example.com' | sudo tee -a /etc/hosts
echo '127.0.0.1 phpmyadmin.example.com' | sudo tee -a /etc/hosts
Run:
docker-compose up
If there is error listen udp4 0.0.0.0:53: bind: address already in use
or something similar, the OS might already have a DNS server running on localhost UDP port 53
, e.g. systemd-resolved
or docker DNS server. To get around that, change coredns
in docker-compose.yml
to bind to your external interface's IP. Change this
ports:
- 53:53/udp
to
ports:
- 192.168.1.100:53:53/udp
assuming 192.168.1.100
is your machine's external IP address.
If there is a similar error for TCP port 80
or 443
, you might have an existing web server running. Stop the web server first. Run docker-compose up
again.
You should see something like:
$ docker-compose up
[+] Running 8/8
✔ Container bf2stats-coredns-1 Created 0.0s
✔ Container bf2stats-init-container-1 Created 0.0s
✔ Container bf2stats-db-1 Created 0.0s
✔ Container bf2stats-phpmyadmin-1 Created 0.0s
✔ Container bf2stats-prmasterserver-1 Created 0.0s
✔ Container bf2stats-traefik-1 Created 0.0s
✔ Container bf2stats-asp-1 Recreated 0.0s
✔ Container bf2stats-bf2-1 Recreated 0.0s
Attaching to bf2stats-asp-1, bf2stats-bf2-1, bf2stats-coredns-1, bf2stats-db-1, bf2stats-init-container-1, bf2stats-phpmyadmin-1, bf2stats-prmasterserver-1, bf2stats-traefik-1
The full stack is now running:
- Battlefield 2 1.5 server with
bf2stats
3.x.x
support available on your external IP address on UDP ports16567
and29900
on your external IP address - Gamespy server
PRMasterServer
available at your external IP address on TCP ports29900
,29901
,28910
, and UDP ports27900
and29910
on your external IP address coredns
available on your external IP address on UDP port53
on your external IP addresstraefik
(TLS-terminated reverse web proxy) available on port80
and443
on your external IP addressASP
available at https://asp.example.com on your external IP address.phpmyadmin
available at https://phpmyadmin.example.com on your external IP address.
If you are behind NAT, you will need to forward all of the above TCP and UDP ports to your external IP address, in order for clients to reach your gameserver and webserver over the internet.
Visit https://asp.example.com/ASP and login using $admin_user
and $admin_pass
defined in its config file.
Since traefik hasn't got a valid TLS certificate via
ACME
, it will serve theTRAEFIK DEFAULT CERT
. The browser will show a security issue when visiting https://asp.example.com and https://phpmyadmin.example.com. Simply click "visit site anyway" button to get past the security check.
Click on System > System Installation
and install the DB using $db_host
,$db_port
,$db_name
,$db_user
,$db_pass
you defined in config.php
. Click System > System Tests
and Run System Tests
and all tests should be green, except for the BF2Statistics Processing
test and the four .aspx
tests, because we still don't have a Fully Qualified Domain Name (FQDN) with a public DNS record.
Then, restart the BF2 server so that it begins recording stats:
docker-compose restart bf2
Configure coredns
to spoof all gamespy DNS in config/coredns/hosts, replacing the IP addresses with your machine's external IP address which you specified in Step 2.
. Assuming your external IP is 192.168.1.100
, it should look like:
192.168.1.100 battlefield2.available.gamespy.com
192.168.1.100 battlefield2.master.gamespy.com
192.168.1.100 battlefield2.ms14.gamespy.com
192.168.1.100 master.gamespy.com
192.168.1.100 motd.gamespy.com
192.168.1.100 gpsp.gamespy.com
192.168.1.100 gpcm.gamespy.com
192.168.1.100 gamespy.com
192.168.1.100 bf2web.gamespy.com
192.168.1.100 gamestats.gamespy.com
192.168.1.100 eapusher.dice.se
Save the file. coredns
immediately reads the changed file and serves the updated DNS records.
Configure your BF2 client machine (and your friends' machines) to use the DNS server (i.e. your local machine) you configured in Step 2.
(E.g. 192.168.1.100
).
If you are on different networks, you may use any of these methods. Option 3.
is recommended.
If you are all on the same LAN network, configuring DNS via DHCP is the easiest. Configure router's DHCP server's DNS setting to your machine's IP address, which will automatically configure all client's machines to use your machine as the DNS server (i.e. coredns
). Then ensure coredns
forwards all unmatched DNS (all non-gamespy DNS) back to your router so that your LAN DNS remains fully intact. To do so, in config/coredns/Corefile
change this line:
forward . 192.168.0.1:53
to your router's IP address (e.g. 192.168.1.1
):
forward . 192.168.1.1:53
Restart coredns
and it will be ready:
docker-compose restart coredns
BF2 1.5 clients should be able to connect to your gameserver. Start BF2, click Create Account
, and once you've logged in, click CONNECT TO IP
, and in the IP ADDRESS
box enter the external IP address of the machine you used in Step 2.
(E.g. 192.168.1.100
). Join the server.
You may see your server listed under
MULTIPLAYER > JOIN INTERNET
, when clickingUPDATE SERVER LIST
, but with a wrong IP address, for instance,172.16.x.x
instead of being your external IP address192.168.1.100
. This happens because in our exampledocker-compose.yml
, thebf2
server andprmasterserver
are linked using agamespy-network
, such thatbf2
container registered itself withprmasterserver
container overgamespy-network
, soprmasterserver
listed thebf2
server's container's IP address instead of the machine's external IP address. To solve this, run both thebf2
server andprmasterserver
on host networking, so that they talk to each other over the machine's external interface instead of a docker network.
At the end of the first game, you should see your stats updated at https://bf2sclone.example.com.
- Visit https://asp.example.com/ASP to adminstrate your stats database and gamespy server. Login using
$admin_user
and$admin_pass
defined in its config file. - Visit https://phpmyadmin.example.com if you want to self-manage your DB (if you know how). Login using user
root
and passwordMARIADB_ROOT_PASSWORD
(orMARIADB_USER
andMARIADB_PASSWORD
) defined on thedb
service in docker-compose.yml - This example includes all the configuration files for each stack component. Customize them to suit your needs.
- Mount the
ASP
config.php
with write permissions, or elseASP
dashboard will throw an error. UseSystem > Edit Configuration
as reference to customize the config file. - For better security, define
MARIADB_USER
andMARIADB_PASSWORD
for thedb
service, so that a regularmariadb
user is created on the first run, instead of using theroot
user. Note that this hasn't been tested, but it seems to work nicely, although it might break some modules in theASP
dashboard if they rely onroot
privileges (any at all?). - Optional: Mount your customized
armyAbbreviationMap.php
,backendAwards.php
, andranks.php
config files if you are using a customized mod. Unlikeconfig.php
, they don't need write permissions. - Backup the DB using
mysqldump
instead of the ASP.System > Backup Stats Database
will not be allowed since the DB is on remote host. This means there is no need for provisioning abackups-volume
volume. - In a production setup, you want to make sure:
- to use a custom domain name (FQDN)
- to configure
traefik
to be issued an ACME certificate for HTTPS to work for the web endpoints - to run
traefik
on--network host
or to use the PROXY protocol, so that it preserves client IP addresses - to run the
bf2
server andprmasterserver
on--network host
so that they: 1) talk to each other over the machine's external interface - to use stronger authentication in front of the
ASP
andphpmyadmin
, which don't have in-built strong authentication - to use strong passwords for the
ASP
admin user in config file - to use strong password for the
db
users inMARIADB_ROOT_PASSWORD
,MARIADB_USER
, andMARIADB_PASSWORD
- to use internal networks for the
db
which doesn't need egress traffic
These one-liners may be handy for adminstration of the stack.
# Start
docker-compose up
# Only if you are running the BF2 server, PRMasterServer, or traefik on host networking, you may need these iptables rules
# BF2 server
iptables -A INPUT -p udp -m udp -m conntrack --ctstate NEW --dport 16567 -j ACCEPT
iptables -A INPUT -p udp -m udp -m conntrack --ctstate NEW --dport 29900 -j ACCEPT
# PRMasterServer
iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate NEW --dport 29900 -j ACCEPT
iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate NEW --dport 29901 -j ACCEPT
iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate NEW --dport 28910 -j ACCEPT
iptables -A INPUT -p udp -m udp -m conntrack --ctstate NEW --dport 27900 -j ACCEPT
iptables -A INPUT -p udp -m udp -m conntrack --ctstate NEW --dport 29910 -j ACCEPT
# traefik
iptables -A INPUT -p udp -m udp -m conntrack --ctstate NEW --dport 80 -j ACCEPT
iptables -A INPUT -p udp -m udp -m conntrack --ctstate NEW --dport 443 -j ACCEPT
# Attach to the bf2 server console
docker attach asp_bf2_1
# Copy logs from bf2 server to this folder
docker cp asp_bf2_1:/server/bf2/python/bf2/logs .
# asp - Exec into container
docker exec -it $( docker-compose ps -q asp ) sh
# asp - List backups
docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/backups
# asp - List cache
docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/cache
# asp - List config
docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/config
# asp - List logs
docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/logs
# asp - List snapshots
docker exec -it $( docker-compose ps -q asp ) ls -alR /src/ASP/system/snapshots/
# Dump the DB
docker exec $( docker-compose ps | grep db | awk '{print $1}' ) mysqldump -uroot -pascent bf2stats | gzip > bf2stats.sql.gz
# Restore the DB
zcat bf2stats.sql.gz | docker exec -i $( docker-compose ps | grep db | awk '{print $1}' ) mysql -uroot -pascent bf2stats
# Stop
docker-compose down
# Cleanup. Warning: This destroys the all data!
docker-compose down
docker volume rm asp_prmasterserver-volume
docker volume rm asp_traefik-acme-volume
docker volume rm asp_backups-volume
docker volume rm asp_cache-volume
docker volume rm asp_config-volume
docker volume rm asp_logs-volume
docker volume rm asp_snapshots-volume
docker volume rm asp_db-volume
Problem: The Battlefield 2 client and server binaries are hardcoded with gamespy DNS records, e.g. bf2web.gamespy.com
. Because gamespy has shut down, the DNS records no longer exist on public DNS servers (read more about it here). In order to keep the game's multiplayer working, we need:
- A gamespy replacement - solved by
PRMasterServer
- DNS resolution for gamespy DNS records - solved by either by:
1.
hex patching the game binaries;2.
spoofing DNS server responses;3.
spoofing DNS records viahosts
file
This example opted for 2.
which is DNS spoofing via coredns
, because it can be done on a single machine and multiple machine setups.
This is what bf2hub.com
and many BF2 mods do.
Pros:
- Simple. Patch every client with the new binaries
Cons:
- Difficult to change to another gamespy server
- Difficult to distribute because it requires installation on each client
- Binaries may be patched with malicious code
Pros:
- Most scalable. You configure the DNS server via
DHCP
, so that every client that connects to aDHCP
server (e.g. router) is configured to use the DNS server. No client configuration needed - Easy to change to another gamespy server
Cons:
- Dangerous. The DNS server may be used as an attack vector against clients to steal cookies and direct clients to malicious websites.
Pros:
- Safest. DNS records only apply to the local machine
Cons:
- Difficult to change to another gamespy server
- Tedious to hand edit. See an example of a hosts file here
- Requires administrative privileges to update the machine's
hosts
file
For clients:
- The
BF2statisticsClientLauncher.exe
was made to do this - The
BF2GamespyRedirector
improves onBF2statisticsClientLauncher.exe
by allowing clients to save IP addresses of their favourite gamespy servers, and easily switch between them. Read more here
For servers:
- Servers environments should be stable, so
1.
or2.
is preferred.
For clients:
- The best solution depends on one's setup. If one often needs to switch between gamespy servers,
3.
is best. If one doesn't want clients to have to install anything but wants things to "just work", use2.
. If one prefers a single gamespy server run by a trustworthy community, use1.
.