Upload 18 files
Browse files- Dockerfile +8 -3
- README.md +17 -0
- docker-entrypoint.sh +36 -0
- strip-metadata.py +1 -1
Dockerfile
CHANGED
|
@@ -4,6 +4,7 @@ RUN apt-get update \
|
|
| 4 |
&& apt-get install -y --no-install-recommends \
|
| 5 |
ca-certificates \
|
| 6 |
fonts-dejavu-core \
|
|
|
|
| 7 |
python3 \
|
| 8 |
python3-pil \
|
| 9 |
tini \
|
|
@@ -12,17 +13,21 @@ RUN apt-get update \
|
|
| 12 |
WORKDIR /app
|
| 13 |
COPY --chown=node:node . /app
|
| 14 |
|
| 15 |
-
RUN
|
|
|
|
| 16 |
&& chown -R node:node /app /data
|
| 17 |
|
| 18 |
ENV NODE_ENV=production \
|
|
|
|
| 19 |
PORT=7860 \
|
| 20 |
DATA_DIR=/data \
|
| 21 |
TIMEZONE=Africa/Casablanca \
|
| 22 |
COUNTRY_CODE=MAR
|
| 23 |
|
| 24 |
-
|
|
|
|
|
|
|
| 25 |
EXPOSE 7860
|
| 26 |
|
| 27 |
-
ENTRYPOINT ["/usr/bin/tini", "--"]
|
| 28 |
CMD ["node", "app.js"]
|
|
|
|
| 4 |
&& apt-get install -y --no-install-recommends \
|
| 5 |
ca-certificates \
|
| 6 |
fonts-dejavu-core \
|
| 7 |
+
gosu \
|
| 8 |
python3 \
|
| 9 |
python3-pil \
|
| 10 |
tini \
|
|
|
|
| 13 |
WORKDIR /app
|
| 14 |
COPY --chown=node:node . /app
|
| 15 |
|
| 16 |
+
RUN chmod 755 /app/docker-entrypoint.sh \
|
| 17 |
+
&& mkdir -p /data/logs /data/dispatcher-data/generated \
|
| 18 |
&& chown -R node:node /app /data
|
| 19 |
|
| 20 |
ENV NODE_ENV=production \
|
| 21 |
+
NODE_OPTIONS=--dns-result-order=ipv4first \
|
| 22 |
PORT=7860 \
|
| 23 |
DATA_DIR=/data \
|
| 24 |
TIMEZONE=Africa/Casablanca \
|
| 25 |
COUNTRY_CODE=MAR
|
| 26 |
|
| 27 |
+
# The entrypoint starts as root only long enough to update resolv.conf,
|
| 28 |
+
# then immediately drops privileges to the node user with gosu.
|
| 29 |
+
USER root
|
| 30 |
EXPOSE 7860
|
| 31 |
|
| 32 |
+
ENTRYPOINT ["/usr/bin/tini", "--", "/app/docker-entrypoint.sh"]
|
| 33 |
CMD ["node", "app.js"]
|
README.md
CHANGED
|
@@ -106,3 +106,20 @@ curl -X POST \
|
|
| 106 |
The first live poll creates a score baseline. Generic goal alerts begin with the next score change. If the first poll happens during half-time or after full-time, the corresponding HT or FT post can still be sent.
|
| 107 |
|
| 108 |
Set `SCHEDULE_ONLY_MODE=false` only to restore the old per-match detailed watchers. That mode may remain stuck when FotMob requests browser verification.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
The first live poll creates a score baseline. Generic goal alerts begin with the next score change. If the first poll happens during half-time or after full-time, the corresponding HT or FT post can still be sent.
|
| 107 |
|
| 108 |
Set `SCHEDULE_ONLY_MODE=false` only to restore the old per-match detailed watchers. That mode may remain stuck when FotMob requests browser verification.
|
| 109 |
+
|
| 110 |
+
## Hugging Face Facebook DNS workaround
|
| 111 |
+
|
| 112 |
+
This build starts as root only long enough to replace `/etc/resolv.conf` with Cloudflare and Google public DNS, runs DNS/HTTPS diagnostics for `graph.facebook.com`, and then starts the app as the unprivileged `node` user.
|
| 113 |
+
|
| 114 |
+
Expected startup diagnostics:
|
| 115 |
+
|
| 116 |
+
```text
|
| 117 |
+
== DNS after ==
|
| 118 |
+
nameserver 1.1.1.1
|
| 119 |
+
nameserver 8.8.8.8
|
| 120 |
+
...
|
| 121 |
+
== Facebook HTTPS test ==
|
| 122 |
+
Facebook HTTPS reachable: HTTP 400
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
Any HTTP status proves that the TCP/TLS connection reached Facebook. A timeout means the selected route is still inaccessible.
|
docker-entrypoint.sh
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
set -eu
|
| 3 |
+
|
| 4 |
+
echo "== DNS before =="
|
| 5 |
+
cat /etc/resolv.conf || true
|
| 6 |
+
|
| 7 |
+
# Hugging Face's resolver can return an unreachable Facebook edge.
|
| 8 |
+
# Prefer public resolvers when the platform permits replacing resolv.conf.
|
| 9 |
+
if [ -w /etc/resolv.conf ]; then
|
| 10 |
+
printf '%s\n' \
|
| 11 |
+
'nameserver 1.1.1.1' \
|
| 12 |
+
'nameserver 8.8.8.8' \
|
| 13 |
+
'options timeout:2 attempts:2 rotate' > /etc/resolv.conf || true
|
| 14 |
+
else
|
| 15 |
+
echo "Warning: /etc/resolv.conf is not writable; keeping platform DNS."
|
| 16 |
+
fi
|
| 17 |
+
|
| 18 |
+
echo "== DNS after =="
|
| 19 |
+
cat /etc/resolv.conf || true
|
| 20 |
+
|
| 21 |
+
echo "== Facebook DNS test =="
|
| 22 |
+
getent ahostsv4 graph.facebook.com || true
|
| 23 |
+
|
| 24 |
+
echo "== Facebook HTTPS test =="
|
| 25 |
+
node -e '
|
| 26 |
+
const signal = AbortSignal.timeout(10000);
|
| 27 |
+
fetch("https://graph.facebook.com/", { signal })
|
| 28 |
+
.then((response) => console.log(`Facebook HTTPS reachable: HTTP ${response.status}`))
|
| 29 |
+
.catch((error) => {
|
| 30 |
+
const detail = error?.cause?.message || error?.message || String(error);
|
| 31 |
+
console.log(`Facebook HTTPS test failed: ${detail}`);
|
| 32 |
+
});
|
| 33 |
+
' || true
|
| 34 |
+
|
| 35 |
+
# Start the application as the unprivileged node user.
|
| 36 |
+
exec gosu node "$@"
|
strip-metadata.py
CHANGED
|
@@ -17,4 +17,4 @@ def main() -> None:
|
|
| 17 |
|
| 18 |
|
| 19 |
if __name__ == "__main__":
|
| 20 |
-
main()
|
|
|
|
| 17 |
|
| 18 |
|
| 19 |
if __name__ == "__main__":
|
| 20 |
+
main()
|