From f893a5cb219d84a741113795788cc92f394c865f Mon Sep 17 00:00:00 2001 From: Leonard Jonathan Oh Date: Tue, 7 Nov 2023 15:56:08 +0000 Subject: [PATCH] Change (docker): Combine nginx and php to a single image for both `ASP` with env var support for configuration In <= v3.2.0, `asp` had separate `nginx` and `php` images. Now: `asp` image containing both `nginx` and `php`, with environment variable support, and entrypoint that sets the correct permissions. Benefits: - Easier to deploy / upgrade. No need to separate `nginx` and `php` containers - Environment variable configuration means no more need to mount config into `asp` and `bf2sclone` containers - Entrypoint script sets permissions on volumes. `init-container` should only need to set permissions for `db` volume Notable changes: - Add documentation for upgrading docker images to v3.3.x from prior versions - Update `./docs/examples` - Add tests for production builds for examples in `./docs/examples` Closes #69 --- .github/workflows/ci-master-pr.yml | 76 +++--- Dockerfile.php => Dockerfile | 32 ++- Dockerfile.nginx | 18 -- README.md | 32 ++- config/ASP/armyAbbreviationMap.php | 204 -------------- config/ASP/backendAwards.php | 235 ---------------- config/ASP/config.php | 54 ---- config/ASP/docker-entrypoint.sh | 105 ++++++++ config/ASP/{ => etc}/nginx/nginx.conf | 2 +- config/ASP/php-fpm.d/www.conf | 10 - config/ASP/ranks.php | 253 ------------------ config/ASP/supervisor.conf | 31 +++ .../ASP/usr/local/etc/php-fpm.d/php-fpm.conf | 32 +++ .../{ => usr/local/etc}/php/conf.d/php.ini | 0 docker-compose.build.yml | 15 +- docker-compose.test.yml | 233 +++++++++++++--- docker-compose.yml | 74 +---- docs/full-bf2-stack-example/.env | 2 +- docs/full-bf2-stack-example/README.md | 41 ++- .../config/ASP/armyAbbreviationMap.php | 204 -------------- .../config/ASP/backendAwards.php | 235 ---------------- .../config/ASP/config.php | 54 ---- .../config/ASP/nginx/nginx.conf | 121 --------- .../config/ASP/php-fpm.d/www.conf | 10 - .../config/ASP/php/conf.d/php.ini | 27 -- .../config/ASP/ranks.php | 253 ------------------ .../python/bf2/BF2StatisticsConfig-custom.py | 2 +- .../config/coredns/hosts | 4 +- .../docker-compose.build.prod.yml | 11 + .../full-bf2-stack-example/docker-compose.yml | 166 +++--------- docs/upgrading-docker-images-to-2.6.md | 98 +++++++ 31 files changed, 642 insertions(+), 1992 deletions(-) rename Dockerfile.php => Dockerfile (56%) delete mode 100644 Dockerfile.nginx delete mode 100644 config/ASP/armyAbbreviationMap.php delete mode 100644 config/ASP/backendAwards.php delete mode 100644 config/ASP/config.php create mode 100644 config/ASP/docker-entrypoint.sh rename config/ASP/{ => etc}/nginx/nginx.conf (99%) delete mode 100644 config/ASP/php-fpm.d/www.conf delete mode 100644 config/ASP/ranks.php create mode 100644 config/ASP/supervisor.conf create mode 100644 config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf rename config/ASP/{ => usr/local/etc}/php/conf.d/php.ini (100%) delete mode 100644 docs/full-bf2-stack-example/config/ASP/armyAbbreviationMap.php delete mode 100644 docs/full-bf2-stack-example/config/ASP/backendAwards.php delete mode 100644 docs/full-bf2-stack-example/config/ASP/config.php delete mode 100644 docs/full-bf2-stack-example/config/ASP/nginx/nginx.conf delete mode 100644 docs/full-bf2-stack-example/config/ASP/php-fpm.d/www.conf delete mode 100644 docs/full-bf2-stack-example/config/ASP/php/conf.d/php.ini delete mode 100644 docs/full-bf2-stack-example/config/ASP/ranks.php create mode 100644 docs/full-bf2-stack-example/docker-compose.build.prod.yml create mode 100644 docs/upgrading-docker-images-to-2.6.md diff --git a/.github/workflows/ci-master-pr.yml b/.github/workflows/ci-master-pr.yml index 38d150b9..58d28412 100644 --- a/.github/workflows/ci-master-pr.yml +++ b/.github/workflows/ci-master-pr.yml @@ -16,31 +16,23 @@ jobs: matrix: testenv: - dev + - prod runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v2 - - - name: Cache Docker layers (nginx) - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache-nginx - key: ${{ runner.os }}-buildx-nginx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx-nginx- - ${{ runner.os }}-buildx- + # This is commented out, so we use the default 'docker' driver instead of the 'docker-container' driver. When using 'docker-container' driver, there appears to be a rate limit on writes on Github CI which causes buildx to fail with error code 17 when it is exporting to cache + # - name: Set up Docker Buildx + # id: buildx + # uses: docker/setup-buildx-action@v2 - - name: Cache Docker layers (php) + - name: Cache Docker layers uses: actions/cache@v3 with: - path: /tmp/.buildx-cache-php - key: ${{ runner.os }}-buildx-php-${{ github.sha }} + path: /tmp/.buildx-asp-cache-nginx + key: ${{ runner.os }}-buildx-asp-${{ github.sha }} restore-keys: | - ${{ runner.os }}-buildx-php- ${{ runner.os }}-buildx- - name: Print buildx and compose @@ -54,14 +46,21 @@ jobs: run: | set -eux docker compose -f docker-compose.yml -f docker-compose.build.yml up --build -d - docker compose -f docker-compose.test.yml up + docker compose -f docker-compose.test.yml --profile dev up + + - name: Integration test 1 (prod) + if: matrix.testenv == 'prod' + run: | + set -eux + ( + cd docs/full-bf2-stack-example + sed -i '$!N;s@ports:\n - 53:53.*@@;P;D' docker-compose.yml # Remove coredns ports because it conflicts with system-resolved on the host + docker compose -f docker-compose.yml -f docker-compose.build.prod.yml up --build -d + ) + docker compose -f docker-compose.test.yml --profile prod up + docker compose -f docker-compose.test.yml --profile dns up build: - strategy: - matrix: - variant: - - nginx - - php runs-on: ubuntu-latest steps: - name: Checkout @@ -91,10 +90,9 @@ jobs: - name: Cache Docker layers uses: actions/cache@v3 with: - path: /tmp/.buildx-cache-${{ matrix.variant }} - key: ${{ runner.os }}-buildx-${{ matrix.variant }}-${{ github.sha }} + path: /tmp/.buildx-cache-asp + key: ${{ runner.os }}-buildx-${{ github.sha }} restore-keys: | - ${{ runner.os }}-buildx-${{ matrix.variant }}- ${{ runner.os }}-buildx- # This step generates the docker tags @@ -108,12 +106,12 @@ jobs: # type=ref,event=branch generates tag(s) on branch only. E.g. 'master-', 'master-abc0123-' # type=ref,event=tag generates tag(s) on tags only. E.g. 'v0.0.0-', 'v0.0.0-abc0123-' tags: | - type=ref,suffix=-${{ matrix.variant }},event=pr - type=ref,suffix=-{{sha}}-${{ matrix.variant }},event=pr - type=ref,suffix=-${{ matrix.variant }},event=branch - type=ref,suffix=-{{sha}}-${{ matrix.variant }},event=branch - type=ref,suffix=-${{ matrix.variant }},event=tag - type=ref,suffix=-{{sha}}-${{ matrix.variant }},event=tag + type=ref,suffix=,event=pr + type=ref,suffix=-{{sha}},event=pr + type=ref,suffix=,event=branch + type=ref,suffix=-{{sha}},event=branch + type=ref,suffix=,event=tag + type=ref,suffix=-{{sha}},event=tag # Disable 'latest' tag flavor: | latest=false @@ -131,36 +129,36 @@ jobs: if: github.event_name == 'pull_request' uses: docker/build-push-action@v3 with: - file: Dockerfile.${{ matrix.variant }} + file: Dockerfile context: '.' target: prod platforms: linux/amd64 push: false tags: ${{ steps.meta.outputs.tags }} - cache-from: type=local,src=/tmp/.buildx-cache-${{ matrix.variant }} - cache-to: type=local,dest=/tmp/.buildx-cache-${{ matrix.variant }}-new,mode=max + cache-from: type=local,src=/tmp/.buildx-cache-asp + cache-to: type=local,dest=/tmp/.buildx-cache-asp-new,mode=max - name: Build and push # Run on master and tags if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') uses: docker/build-push-action@v3 with: - file: Dockerfile.${{ matrix.variant }} + file: Dockerfile context: '.' target: prod platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/s390x push: true tags: ${{ steps.meta.outputs.tags }} - cache-from: type=local,src=/tmp/.buildx-cache-${{ matrix.variant }} - cache-to: type=local,dest=/tmp/.buildx-cache-${{ matrix.variant }}-new,mode=max + cache-from: type=local,src=/tmp/.buildx-cache-asp + cache-to: type=local,dest=/tmp/.buildx-cache-asp-new,mode=max # Temp fix # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 - name: Move cache run: | - rm -rf /tmp/.buildx-cache-${{ matrix.variant }} - mv /tmp/.buildx-cache-${{ matrix.variant }}-new /tmp/.buildx-cache-${{ matrix.variant }} + rm -rf /tmp/.buildx-cache-asp + mv /tmp/.buildx-cache-asp-new /tmp/.buildx-cache-asp update-draft-release: needs: [test, build] diff --git a/Dockerfile.php b/Dockerfile similarity index 56% rename from Dockerfile.php rename to Dockerfile index bc4071f1..3c736b30 100644 --- a/Dockerfile.php +++ b/Dockerfile @@ -2,14 +2,17 @@ FROM $IMAGE AS build # Set permissions for 'www-data' user -COPY ./src /src -WORKDIR /src +COPY ./src/ASP /src/ASP +WORKDIR /src/ASP RUN chown -R www-data:www-data . \ && find . -type d -exec chmod 750 {} \; \ && find . -type f -exec chmod 640 {} \; FROM $IMAGE AS dev +# Install nginx and supervisor for multi-process container +RUN apk add --no-cache ca-certificates nginx supervisor + # opcache RUN docker-php-ext-install opcache @@ -37,9 +40,28 @@ php -i; \ php -m -# Add default configs -COPY ./config/ASP/php/conf.d/php.ini /usr/local/etc/php/conf.d/php.ini -COPY ./config/ASP/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf +# Add configs +COPY ./config/ASP/. / +COPY ./src/ASP/system/config /config.sample +RUN chmod +x /docker-entrypoint.sh; +# Disable the built-in php-fpm configs, since we're using our own config +RUN set -eux; \ + mv -v /usr/local/etc/php-fpm.d/docker.conf /usr/local/etc/php-fpm.d/docker.conf.disabled; \ + mv -v /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf.disabled; \ + mv -v /usr/local/etc/php-fpm.d/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf.disabled; + +# In docker, IPs may be dynamic. This ensures we get access +ENV ADMIN_HOSTS=0.0.0.0/0 +VOLUME /src/ASP/system/backups +VOLUME /src/ASP/system/cache +VOLUME /src/ASP/system/config +VOLUME /src/ASP/system/logs +VOLUME /src/ASP/system/snapshots +EXPOSE 80 +EXPOSE 9000 +WORKDIR /src/ASP +ENTRYPOINT [] +CMD ["/docker-entrypoint.sh"] FROM dev AS prod diff --git a/Dockerfile.nginx b/Dockerfile.nginx deleted file mode 100644 index 5adae2ed..00000000 --- a/Dockerfile.nginx +++ /dev/null @@ -1,18 +0,0 @@ -ARG IMAGE=nginx:1.21-alpine -FROM $IMAGE AS build - -# Set permissions for 'nginx' user -COPY ./src /src -WORKDIR /src -RUN chown -R nginx:nginx . \ - && find . -type d -exec chmod 750 {} \; \ - && find . -type f -exec chmod 640 {} \; - -FROM $IMAGE AS dev - -# Add default configs -COPY config/ASP/nginx/nginx.conf /etc/nginx/nginx.conf - -FROM dev AS prod - -COPY --from=build /src /src diff --git a/README.md b/README.md index 8cac7315..2177ec4a 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,22 @@ [![github-actions](https://github.com/startersclan/asp/workflows/ci-master-pr/badge.svg)](https://github.com/startersclan/asp/actions) [![github-release](https://img.shields.io/github/v/release/startersclan/asp?style=flat-square)](https://github.com/startersclan/asp/releases/) -[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/asp/master-nginx?label=nginx)](https://hub.docker.com/r/startersclan/asp) -[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/asp/master-php?label=php)](https://hub.docker.com/r/startersclan/asp) +[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master?label=asp)](https://hub.docker.com/r/startersclan/asp) The new BF2Statistics 3.0 ASP, currently in public Beta. The GameSpy server to match is over at https://github.com/BF2Statistics/BattleSpy -## Usage +## Usage (docker) ```sh -docker pull startersclan/asp:3.2.0-nginx -docker pull startersclan/asp:3.2.0-php +docker run --rm -it -p 80:80 -e DB_HOST=db -e DB_HOST=db -e DB_PORT=3306 -e DB_NAME=bf2stats -e DB_USER=admin -e DB_PASS=admin startersclan/asp:3.3.0 ``` See [this](docs/full-bf2-stack-example) example showing how to deploy [Battlefield 2 1.5 server](https://github.com/startersclan/docker-bf2), [PRMasterserver](https://github.com/startersclan/PRMasterServer) as the master server, and `ASP` as the stats web server, using `docker-compose`. +### Upgrading to v2.6.0 from prior versions + +See here for [quick instructions](docs/upgrading-docker-images-to-2.6.md). + ## Development ```sh @@ -33,12 +35,24 @@ code --install-extension ms-python.python # Python intellisense # Execute this to allow php to reach the host machine via the docker0 bridge sudo iptables -A INPUT -i br+ -j ACCEPT +# 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 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/ + # Test routes -docker-compose -f docker-compose.test.yml up +docker-compose -f docker-compose.test.yml --profile dev up -# Test production builds locally -docker build -t startersclan/asp:nginx -f Dockerfile.nginx --target prod . -docker build -t startersclan/asp:php -f Dockerfile.php --target prod . +# Test production builds +(cd docs/full-bf2-stack-example && docker compose -f docker-compose.yml -f docker-compose.build.prod.yml up --build) +docker compose -f docker-compose.test.yml --profile prod up +docker compose -f docker-compose.test.yml --profile dns up # Dump the DB docker exec $( docker-compose ps | grep db | awk '{print $1}' ) mysqldump -uroot -pascent bf2stats | gzip > bf2stats.sql.gz diff --git a/config/ASP/armyAbbreviationMap.php b/config/ASP/armyAbbreviationMap.php deleted file mode 100644 index 3fa3c298..00000000 --- a/config/ASP/armyAbbreviationMap.php +++ /dev/null @@ -1,204 +0,0 @@ - [ - 'flag' => 0, - 'name' => 'United States Marine Corps' - ], - 'mec' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition' - ], - 'ch' => [ - 'flag' => 2, - 'name' => 'People\'s Liberation Army' - ], - - // Xpack 1 Special Forces - 'seal' => [ - 'flag' => 0, - 'name' => 'United States Navy Seals' - ], - 'mecsf' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition Special Forces' - ], - 'sas' => [ - 'flag' => 4, - 'name' => 'British Special Air Service' - ], - 'spetz' => [ - 'flag' => 5, - 'name' => 'Russian Spetsnaz' - ], - 'chinsurgent' => [ - 'flag' => 7, - 'name' => 'Rebels' - ], - 'meinsurgent' => [ - 'flag' => 8, - 'name' => 'Insurgents' - ], - - // Booster Pack 1 EuroForce - 'eu' => [ - 'flag' => 9, - 'name' => 'European Union' - ], - - // POE2 - 'ger' => [ - 'flag' => 10, - 'name' => 'German Forces' - ], - 'ukr' => [ - 'flag' => 12, - 'name' => 'Ukrainian Forces' - ], - - // AIX - 'un' => [ - 'flag' => 13, - 'name' => 'United Nations' - ], - - // Hard Justice - 'us2' => [ - 'flag' => 0, - 'name' => 'United States Marine Corps' - ], - 'us3' => [ - 'flag' => 0, - 'name' => 'United States Marine Corps' - ], - 'mec2' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition' - ], - 'mec3' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition' - ], - 'ch2' => [ - 'flag' => 2, - 'name' => 'People\'s Liberation Army' - ], - 'ch3' => [ - 'flag' => 2, - 'name' => 'People\'s Liberation Army' - ], - 'ca' => [ - 'flag' => 13, - 'name' => 'Canadian Forces' - ], - - // Nations at war 8.0 - 'blackwater' => [ - 'flag' => 14, - 'name' => 'Blackwater Military Contractors' - ], - 'taliban' => [ - 'flag' => 15, - 'name' => 'Taliban Forces' - ], - 'au' => [ - 'flag' => 16, - 'name' => 'Australian Forces' - ], - 'ru' => [ - 'flag' => 17, - 'name' => 'Russian Forces' - ], - 'gb' => [ - 'flag' => 18, - 'name' => 'British Forces' - ], - 'nato' => [ - 'flag' => 19, - 'name' => 'NATO Forces' - ], - 'isis' => [ - 'flag' => 20, - 'name' => 'ISIS Forces' - ], - 'iraqa' => [ - 'flag' => 21, - 'name' => 'Iraqi Forces' - ], - 'usmc' => [ - 'flag' => 0, - 'name' => 'United States Marines Corps' - ], - 'somalia' => [ - 'flag' => 23, - 'name' => 'Somalian Forces' - ], - 'rangers' => [ - 'flag' => 0, - 'name' => 'U.S Army Rangers' - ], - 'idf' => [ - 'flag' => 25, - 'name' => 'Israel Defense Force' - ], - 'chsf' => [ - 'flag' => 2, - 'name' => 'Chinese Special Forces' - ], - 'paras' => [ - 'flag' => 27, - 'name' => 'British Paratroop Regiment' - ], - 'casf' => [ - 'flag' => 28, - 'name' => 'Canadian Special Forces' - ], - 'hamas' => [ - 'flag' => 29, - 'name' => 'Hamas Forces' - ], - 'hezbollah' => [ - 'flag' => 30, - 'name' => 'Hezbollah Forces' - ], - 'iran' => [ - 'flag' => 31, - 'name' => 'Iran Forces' - ], - 'saudi_arabia' => [ - 'flag' => 32, - 'name' => 'Saudi Arabia Forces' - ], - 'syria' => [ - 'flag' => 33, - 'name' => 'Syrian Forces' - ], - 'egypt' => [ - 'flag' => 34, - 'name' => 'Egyptian Army' - ], - 'pakistan' => [ - 'flag' => 35, - 'name' => 'Pakistan Army' - ], - 'india' => [ - 'flag' => 36, - 'name' => 'Indian Armed forces' - ], -); \ No newline at end of file diff --git a/config/ASP/backendAwards.php b/config/ASP/backendAwards.php deleted file mode 100644 index 053add94..00000000 --- a/config/ASP/backendAwards.php +++ /dev/null @@ -1,235 +0,0 @@ - 180000); -}; - -/** - * Vanilla BF2 Medal Criteria - * - * @param array $row The AwardCriteria resulting row - * @param int $timesAwarded the number of times this award has been awarded - * - * @return bool true if the player is eligible to receive the award, false otherwise - */ -$vServiceMedalCriteria = function($row, $timesAwarded) -{ - $level = $timesAwarded + 1; - $best = (int)$row['brnd']; - $time = ((int)$row['time']) / 3600; // Convert to hours - $wins = (int)$row['wins']; - return ($best >= (100 * $level) && $time >= (100 * $level) && $wins >= (100 * $level)); -}; - -/** - * Special Forces Medal Criteria - * - * @param array $row The AwardCriteria resulting row - * @param int $timesAwarded the number of times this award has been awarded - * - * @return bool true if the player is eligible to receive the award, false otherwise - */ -$xServiceMedalCriteria = function($row, $timesAwarded) -{ - $level = $timesAwarded + 1; - $best = (int)$row['brnd']; - $time = ((int)$row['time']) / 3600; // Convert to hours - $wins = (int)$row['wins']; - return ($best >= (100 * $level) && $time >= (50 * $level) && $wins >= (50 * $level)); -}; - - -/** - * ------------------------------------------------------------------ - * Return Backend Awards and Criteria - * ------------------------------------------------------------------ - */ - -return array( - /** Service Ribbons */ - - // Middle Eastern Service Ribbon - new BackendAward(3191305, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (0,1,2,3,4,5,6) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 7); - } - ) - ]), - // Far East Service Ribbon - new BackendAward(3190605, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (100,101,102,103,105,601) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 6); - } - ) - ]), - // European Union Service Ribbon - new BackendAward(3270519, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (10,11,110) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - new AwardCriteria('player_map', 'sum(time) AS result', 'map_id IN (10,11,110)', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 180000); - } - ), - ]), - // North American Service Ribbon - new BackendAward(3271401, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (200,201,202) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - new AwardCriteria('player_map', 'sum(time) AS result', 'map_id IN (200,201,202)', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 90000); - } - ), - ]), - - /** Xpack Service Ribbons */ - - // Navy Seal Special Service Ribbon - new BackendAward(3261919, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 3', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (300,301,304) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // SAS Special Service Ribbon - new BackendAward(3261901, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 4', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (302,303,307) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // SPETZNAS Service Ribbon - new BackendAward(3261819, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 5', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (305,306,307) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // MECSF Service Ribbon - new BackendAward(3261319, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 6', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (300,301,304) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // Rebel Service Ribbon - new BackendAward(3261805, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 7', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (305,306) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 2); - } - ), - ]), - // Insurgent Service Ribbon - new BackendAward(3260914, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 8', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (302,303) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 2); - } - ), - ]), - - /** Service Medals */ - - // Navy Cross - new BackendAward(2021403, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 0', $vServiceMedalCriteria), - ]), - // Golden Scimitar - new BackendAward(2020719, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 1', $vServiceMedalCriteria), - ]), - // Peoples Medallion - new BackendAward(2021613, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 2', $vServiceMedalCriteria), - ]), - // European Union Service Medal - new BackendAward(2270521, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 9', $xServiceMedalCriteria), - ]), - - /** Xpack Service Medals */ - - // Navy Seal Special Service Medal - new BackendAward(2261913, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 3', $xServiceMedalCriteria), - ]), - // SAS Special Service Medal - new BackendAward(2261919, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 4', $xServiceMedalCriteria), - ]), - // SPETZ Special Service Medal - new BackendAward(2261613, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 5', $xServiceMedalCriteria), - ]), - // MECSF Special Service Medal - new BackendAward(2261303, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 6', $xServiceMedalCriteria), - ]), - // Rebels Special Service Medal - new BackendAward(2261802, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 7', $xServiceMedalCriteria), - ]), - // Insurgent Special Service Medal - new BackendAward(2260914, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 8', $xServiceMedalCriteria), - ]), -); \ No newline at end of file diff --git a/config/ASP/config.php b/config/ASP/config.php deleted file mode 100644 index 4fa69033..00000000 --- a/config/ASP/config.php +++ /dev/null @@ -1,54 +0,0 @@ - 'db_host' + VALUE=$( echo "$VALUE" | rev | sed 's/^;//' | rev ) # Strip the trailing semicolon + TYPE= + if echo "$VALUE" | grep -E "^'" > /dev/null; then + TYPE=string + elif echo "$VALUE" | grep -E "^array\(" > /dev/null; then + TYPE=array + elif echo "$VALUE" | grep -E "^[0-9]+$" > /dev/null; then + TYPE=int + else + echo "Unable to determine variable type of KEY '$KEY' in config file $CONFIG_FILE. Please check syntax." + exit 1 + fi + write_config "$KEY" "$TYPE" "$CONFIG_FILE" +done + +echo "Checking syntax of config file: $CONFIG_FILE" +php "$CONFIG_FILE" + +exec /usr/bin/supervisord -c /supervisor.conf --pidfile /run/supervisord.pid diff --git a/config/ASP/nginx/nginx.conf b/config/ASP/etc/nginx/nginx.conf similarity index 99% rename from config/ASP/nginx/nginx.conf rename to config/ASP/etc/nginx/nginx.conf index 685fdf32..a37112a6 100644 --- a/config/ASP/nginx/nginx.conf +++ b/config/ASP/etc/nginx/nginx.conf @@ -106,7 +106,7 @@ http { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTP_MOD_REWRITE On; # Tell PHP that the mod_rewrite module is ENABLED. fastcgi_index index.php; - fastcgi_pass asp-php:9000; + fastcgi_pass 127.0.0.1:9000; } location / { diff --git a/config/ASP/php-fpm.d/www.conf b/config/ASP/php-fpm.d/www.conf deleted file mode 100644 index b931b2cf..00000000 --- a/config/ASP/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/config/ASP/ranks.php b/config/ASP/ranks.php deleted file mode 100644 index 0b76d79d..00000000 --- a/config/ASP/ranks.php +++ /dev/null @@ -1,253 +0,0 @@ - array( - 'title' => 'Private', - 'points' => 0, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 0, - 'has_awards' => array() - ), - 1 => array( - 'title' => 'Private First Class', - 'points' => 150, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 0, - 'has_awards' => array() - ), - 2 => array( - 'title' => 'Lance Corporal', - 'points' => 500, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 1, - 'has_awards' => array() - ), - 3 => array( - 'title' => 'Corporal', - 'points' => 800, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 2, - 'has_awards' => array() - ), - 4 => array( - 'title' => 'Sergeant', - 'points' => 2500, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 3, - 'has_awards' => array() - ), - 5 => array( - 'title' => 'Staff Sergeant', - 'points' => 5000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 4, - 'has_awards' => array() - ), - 6 => array( - 'title' => 'Gunnery Sergeant', - 'points' => 8000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 5, - 'has_awards' => array() - ), - 7 => array( - 'title' => 'Master Sergeant', - 'points' => 20000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 6, - 'has_awards' => array() - ), - 8 => array( - 'title' => 'First Sergeant', - 'points' => 20000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 6, - 'has_awards' => array( - '1031105' => 1, // Engineer Combat Badge - '1031109' => 1, // Sniper Combat Badge - '1031113' => 1, // Medic Combat Badge - '1031115' => 1, // Spec Ops Combat Badge - '1031119' => 1, // Assault Combat Badge - '1031120' => 1, // Anti-tank Combat Badge - '1031121' => 1, // Support Combat Badge - '1031406' => 1, // Knife Combat Badge - '1031619' => 1 // Pistol Combat Badge - ) - ), - 9 => array( - 'title' => 'Master Gunnery Sergeant', - 'points' => 50000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => array(7, 8), - 'has_awards' => array() - ), - 10 => array( - 'title' => 'Sergeant Major', - 'points' => 50000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => array(7, 8), - 'has_awards' => array( - '1031923' => 1, // Ground Defense - '1220104' => 1, // Air Defense - '1220118' => 1, // Armor Badge - '1220122' => 1, // Aviator Badge - '1220803' => 1, // Helicopter Badge - '1222016' => 1 // Transport Badge - ) - ), - 11 => array( - 'title' => 'Sergeant Major of the Corp', - 'points' => 50000, - 'time' => 0, - 'skip' => true, - 'backend' => true, - 'has_rank' => 10, - 'has_awards' => array() - ), - 12 => array( - 'title' => '2nd Lieutenant', - 'points' => 60000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => array(9, 10, 11), - 'has_awards' => array() - ), - 13 => array( - 'title' => '1st Lieutenant', - 'points' => 75000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 12, - 'has_awards' => array() - ), - 14 => array( - 'title' => 'Captain', - 'points' => 90000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 13, - 'has_awards' => array() - ), - 15 => array( - 'title' => 'Major', - 'points' => 115000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 14, - 'has_awards' => array() - ), - 16 => array( - 'title' => 'Lieutenant Colonel', - 'points' => 125000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 15, - 'has_awards' => array() - ), - 17 => array( - 'title' => 'Colonel', - 'points' => 150000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 16, - 'has_awards' => array() - ), - 18 => array( - 'title' => 'Brigadier General', - 'points' => 180000, - 'time' => 3888000, // In seconds - 'skip' => false, - 'backend' => false, - 'has_rank' => 17, - 'has_awards' => array( - '1031105' => 2, // Engineer Combat Badge - '1031109' => 2, // Sniper Combat Badge - '1031113' => 2, // Medic Combat Badge - '1031115' => 2, // Spec Ops Combat Badge - '1031119' => 2, // Assault Combat Badge - '1031120' => 2, // Anti-tank Combat Badge - '1031121' => 2, // Support Combat Badge - '1031406' => 2, // Knife Combat Badge - '1031619' => 2 // Pistol Combat Badge - ) - ), - 19 => array( - 'title' => 'Major General', - 'points' => 180000, - 'time' => 4500000, // In seconds - 'skip' => false, - 'backend' => false, - 'has_rank' => 18, - 'has_awards' => array( - '1031923' => 2, // Ground Defense - '1220104' => 2, // Air Defense - '1220118' => 2, // Armor Badge - '1220122' => 2, // Aviator Badge - '1220803' => 2, // Helicopter Badge - '1222016' => 2 // Transport Badge - ) - ), - 20 => array( - 'title' => 'Lieutenant General', - 'points' => 200000, - 'time' => 5184000, // In seconds - 'skip' => false, - 'backend' => false, - 'has_rank' => 19, - 'has_awards' => array() - ), - 21 => array( - 'title' => 'General', - 'points' => 200000, - 'time' => 0, - 'skip' => false, - 'backend' => true, - 'has_rank' => 20, - 'has_awards' => array() - ), -); \ No newline at end of file diff --git a/config/ASP/supervisor.conf b/config/ASP/supervisor.conf new file mode 100644 index 00000000..26409e23 --- /dev/null +++ b/config/ASP/supervisor.conf @@ -0,0 +1,31 @@ +[supervisord] +nodaemon=true +user=root +logfile=/dev/null +logfile_maxbytes=0 + +[program:nginx] +command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;' +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:php-fpm] +command=php-fpm -F +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf b/config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf new file mode 100644 index 00000000..b5c7c7eb --- /dev/null +++ b/config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf @@ -0,0 +1,32 @@ +; Docs: https://www.php.net/manual/en/install.fpm.configuration.php +[global] +daemonize = no +error_log = /proc/self/fd/2 +; https://github.com/docker-library/php/pull/725#issuecomment-443540114 +log_limit = 8192 +log_buffering = no + +[default] +listen = 9000 +user = www-data +listen.owner = www-data +listen.group = www-data +pm = dynamic +pm.max_children = 10 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +pm.process_idle_timeout = 10s +pm.max_requests = 500 +; Enable php to read env vars +clear_env = no +catch_workers_output = yes +decorate_workers_output = no +chdir = / +pm.status_path = /status +; Allow .aspx extension +security.limit_extensions = .php .aspx +php_admin_value[log_errors] = On +php_admin_value[expose_php] = Off +php_admin_value[display_errors] = Off +php_admin_value[date.timezone] = UTC diff --git a/config/ASP/php/conf.d/php.ini b/config/ASP/usr/local/etc/php/conf.d/php.ini similarity index 100% rename from config/ASP/php/conf.d/php.ini rename to config/ASP/usr/local/etc/php/conf.d/php.ini diff --git a/docker-compose.build.yml b/docker-compose.build.yml index 7674decb..610b5b0e 100644 --- a/docker-compose.build.yml +++ b/docker-compose.build.yml @@ -1,15 +1,8 @@ # This is a docker compose override file, for development builds with caching for CI environments services: - asp-nginx: + asp: build: cache_from: - - type=local,src=/tmp/.buildx-cache-web - cache_to: - - type=local,dest=/tmp/.buildx-cache-web,mode=max - - asp-php: - build: - cache_from: - - type=local,src=/tmp/.buildx-cache-php - cache_to: - - type=local,dest=/tmp/.buildx-cache-php,mode=max + - type=local,src=/tmp/.buildx-cache-asp + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-asp,mode=maxmax diff --git a/docker-compose.test.yml b/docker-compose.test.yml index bde9817d..a0c019ec 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,41 +1,14 @@ version: '2.2' services: - test-routes: + test-ready: + profiles: + - dev + - prod + - dns image: alpine:latest - environment: - URLS: | - http://asp-nginx/ 403 - http://asp-nginx/.htaccess 401 - http://asp-nginx/ASP/ 200 - http://asp-nginx/ASP/aspx 401 - http://asp-nginx/ASP/bf2statistics.php 403 - http://asp-nginx/ASP/frontend 401 - http://asp-nginx/ASP/frontend/css/bootstrap.min.css 200 - http://asp-nginx/ASP/frontend/images/maps/foo.png 200 - http://asp-nginx/ASP/frontend/images/ranks/foo.png 200 - http://asp-nginx/ASP/frontend/images/armies/foo.png 200 - http://asp-nginx/ASP/frontend/css/bootstrap.min.css 200 - http://asp-nginx/ASP/createplayer.aspx 200 - http://asp-nginx/ASP/getawardsinfo.aspx 200 - http://asp-nginx/ASP/getbackendinfo.aspx 200 - http://asp-nginx/ASP/getleaderboard.aspx 200 - http://asp-nginx/ASP/getmapinfo.aspx 200 - http://asp-nginx/ASP/getplayerid.aspx 200 - http://asp-nginx/ASP/getplayerinfo.aspx 200 - http://asp-nginx/ASP/getrankinfo.aspx 200 - http://asp-nginx/ASP/getunlocksinfo.aspx 200 - http://asp-nginx/ASP/ranknotification.aspx 200 - http://asp-nginx/ASP/searchforplayers.aspx 200 - http://asp-nginx/ASP/selectunlock.aspx 200 - http://asp-nginx/ASP/verifyplayer.aspx 200 - http://asp-nginx/ASP/index.php 200 - http://asp-nginx/ASP/ranknotification.aspx 200 - http://asp-nginx/ASP/searchforplayers.aspx 200 - http://asp-nginx/ASP/selectunlock.aspx 200 - http://asp-nginx/ASP/getplayerinfo.aspx 200 - http://asp-nginx/ASP/system 401 networks: - bf2-network + stop_signal: SIGKILL entrypoint: - /bin/sh command: @@ -46,10 +19,10 @@ services: echo "Waiting for stack to be ready" s=0 while true; do - nc -vz -w 1 asp-nginx 80 \ - && nc -vz -w 1 asp-php 9000 \ - && nc -vz -w 1 db 3306 \ - && break || true + nc -vz -w 1 asp 80 \ + && nc -vz -w 1 asp 9000 \ + && nc -vz -w 1 db 3306 \ + && break || true s=$$(( $$s + 1 )) if [ "$$s" -eq 600 ]; then exit 1 @@ -58,6 +31,57 @@ services: sleep 3 done + test-routes: + profiles: + - dev + - prod + image: alpine:latest + environment: + URLS: | + http://asp/ 403 + http://asp/.htaccess 401 + http://asp/ASP/ 200 + http://asp/ASP/aspx 401 + http://asp/ASP/bf2statistics.php 403 + http://asp/ASP/frontend 401 + http://asp/ASP/frontend/css/bootstrap.min.css 200 + http://asp/ASP/frontend/images/maps/foo.png 200 + http://asp/ASP/frontend/images/ranks/foo.png 200 + http://asp/ASP/frontend/images/armies/foo.png 200 + http://asp/ASP/frontend/css/bootstrap.min.css 200 + http://asp/ASP/createplayer.aspx 200 + http://asp/ASP/getawardsinfo.aspx 200 + http://asp/ASP/getbackendinfo.aspx 200 + http://asp/ASP/getleaderboard.aspx 200 + http://asp/ASP/getmapinfo.aspx 200 + http://asp/ASP/getplayerid.aspx 200 + http://asp/ASP/getplayerinfo.aspx 200 + http://asp/ASP/getrankinfo.aspx 200 + http://asp/ASP/getunlocksinfo.aspx 200 + http://asp/ASP/ranknotification.aspx 200 + http://asp/ASP/searchforplayers.aspx 200 + http://asp/ASP/selectunlock.aspx 200 + http://asp/ASP/verifyplayer.aspx 200 + http://asp/ASP/index.php 200 + http://asp/ASP/ranknotification.aspx 200 + http://asp/ASP/searchforplayers.aspx 200 + http://asp/ASP/selectunlock.aspx 200 + http://asp/ASP/getplayerinfo.aspx 200 + http://asp/ASP/system 401 + + http://phpmyadmin/ 200 + networks: + - bf2-network + depends_on: + test-ready: + condition: service_completed_successfully + stop_signal: SIGKILL + entrypoint: + - /bin/sh + command: + - -c + - | + set -eu echo "$$URLS" | awk NF | while read -r i j; do if wget -q -SO- "$$i" 2>&1 | grep "HTTP/1.1 $$j " > /dev/null; then echo "PASS: $$i" @@ -67,6 +91,139 @@ services: fi done + test-endpoints: + profiles: + - prod + image: alpine:latest + environment: + ENDPOINTS: | + asp.example.com/ 403 + asp.example.com/.htaccess 401 + asp.example.com/ASP/ 200 + asp.example.com/ASP/aspx 401 + asp.example.com/ASP/bf2statistics.php 403 + asp.example.com/ASP/frontend 401 + asp.example.com/ASP/frontend/css/bootstrap.min.css 200 + asp.example.com/ASP/frontend/images/maps/foo.png 200 + asp.example.com/ASP/frontend/images/ranks/foo.png 200 + asp.example.com/ASP/frontend/images/armies/foo.png 200 + asp.example.com/ASP/frontend/css/bootstrap.min.css 200 + asp.example.com/ASP/createplayer.aspx 200 + asp.example.com/ASP/getawardsinfo.aspx 200 + asp.example.com/ASP/getbackendinfo.aspx 200 + asp.example.com/ASP/getleaderboard.aspx 200 + asp.example.com/ASP/getmapinfo.aspx 200 + asp.example.com/ASP/getplayerid.aspx 200 + asp.example.com/ASP/getplayerinfo.aspx 200 + asp.example.com/ASP/getrankinfo.aspx 200 + asp.example.com/ASP/getunlocksinfo.aspx 200 + asp.example.com/ASP/ranknotification.aspx 200 + asp.example.com/ASP/searchforplayers.aspx 200 + asp.example.com/ASP/selectunlock.aspx 200 + asp.example.com/ASP/verifyplayer.aspx 200 + asp.example.com/ASP/index.php 200 + asp.example.com/ASP/ranknotification.aspx 200 + asp.example.com/ASP/searchforplayers.aspx 200 + asp.example.com/ASP/selectunlock.aspx 200 + asp.example.com/ASP/getplayerinfo.aspx 200 + asp.example.com/ASP/system 401 + network_mode: host + depends_on: + test-ready: + condition: service_completed_successfully + stop_signal: SIGKILL + entrypoint: + - /bin/sh + command: + - -c + - | + set -eu + apk add --no-cache curl + echo "$$ENDPOINTS" | awk NF | while read -r i j; do + d=$$( echo "$$i" | cut -d '/' -f1 ) + if curl --head -skL http://$$i --resolve $$d:80:127.0.0.1 --resolve $$d:443:127.0.0.1 2>&1 | grep -E "^HTTP/(1.1|2) $$j " > /dev/null; then + echo "PASS: $$i" + else + echo "FAIL: $$i" + exit 1 + fi + done + + test-interal-dns: + profiles: + - dns + image: alpine:latest + environment: + DNS: | + battlefield2.available.gamespy.com + battlefield2.master.gamespy.com + battlefield2.ms14.gamespy.com + master.gamespy.com + motd.gamespy.com + gpsp.gamespy.com + gpcm.gamespy.com + gamespy.com + bf2web.gamespy.com + gamestats.gamespy.com + eapusher.dice.se + networks: + - bf2-network + depends_on: + test-ready: + condition: service_completed_successfully + stop_signal: SIGKILL + entrypoint: + - /bin/sh + command: + - -c + - | + set -eu + echo "$$DNS" | awk NF | grep -v '127.0.0' | while read -r h; do + if nslookup $$h | grep -v '127.0.0' | grep -E '^Address: [0-9\.]+$$'; then + echo "PASS: $$h" + else + echo "FAIL: $$h" + exit 1 + fi + done + + test-coredns: + profiles: + - dns + image: alpine:latest + environment: + DNS: | + 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 + networks: + - bf2-network + depends_on: + test-ready: + condition: service_completed_successfully + stop_signal: SIGKILL + entrypoint: + - /bin/sh + command: + - -c + - | + set -eu + echo "$$DNS" | awk NF | while read -r ip h; do + if nslookup $$h coredns | grep -E "^Address: $$ip" > /dev/null; then + echo "PASS: $$h" + else + echo "FAIL: $$h" + exit 1 + fi + done + networks: bf2-network: - name: bf2-network diff --git a/docker-compose.yml b/docker-compose.yml index eac55880..177cc220 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,11 +4,6 @@ services: image: alpine:latest volumes: - ./src:/src - - ./config/ASP/config.php:/src/ASP/system/config/config.php - - backups-volume:/src/ASP/system/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - - cache-volume:/src/ASP/system/cache - - logs-volume:/src/ASP/system/logs - - snapshots-volume:/src/ASP/system/snapshots - db-volume:/var/lib/mysql entrypoint: - /bin/sh @@ -17,78 +12,37 @@ services: - | set -eu - echo "Granting nginx and php read permissions" - find /src -type d -exec chmod 755 {} \; - find /src -type f -exec chmod 644 {} \; - - echo "Granting php write permissions" - chmod 777 /src/ASP/system/config - chmod 666 /src/ASP/system/config/config.php - chmod 666 /src/ASP/system/config/config.php.bak || true - - find /src/ASP/system/backups -type d -exec chmod 777 {} \; - find /src/ASP/system/backups -type f -exec chmod 666 {} \; - - find /src/ASP/system/cache -type d -exec chmod 777 {} \; - find /src/ASP/system/cache -type f -exec chmod 666 {} \; - - find /src/ASP/system/config -type d -exec chmod 777 {} \; - find /src/ASP/system/config -type f -exec chmod 666 {} \; - - find /src/ASP/system/logs -type d -exec chmod 777 {} \; - find /src/ASP/system/logs -type f -exec chmod 666 {} \; - - mkdir -p /src/ASP/system/snapshots/failed - mkdir -p /src/ASP/system/snapshots/processed - mkdir -p /src/ASP/system/snapshots/unauthorized - mkdir -p /src/ASP/system/snapshots/unprocessed - find /src/ASP/system/snapshots -type d -exec chmod 777 {} \; - find /src/ASP/system/snapshots -type f -exec chmod 666 {} \; - echo "Granting db write permissions" chown -R 999:999 /var/lib/mysql - asp-nginx: + asp: build: - dockerfile: Dockerfile.nginx - context: . - target: dev - volumes: - - ./src:/src:ro - - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ports: - - 8081:80 - networks: - - bf2-network - depends_on: - - init-container - - asp-php - - asp-php: - build: - dockerfile: Dockerfile.php + dockerfile: Dockerfile context: . target: dev + environment: + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=root + - DB_PASS=ascent volumes: - ./src:/src - - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize as needed - # - ./config/ASP/armyAbbreviationMap.php:/src/ASP/system/config/armyAbbreviationMap.php:ro # Optional: Customize as needed if using a custom mod - # - ./config/ASP/backendAwards.php:/src/ASP/system/config/backendAwards.php:ro # Optional: Customize as needed if using a custom mod - # - ./config/ASP/ranks.php:/src/ASP/system/config/ranks.php:ro # Optional: Customize as needed if using a custom mod - # - ./config/ASP/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro - # - ./config/ASP/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro - backups-volume:/src/ASP/system/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - cache-volume:/src/ASP/system/cache + - config-volume:/src/ASP/system/config # For a stateful config file - logs-volume:/src/ASP/system/logs - snapshots-volume:/src/ASP/system/snapshots + ports: + - 8081:80 + - 9000 networks: - bf2-network extra_hosts: # For xdebug to reach the host via `host.docker.internal`. See: https://github.com/moby/moby/pull/40007#issuecomment-578729356 and https://stackoverflow.com/questions/49907308/installing-xdebug-in-docker # If xdebug does not work, you may need to add an iptables rule to the INPUT chain: iptables -A INPUT -i br+ -j ACCEPT - host.docker.internal:host-gateway - depends_on: - - init-container db: image: mariadb:10.8 @@ -116,11 +70,11 @@ services: networks: bf2-network: - name: bf2-network volumes: backups-volume: cache-volume: + config-volume: logs-volume: snapshots-volume: db-volume: diff --git a/docs/full-bf2-stack-example/.env b/docs/full-bf2-stack-example/.env index 9a2f2c31..4cc5b70a 100644 --- a/docs/full-bf2-stack-example/.env +++ b/docs/full-bf2-stack-example/.env @@ -1 +1 @@ -COMPOSE_PROJECT_NAME=bf2stats +COMPOSE_PROJECT_NAME=asp diff --git a/docs/full-bf2-stack-example/README.md b/docs/full-bf2-stack-example/README.md index c26a2cd8..989d6758 100644 --- a/docs/full-bf2-stack-example/README.md +++ b/docs/full-bf2-stack-example/README.md @@ -2,11 +2,11 @@ This example deploys a stack with BF2Statistics `ASP` `3.x.x`. -Note that the `bf2sclone` `2.2.0` included in this example does not work with BF2Statistics `3.x.x`, but is only for demonstrative purposes. The community has tried to [fix it](https://bf2statistics.com/threads/bf2sclone-v3.2972/), 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](https://bf2statistics.com/threads/bf2statistics-v3-1-0-full-release.3010/), so we might see it soon. If you want to have a working `bf2sclone`, use [BF2Statistics `2.x.x`](https://github.com/startersclan/bf2stats) in the meantime. +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](https://bf2statistics.com/threads/bf2sclone-v3.2972/), 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](https://bf2statistics.com/threads/bf2statistics-v3-1-0-full-release.3010/), so we might see it soon. If you want to have a working `bf2sclone`, use [BF2Statistics `2.x.x`](https://github.com/startersclan/bf2stats) in the meantime. ## Usage -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`, `bf2sclone`, and `phpmyadmin`. +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`. ### 1. Setup hosts file @@ -15,7 +15,6 @@ Add a couple of hostnames to the `hosts` file for the web endpoints: ```sh # 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 bf2sclone.example.com' | sudo tee -a /etc/hosts echo '127.0.0.1 phpmyadmin.example.com' | sudo tee -a /etc/hosts ``` @@ -51,18 +50,16 @@ You should see something like: ```sh $ docker-compose up -[+] Running 10/0 - ⠿ Container bf2stats-prmasterserver-1 Running 0.0s - ⠿ Container bf2stats-phpmyadmin-1 Running 0.0s - ⠿ Container bf2stats-bf2-1 Running 0.0s - ⠿ Container bf2stats-traefik-1 Running 0.0s - ⠿ Container bf2stats-init-container-1 Created 0.0s - ⠿ Container bf2stats-db-1 Running 0.0s - ⠿ Container bf2stats-asp-php-1 Running 0.0s - ⠿ Container bf2stats-bf2sclone-php-1 Running 0.0s - ⠿ Container bf2stats-asp-nginx-1 Running 0.0s - ⠿ Container bf2stats-bf2sclone-nginx-1 Running 0.0s -Attaching to bf2stats-asp-nginx-1, bf2stats-asp-php-1, bf2stats-bf2-1, bf2stats-bf2sclone-nginx-1, bf2stats-bf2sclone-php-1, bf2stats-coredns-1, bf2stats-db-1, bf2stats-init-container-1, bf2stats-phpmyadmin-1, bf2stats-prmasterserver-1, bf2stats-traefik-1 +[+] 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: @@ -72,7 +69,6 @@ The full stack is now running: - `coredns` available on your external IP address on UDP port `53` on your external IP address - `traefik` (TLS-terminated reverse web proxy) available on port `80` and `443` on your external IP address - `ASP` available at https://asp.example.com on your external IP address. -- `bf2sclone` available at https://bf2sclone.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. @@ -81,7 +77,7 @@ The full stack is now running: Visit https://asp.example.com/ASP and login using `$admin_user` and `$admin_pass` defined in its [config file](./config/ASP/config.php). -> Since traefik hasn't got a valid TLS certificate via `ACME`, it will serve the `TRAEFIK DEFAULT CERT`. The browser will show a security issue when visiting https://asp.example.com, https://bf2sclone.example.com, and https://phpmyadmin.example.com. Simply click "visit site anyway" button to get past the security check. +> Since traefik hasn't got a valid TLS certificate via `ACME`, it will serve the `TRAEFIK 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`](./config/ASP/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. @@ -96,17 +92,17 @@ docker-compose restart bf2 Configure `coredns` to spoof all gamespy DNS in [config/coredns/hosts](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: ```txt -192.168.1.100 eapusher.dice.se 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 gamestats.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. @@ -146,7 +142,6 @@ At the end of the first game, you should see your stats updated at https://bf2sc ### Cheat sheet - 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](./config/ASP/config.php). -- Visit https://bf2sclone.example.com to view your stats over the web. It's a nice pretty web interface. Your stats will be updated at the end of each gameserver round. - Visit https://phpmyadmin.example.com if you want to self-manage your DB (if you know how). Login using user `root` and password `MARIADB_ROOT_PASSWORD` (or `MARIADB_USER` and `MARIADB_PASSWORD`) defined on the `db` service in [docker-compose.yml](./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`](./config/ASP/config.php) with write permissions, or else `ASP` dashboard will throw an error. Use `System > Edit Configuration` as reference to customize the config file. @@ -156,7 +151,7 @@ At the end of the first game, you should see your stats updated at https://bf2sc - 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 `traefik` on `--network host` or to use the PROXY protocol, so that it preserves client IP addresses - to run the `bf2` server and `prmasterserver` 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` and `phpmyadmin`, which don't have in-built strong authentication - to use strong passwords for the `ASP` admin user in [config file](./config/ASP/config.php) @@ -206,15 +201,15 @@ docker volume rm bf2stats_prmasterserver-volume docker volume rm bf2stats_traefik-acme-volume docker volume rm bf2stats_backups-volume docker volume rm bf2stats_cache-volume +docker volume rm bf2stats_config-volume docker volume rm bf2stats_logs-volume docker volume rm bf2stats_snapshots-volume -docker volume rm bf2stats_bf2sclone-cache-volume docker volume rm bf2stats_db-volume ``` ## Background: Keeping Battlefield 2 working -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. In order to keep the game's multiplayer working, we need: +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](https://github.com/startersclan/docker-bf2/master/docs/usage.md#dns-spoofing)). 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 via `hosts` file diff --git a/docs/full-bf2-stack-example/config/ASP/armyAbbreviationMap.php b/docs/full-bf2-stack-example/config/ASP/armyAbbreviationMap.php deleted file mode 100644 index 3fa3c298..00000000 --- a/docs/full-bf2-stack-example/config/ASP/armyAbbreviationMap.php +++ /dev/null @@ -1,204 +0,0 @@ - [ - 'flag' => 0, - 'name' => 'United States Marine Corps' - ], - 'mec' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition' - ], - 'ch' => [ - 'flag' => 2, - 'name' => 'People\'s Liberation Army' - ], - - // Xpack 1 Special Forces - 'seal' => [ - 'flag' => 0, - 'name' => 'United States Navy Seals' - ], - 'mecsf' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition Special Forces' - ], - 'sas' => [ - 'flag' => 4, - 'name' => 'British Special Air Service' - ], - 'spetz' => [ - 'flag' => 5, - 'name' => 'Russian Spetsnaz' - ], - 'chinsurgent' => [ - 'flag' => 7, - 'name' => 'Rebels' - ], - 'meinsurgent' => [ - 'flag' => 8, - 'name' => 'Insurgents' - ], - - // Booster Pack 1 EuroForce - 'eu' => [ - 'flag' => 9, - 'name' => 'European Union' - ], - - // POE2 - 'ger' => [ - 'flag' => 10, - 'name' => 'German Forces' - ], - 'ukr' => [ - 'flag' => 12, - 'name' => 'Ukrainian Forces' - ], - - // AIX - 'un' => [ - 'flag' => 13, - 'name' => 'United Nations' - ], - - // Hard Justice - 'us2' => [ - 'flag' => 0, - 'name' => 'United States Marine Corps' - ], - 'us3' => [ - 'flag' => 0, - 'name' => 'United States Marine Corps' - ], - 'mec2' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition' - ], - 'mec3' => [ - 'flag' => 1, - 'name' => 'Middle Eastern Coalition' - ], - 'ch2' => [ - 'flag' => 2, - 'name' => 'People\'s Liberation Army' - ], - 'ch3' => [ - 'flag' => 2, - 'name' => 'People\'s Liberation Army' - ], - 'ca' => [ - 'flag' => 13, - 'name' => 'Canadian Forces' - ], - - // Nations at war 8.0 - 'blackwater' => [ - 'flag' => 14, - 'name' => 'Blackwater Military Contractors' - ], - 'taliban' => [ - 'flag' => 15, - 'name' => 'Taliban Forces' - ], - 'au' => [ - 'flag' => 16, - 'name' => 'Australian Forces' - ], - 'ru' => [ - 'flag' => 17, - 'name' => 'Russian Forces' - ], - 'gb' => [ - 'flag' => 18, - 'name' => 'British Forces' - ], - 'nato' => [ - 'flag' => 19, - 'name' => 'NATO Forces' - ], - 'isis' => [ - 'flag' => 20, - 'name' => 'ISIS Forces' - ], - 'iraqa' => [ - 'flag' => 21, - 'name' => 'Iraqi Forces' - ], - 'usmc' => [ - 'flag' => 0, - 'name' => 'United States Marines Corps' - ], - 'somalia' => [ - 'flag' => 23, - 'name' => 'Somalian Forces' - ], - 'rangers' => [ - 'flag' => 0, - 'name' => 'U.S Army Rangers' - ], - 'idf' => [ - 'flag' => 25, - 'name' => 'Israel Defense Force' - ], - 'chsf' => [ - 'flag' => 2, - 'name' => 'Chinese Special Forces' - ], - 'paras' => [ - 'flag' => 27, - 'name' => 'British Paratroop Regiment' - ], - 'casf' => [ - 'flag' => 28, - 'name' => 'Canadian Special Forces' - ], - 'hamas' => [ - 'flag' => 29, - 'name' => 'Hamas Forces' - ], - 'hezbollah' => [ - 'flag' => 30, - 'name' => 'Hezbollah Forces' - ], - 'iran' => [ - 'flag' => 31, - 'name' => 'Iran Forces' - ], - 'saudi_arabia' => [ - 'flag' => 32, - 'name' => 'Saudi Arabia Forces' - ], - 'syria' => [ - 'flag' => 33, - 'name' => 'Syrian Forces' - ], - 'egypt' => [ - 'flag' => 34, - 'name' => 'Egyptian Army' - ], - 'pakistan' => [ - 'flag' => 35, - 'name' => 'Pakistan Army' - ], - 'india' => [ - 'flag' => 36, - 'name' => 'Indian Armed forces' - ], -); \ No newline at end of file diff --git a/docs/full-bf2-stack-example/config/ASP/backendAwards.php b/docs/full-bf2-stack-example/config/ASP/backendAwards.php deleted file mode 100644 index 053add94..00000000 --- a/docs/full-bf2-stack-example/config/ASP/backendAwards.php +++ /dev/null @@ -1,235 +0,0 @@ - 180000); -}; - -/** - * Vanilla BF2 Medal Criteria - * - * @param array $row The AwardCriteria resulting row - * @param int $timesAwarded the number of times this award has been awarded - * - * @return bool true if the player is eligible to receive the award, false otherwise - */ -$vServiceMedalCriteria = function($row, $timesAwarded) -{ - $level = $timesAwarded + 1; - $best = (int)$row['brnd']; - $time = ((int)$row['time']) / 3600; // Convert to hours - $wins = (int)$row['wins']; - return ($best >= (100 * $level) && $time >= (100 * $level) && $wins >= (100 * $level)); -}; - -/** - * Special Forces Medal Criteria - * - * @param array $row The AwardCriteria resulting row - * @param int $timesAwarded the number of times this award has been awarded - * - * @return bool true if the player is eligible to receive the award, false otherwise - */ -$xServiceMedalCriteria = function($row, $timesAwarded) -{ - $level = $timesAwarded + 1; - $best = (int)$row['brnd']; - $time = ((int)$row['time']) / 3600; // Convert to hours - $wins = (int)$row['wins']; - return ($best >= (100 * $level) && $time >= (50 * $level) && $wins >= (50 * $level)); -}; - - -/** - * ------------------------------------------------------------------ - * Return Backend Awards and Criteria - * ------------------------------------------------------------------ - */ - -return array( - /** Service Ribbons */ - - // Middle Eastern Service Ribbon - new BackendAward(3191305, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (0,1,2,3,4,5,6) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 7); - } - ) - ]), - // Far East Service Ribbon - new BackendAward(3190605, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (100,101,102,103,105,601) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 6); - } - ) - ]), - // European Union Service Ribbon - new BackendAward(3270519, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (10,11,110) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - new AwardCriteria('player_map', 'sum(time) AS result', 'map_id IN (10,11,110)', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 180000); - } - ), - ]), - // North American Service Ribbon - new BackendAward(3271401, [ - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (200,201,202) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - new AwardCriteria('player_map', 'sum(time) AS result', 'map_id IN (200,201,202)', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 90000); - } - ), - ]), - - /** Xpack Service Ribbons */ - - // Navy Seal Special Service Ribbon - new BackendAward(3261919, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 3', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (300,301,304) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // SAS Special Service Ribbon - new BackendAward(3261901, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 4', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (302,303,307) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // SPETZNAS Service Ribbon - new BackendAward(3261819, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 5', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (305,306,307) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // MECSF Service Ribbon - new BackendAward(3261319, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 6', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (300,301,304) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 3); - } - ), - ]), - // Rebel Service Ribbon - new BackendAward(3261805, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 7', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (305,306) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 2); - } - ), - ]), - // Insurgent Service Ribbon - new BackendAward(3260914, [ - new AwardCriteria('player_army', 'time AS result', 'army_id = 8', $sRibbonCriteria), - new AwardCriteria('player_map', 'count(*) AS result', 'map_id IN (302,303) AND time >= 1', - function($row, $timesAwarded) - { - return ($timesAwarded == 0 && $row['result'] == 2); - } - ), - ]), - - /** Service Medals */ - - // Navy Cross - new BackendAward(2021403, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 0', $vServiceMedalCriteria), - ]), - // Golden Scimitar - new BackendAward(2020719, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 1', $vServiceMedalCriteria), - ]), - // Peoples Medallion - new BackendAward(2021613, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 2', $vServiceMedalCriteria), - ]), - // European Union Service Medal - new BackendAward(2270521, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 9', $xServiceMedalCriteria), - ]), - - /** Xpack Service Medals */ - - // Navy Seal Special Service Medal - new BackendAward(2261913, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 3', $xServiceMedalCriteria), - ]), - // SAS Special Service Medal - new BackendAward(2261919, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 4', $xServiceMedalCriteria), - ]), - // SPETZ Special Service Medal - new BackendAward(2261613, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 5', $xServiceMedalCriteria), - ]), - // MECSF Special Service Medal - new BackendAward(2261303, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 6', $xServiceMedalCriteria), - ]), - // Rebels Special Service Medal - new BackendAward(2261802, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 7', $xServiceMedalCriteria), - ]), - // Insurgent Special Service Medal - new BackendAward(2260914, [ - new AwardCriteria('player_army', 'time, wins, brnd', 'army_id = 8', $xServiceMedalCriteria), - ]), -); \ No newline at end of file diff --git a/docs/full-bf2-stack-example/config/ASP/config.php b/docs/full-bf2-stack-example/config/ASP/config.php deleted file mode 100644 index 4fa69033..00000000 --- a/docs/full-bf2-stack-example/config/ASP/config.php +++ /dev/null @@ -1,54 +0,0 @@ - array( - 'title' => 'Private', - 'points' => 0, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 0, - 'has_awards' => array() - ), - 1 => array( - 'title' => 'Private First Class', - 'points' => 150, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 0, - 'has_awards' => array() - ), - 2 => array( - 'title' => 'Lance Corporal', - 'points' => 500, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 1, - 'has_awards' => array() - ), - 3 => array( - 'title' => 'Corporal', - 'points' => 800, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 2, - 'has_awards' => array() - ), - 4 => array( - 'title' => 'Sergeant', - 'points' => 2500, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 3, - 'has_awards' => array() - ), - 5 => array( - 'title' => 'Staff Sergeant', - 'points' => 5000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 4, - 'has_awards' => array() - ), - 6 => array( - 'title' => 'Gunnery Sergeant', - 'points' => 8000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 5, - 'has_awards' => array() - ), - 7 => array( - 'title' => 'Master Sergeant', - 'points' => 20000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 6, - 'has_awards' => array() - ), - 8 => array( - 'title' => 'First Sergeant', - 'points' => 20000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 6, - 'has_awards' => array( - '1031105' => 1, // Engineer Combat Badge - '1031109' => 1, // Sniper Combat Badge - '1031113' => 1, // Medic Combat Badge - '1031115' => 1, // Spec Ops Combat Badge - '1031119' => 1, // Assault Combat Badge - '1031120' => 1, // Anti-tank Combat Badge - '1031121' => 1, // Support Combat Badge - '1031406' => 1, // Knife Combat Badge - '1031619' => 1 // Pistol Combat Badge - ) - ), - 9 => array( - 'title' => 'Master Gunnery Sergeant', - 'points' => 50000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => array(7, 8), - 'has_awards' => array() - ), - 10 => array( - 'title' => 'Sergeant Major', - 'points' => 50000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => array(7, 8), - 'has_awards' => array( - '1031923' => 1, // Ground Defense - '1220104' => 1, // Air Defense - '1220118' => 1, // Armor Badge - '1220122' => 1, // Aviator Badge - '1220803' => 1, // Helicopter Badge - '1222016' => 1 // Transport Badge - ) - ), - 11 => array( - 'title' => 'Sergeant Major of the Corp', - 'points' => 50000, - 'time' => 0, - 'skip' => true, - 'backend' => true, - 'has_rank' => 10, - 'has_awards' => array() - ), - 12 => array( - 'title' => '2nd Lieutenant', - 'points' => 60000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => array(9, 10, 11), - 'has_awards' => array() - ), - 13 => array( - 'title' => '1st Lieutenant', - 'points' => 75000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 12, - 'has_awards' => array() - ), - 14 => array( - 'title' => 'Captain', - 'points' => 90000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 13, - 'has_awards' => array() - ), - 15 => array( - 'title' => 'Major', - 'points' => 115000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 14, - 'has_awards' => array() - ), - 16 => array( - 'title' => 'Lieutenant Colonel', - 'points' => 125000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 15, - 'has_awards' => array() - ), - 17 => array( - 'title' => 'Colonel', - 'points' => 150000, - 'time' => 0, - 'skip' => false, - 'backend' => false, - 'has_rank' => 16, - 'has_awards' => array() - ), - 18 => array( - 'title' => 'Brigadier General', - 'points' => 180000, - 'time' => 3888000, // In seconds - 'skip' => false, - 'backend' => false, - 'has_rank' => 17, - 'has_awards' => array( - '1031105' => 2, // Engineer Combat Badge - '1031109' => 2, // Sniper Combat Badge - '1031113' => 2, // Medic Combat Badge - '1031115' => 2, // Spec Ops Combat Badge - '1031119' => 2, // Assault Combat Badge - '1031120' => 2, // Anti-tank Combat Badge - '1031121' => 2, // Support Combat Badge - '1031406' => 2, // Knife Combat Badge - '1031619' => 2 // Pistol Combat Badge - ) - ), - 19 => array( - 'title' => 'Major General', - 'points' => 180000, - 'time' => 4500000, // In seconds - 'skip' => false, - 'backend' => false, - 'has_rank' => 18, - 'has_awards' => array( - '1031923' => 2, // Ground Defense - '1220104' => 2, // Air Defense - '1220118' => 2, // Armor Badge - '1220122' => 2, // Aviator Badge - '1220803' => 2, // Helicopter Badge - '1222016' => 2 // Transport Badge - ) - ), - 20 => array( - 'title' => 'Lieutenant General', - 'points' => 200000, - 'time' => 5184000, // In seconds - 'skip' => false, - 'backend' => false, - 'has_rank' => 19, - 'has_awards' => array() - ), - 21 => array( - 'title' => 'General', - 'points' => 200000, - 'time' => 0, - 'skip' => false, - 'backend' => true, - 'has_rank' => 20, - 'has_awards' => array() - ), -); \ No newline at end of file diff --git a/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py b/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py index 2532dfb5..bb1ae6ce 100644 --- a/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py +++ b/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py @@ -30,7 +30,7 @@ # ------------------------------------------------------------------------------ # ASP Stats Backend Web Server # ------------------------------------------------------------------------------ -http_backend_addr = 'asp-nginx' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. +http_backend_addr = 'asp' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. http_backend_port = 80 http_backend_asp = '/ASP/bf2statistics.php' diff --git a/docs/full-bf2-stack-example/config/coredns/hosts b/docs/full-bf2-stack-example/config/coredns/hosts index 76e7dcb4..ad8b84b2 100644 --- a/docs/full-bf2-stack-example/config/coredns/hosts +++ b/docs/full-bf2-stack-example/config/coredns/hosts @@ -1,12 +1,12 @@ # Replace these gamespy's DNS records with your machine's external IP addresses -192.168.1.100 eapusher.dice.se 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 gamestats.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 diff --git a/docs/full-bf2-stack-example/docker-compose.build.prod.yml b/docs/full-bf2-stack-example/docker-compose.build.prod.yml new file mode 100644 index 00000000..ddd5b67f --- /dev/null +++ b/docs/full-bf2-stack-example/docker-compose.build.prod.yml @@ -0,0 +1,11 @@ +# This is a docker compose override file, for production builds with caching for CI environments +services: + asp: + build: + dockerfile: Dockerfile + context: ../../ + target: prod + cache_from: + - type=local,src=/tmp/.buildx-cache-asp + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-asp,mode=max diff --git a/docs/full-bf2-stack-example/docker-compose.yml b/docs/full-bf2-stack-example/docker-compose.yml index 8065763c..e530984c 100644 --- a/docs/full-bf2-stack-example/docker-compose.yml +++ b/docs/full-bf2-stack-example/docker-compose.yml @@ -15,8 +15,7 @@ services: - gamespy-network - bf2-network depends_on: - - asp-nginx - - asp-php + - asp restart: unless-stopped tty: true stdin_open: true @@ -33,20 +32,20 @@ services: - 27900:27900/udp # Master server - 29910:29910/udp # CD key server networks: - # Spoof all gamespy DNS for the gameserver connected to this network + # Spoof all gamespy DNS for the BF2 server connected to this network gamespy-network: aliases: - - eapusher.dice.se - battlefield2.available.gamespy.com - battlefield2.master.gamespy.com - battlefield2.ms14.gamespy.com - - gamestats.gamespy.com - master.gamespy.com - motd.gamespy.com - gpsp.gamespy.com - gpcm.gamespy.com - gamespy.com - bf2web.gamespy.com + - gamestats.gamespy.com + - eapusher.dice.se restart: unless-stopped # A DNS server to spoof gamespy's DNS records for BF2 clients or servers @@ -57,7 +56,7 @@ services: # ports: # - 192.168.1.100:53:53/udp # Test DNS records to ensure coredns responds with your machine's external IP address. For example: - # nslookup bf2web.gamespy.com 192.168.1.100 + # nslookup bf2web.gamespy.com 192.168.1.100 # Response should be: # Server: 192.168.1.100 # Address: 192.168.1.100#53 @@ -68,10 +67,12 @@ services: coredns: image: coredns/coredns:1.9.3 ports: - - 192.168.1.132:53:53/udp + - 53:53/udp volumes: - ./config/coredns/Corefile:/Corefile:ro - ./config/coredns/hosts:/hosts:ro + networks: + - bf2-network restart: unless-stopped entrypoint: - /coredns @@ -102,21 +103,16 @@ services: - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - - "--certificatesresolvers.myresolver.acme.dnschallenge=true" - - "--certificatesresolvers.myresolver.acme.dnschallenge.provider=ovh" - # - "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" - - "--certificatesresolvers.myresolver.acme.email=postmaster@example.com" - - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" + - --certificatesresolvers.myresolver.acme.dnschallenge=true + - --certificatesresolvers.myresolver.acme.dnschallenge.provider=ovh + # - --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory + - --certificatesresolvers.myresolver.acme.email=postmaster@example.com + - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json - # The init container that sets up permissions for the asp and db volumes + # The init container that sets up permissions init-container: image: alpine:latest volumes: - - ./config/ASP/config.php:/src/ASP/system/config/config.php - - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - - logs-volume:/src/ASP/system/logs - - snapshots-volume:/src/ASP/system/snapshots - - bf2sclone-cache-volume:/src/bf2sclone/cache - db-volume:/var/lib/mysql entrypoint: - /bin/sh @@ -125,136 +121,57 @@ services: - | set -eu - echo "Granting ASP php write permissions" - chmod 666 /src/ASP/system/config/config.php - - chown -R 82:82 /src/ASP/system/backups - find /src/ASP/system/backups -type d -exec chmod 750 {} \; - find /src/ASP/system/backups -type f -exec chmod 640 {} \; - - chown -R 82:82 /src/ASP/system/cache - find /src/ASP/system/cache -type d -exec chmod 750 {} \; - find /src/ASP/system/cache -type f -exec chmod 640 {} \; - - chown -R 82:82 /src/ASP/system/logs - find /src/ASP/system/logs -type d -exec chmod 750 {} \; - find /src/ASP/system/logs -type f -exec chmod 640 {} \; - - mkdir -p /src/ASP/system/snapshots/failed - mkdir -p /src/ASP/system/snapshots/processed - mkdir -p /src/ASP/system/snapshots/unauthorized - mkdir -p /src/ASP/system/snapshots/unprocessed - chown -R 82:82 /src/ASP/system/snapshots - find /src/ASP/system/snapshots -type d -exec chmod 750 {} \; - find /src/ASP/system/snapshots -type f -exec chmod 640 {} \; - - echo "Granting bf2sclone php write permissions" - chown -R 82:82 /src/bf2sclone/cache - find /src/bf2sclone/cache -type d -exec chmod 750 {} \; - find /src/bf2sclone/cache -type f -exec chmod 640 {} \; - - echo "Granting db's 'mysql' user write permissions" + echo "Granting db write permissions" chown -R 999:999 /var/lib/mysql # The gamespy ASP. The dashboard is available at https://asp.example.com/ASP - asp-nginx: - image: startersclan/asp:3.2.0-nginx + asp: + image: startersclan/asp:3.2.0 labels: - "traefik.enable=true" - "traefik.docker.network=${COMPOSE_PROJECT_NAME?err}_traefik-network" # traefik v2 # http - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.rule=Host(`bf2web.gamespy.com`)" # Note: bf2web.gamespy.com doesn't need https + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.rule=Host(`bf2web.gamespy.com`)" # Note: `bf2web.gamespy.com` doesn't need https. The BF2 client BFHQ, and the BF2 server python files, make a HTTP requests to `bf2web.gamespy.com` with `Host: bf2web.gamespy.com`. # http - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.rule=Host(`asp.example.com`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.middlewares=${COMPOSE_PROJECT_NAME?err}-asp-nginx-http-myRedirectScheme" # Redirect http to https - - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.entrypoints=web" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.rule=Host(`asp.example.com`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.middlewares=${COMPOSE_PROJECT_NAME?err}-asp-http-myRedirectScheme" # Redirect http to https + - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-asp-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.tls" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.rule=Host(`asp.example.com`)" - - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-asp-nginx.loadbalancer.server.port=80" - # volumes: - # - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # Customize only if needed - networks: - - traefik-network - - bf2-network - depends_on: - - init-container - - asp-php - restart: unless-stopped - - asp-php: - image: startersclan/asp:3.2.0-php + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.entrypoints=websecure" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.tls=" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.rule=Host(`asp.example.com`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-asp.loadbalancer.server.port=80" + environment: + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=admin + - DB_PASS=admin volumes: - - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize only if needed - # - ./config/ASP/armyAbbreviationMap.php:/src/ASP/system/config/armyAbbreviationMap.php:ro # Optional: Customize as needed if using a custom mod - # - ./config/ASP/backendAwards.php:/src/ASP/system/config/backendAwards.php:ro # Optional: Customize as needed if using a custom mod - # - ./config/ASP/ranks.php:/src/ASP/system/config/ranks.php:ro # Optional: Customize as needed if using a custom mod - # - ./config/ASP/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro # Customize only if needed - # - ./config/ASP/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro # Customize only if needed - backups-volume:/src/ASP/system/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - cache-volume:/src/ASP/system/cache + - config-volume:/src/ASP/system/config # For a stateful config file - logs-volume:/src/ASP/system/logs - snapshots-volume:/src/ASP/system/snapshots networks: - - bf2-network - depends_on: - - init-container - restart: unless-stopped - - # The bf2sclone for viewing BFHQ on the web. It is available at https://bf2sclone.example.com - bf2sclone-nginx: - image: startersclan/bf2stats:2.3.0-bf2sclone-nginx - labels: - - "traefik.enable=true" - - "traefik.docker.network=${COMPOSE_PROJECT_NAME?err}_traefik-network" - # traefik v2 - # http - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.rule=Host(`bf2sclone.example.com`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.middlewares=${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http-myRedirectScheme" # Redirect http to https - - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https - # https - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.tls" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.rule=Host(`bf2sclone.example.com`)" - - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.loadbalancer.server.port=80" - # volumes: - # - ./config/bf2sclone/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # Customize only if needed - networks: - - traefik-network - - bf2-network - depends_on: - - init-container - - bf2sclone-php - restart: unless-stopped - - bf2sclone-php: - image: startersclan/bf2stats:2.3.0-bf2sclone-php - volumes: - - ./config/bf2sclone/config.inc.php:/src/bf2sclone/config.inc.php:ro # Main config file. Customize as needed - # - ./config/bf2sclone/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro # Customize only if needed - # - ./config/bf2sclone/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro # Customize only if needed - - bf2sclone-cache-volume:/src/bf2sclone/cache - networks: - - bf2-network - depends_on: - - init-container + traefik-network: + bf2-network: restart: unless-stopped # The DB container db: image: mariadb:10.8 environment: - - MARIADB_ROOT_PASSWORD=ascent # Change this to a strong password + - MARIADB_ROOT_PASSWORD=ascent - MARIADB_USER=admin - - MARIADB_PASSWORD=admin # Change this to a strong password + - MARIADB_PASSWORD=admin - MARIADB_DATABASE=bf2stats volumes: - - ./config/db/my.cnf:/etc/my.cnf:ro # Customize as needed + - ./config/db/my.cnf:/etc/my.cnf:ro # Config file. Customize as needed - db-volume:/var/lib/mysql networks: - bf2-network @@ -262,7 +179,7 @@ services: - init-container restart: unless-stopped - # The phpmyadmin interface for administrating the DB. It is available at phpmyadmin.example.com + # The phpmyadmin interface for administrating the DB. It is available at https://phpmyadmin.example.com phpmyadmin: image: phpmyadmin:5.2 labels: @@ -276,7 +193,7 @@ services: - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-phpmyadmin-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.tls" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.tls=" - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.rule=Host(`phpmyadmin.example.com`)" - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.loadbalancer.server.port=80" environment: @@ -299,6 +216,7 @@ volumes: traefik-acme-volume: backups-volume: cache-volume: + config-volume: logs-volume: snapshots-volume: bf2sclone-cache-volume: diff --git a/docs/upgrading-docker-images-to-2.6.md b/docs/upgrading-docker-images-to-2.6.md new file mode 100644 index 00000000..87c12b6f --- /dev/null +++ b/docs/upgrading-docker-images-to-2.6.md @@ -0,0 +1,98 @@ +# Upgrading docker images from previous versions + +In <= v3.2.0, `asp` had separate `nginx` and `php` images. + +Since v3.3.0: `asp` image containing both `nginx` and `php`, with environment variable support, and entrypoint that sets the correct permissions. + +Benefits: + +- Easier to deploy / upgrade. No need to separate `nginx` and `php` containers +- Environment variable configuration means no more need to mount config into `asp` and `bf2sclone` containers +- Entrypoint script sets permissions on volumes. `init-container` should only need to set permissions for `db` volume + +## Upgrade steps + +These steps are demonstrated using Docker Compose. + +1. Merge the networks and volumes of `asp-nginx` and `asp-php` into a single `asp` container, switch to a volume and env vars for `asp` configuration, and remove `depends_on`. + +For instance, from this: + +```yaml + asp-nginx: + image: startersclan/bf2stats:3.2.0-nginx + volumes: + - ./src:/src:ro + - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + networks: + traefik-network: + bf2-network: + aliases: + - bf2web.gamespy.com # Important! Spoof Gamespy DNS for the BF2 server to reach our ASP server IP over this network + depends_on: + - init-container + - asp-php + + asp-php: + image: startersclan/bf2stats:3.2.0-php + volumes: + - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize only if needed + - backups-volume:/src/ASP/system/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - cache-volume:/src/ASP/system/cache + - logs-volume:/src/ASP/system/logs + - snapshots-volume:/src/ASP/system/snapshots + networks: + - traefik-network + - bf2-network + depends_on: + - init-container +``` + +To this: + +```yaml + asp: + image: startersclan/bf2stats:3.3.0 + environment: + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=root + - DB_PASS=ascent + volumes: + - backups-volume:/src/ASP/system/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - cache-volume:/src/ASP/system/cache + - config-volume:/src/ASP/system/config # For a stateful config file + - logs-volume:/src/ASP/system/logs + - snapshots-volume:/src/ASP/system/snapshots + networks: + traefik-network: + bf2-network: + aliases: + - bf2web.gamespy.com # Important! Spoof Gamespy DNS for the BF2 server to reach our ASP server IP over this network + +volumes: + config-volume: + ... +``` + +2. If you have `init-container`, now it only needs to set permission for the `db` volume: + +```yaml + init-container: + image: alpine:latest + volumes: + - db-volume:/var/lib/mysql + entrypoint: + - /bin/sh + command: + - -c + - | + set -eu + + echo "Granting db write permissions" + chown -R 999:999 /var/lib/mysql +``` + +Done. Enjoy the simpler setup 😀