Repository navigation
Expand file tree
/
Copy pathdocker-entrypoint.sh
More file actions
106 lines (96 loc) · 4.29 KB
/
Copy pathdocker-entrypoint.sh
File metadata and controls
106 lines (96 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/bin/sh
# Renders the trusted-proxy config, then hands off to supervisord.
#
# Stackyard runs its own nginx inside the container, so when it sits behind
# another reverse proxy (Nginx Proxy Manager, Caddy, Traefik) the inner nginx
# sees that proxy as the client. Every request then looks like it came from one
# address, and per-client rate limiting degrades to one shared bucket.
#
# TRUSTED_PROXY names where the front proxy is. nginx then takes the real client
# address from the forwarding headers those proxies already send by default, so
# nothing has to be configured on their side and nothing downstream has to parse
# a header chain.
#
# TRUSTED_PROXY=172.18.0.0/16
# TRUSTED_PROXY="172.18.0.0/16 10.0.0.5"
#
# Unset means trust nothing, which is correct for direct access.
set -eu
# Overridable so the rendering can be tested without writing into /etc.
REALIP_CONF="${REALIP_CONF:-/etc/nginx/http.d/realip.conf}"
LISTEN_CONF="${LISTEN_CONF:-/etc/nginx/listen-ipv6.inc}"
INET6_PROC="${INET6_PROC:-/proc/net/if_inet6}"
DATA_DIR="${DATA_DIR:-/data}"
ICONS_DIR="${ICONS_DIR:-/icons}"
{
echo "# Generated by docker-entrypoint.sh from TRUSTED_PROXY. Do not edit."
if [ -n "${TRUSTED_PROXY:-}" ]; then
for cidr in $(echo "$TRUSTED_PROXY" | tr ',' ' '); do
echo "set_real_ip_from $cidr;"
done
echo "real_ip_header X-Forwarded-For;"
# Walk the chain from the right, skipping addresses we trust, so the real
# client is found even with several proxies in front.
echo "real_ip_recursive on;"
else
echo "# TRUSTED_PROXY not set: forwarding headers are not trusted."
fi
} > "$REALIP_CONF"
# Some platforms reach the container only over IPv6, and nginx binds the IPv4
# listener alone. Do not make this unconditional. nginx does not start when it
# cannot bind, and a container without IPv6 then serves nothing.
#
# Not under /etc/nginx/http.d/ and not named .conf. Alpine's nginx.conf includes
# that glob at the http level, where `listen` is rejected.
{
echo "# Generated by docker-entrypoint.sh. Do not edit."
# Read it. Every file under /proc reports a size of 0, so -s is always false
# here and would report IPv6 as absent on a container that has it.
if [ -n "$(cat "$INET6_PROC" 2>/dev/null)" ]; then
# ipv6only stays at nginx's default: this is a second listener beside the
# IPv4 one in dashboard.conf, not a replacement for it.
echo "listen [::]:80;"
else
echo "# No IPv6 in this container: IPv4 only."
fi
} > "$LISTEN_CONF"
# A mounted volume carries the host's ownership. The API runs as node and
# cannot write a root-owned mount: every config and icon write then fails.
for dir in "$DATA_DIR" "$ICONS_DIR"; do
[ -d "$dir" ] || continue
if su -s /bin/sh node -c "test -w \"$dir\"" 2>/dev/null; then continue; fi
chown -R node:node "$dir" ||
echo "stackyard: cannot take ownership of $dir; config and icon writes will fail" >&2
done
# Fail fast and loudly rather than starting with a config nginx will reject.
# -q keeps the two success lines out of every boot; set -eu still stops here on
# failure, and nginx still prints what it rejected.
nginx -t -q
# supervisord always exits 0 on SIGTERM, including the SIGTERM that
# scripts/exit-on-fatal.py sends when a program can no longer be started. The
# marker carries that failure out as the container's exit code, so a dead API
# reads as a failure rather than a normal shutdown and `restart: on-failure`
# behaves the same as `unless-stopped` here.
MARKER="${SUPERVISOR_FATAL_MARKER:-/run/stackyard-fatal}"
rm -f "$MARKER"
# Run in the background rather than exec, so this script survives to read the
# marker afterwards. That means signals no longer reach supervisord on their
# own, and without forwarding a `docker stop` would kill this shell and leave
# supervisord running until the kill timeout, with nothing shut down cleanly.
"$@" &
child=$!
trap 'kill -TERM "$child" 2>/dev/null' TERM INT
# Keep `|| status=$?`. A trapped signal makes `wait` return 143, and set -e
# would exit here: the kernel then kills supervisord mid-shutdown.
status=0
wait "$child" || status=$?
while kill -0 "$child" 2>/dev/null; do
status=0
wait "$child" || status=$?
done
if [ -f "$MARKER" ]; then
echo "stackyard: $(cat "$MARKER") could not be started; exiting so the container is restarted" >&2
rm -f "$MARKER"
exit 1
fi
exit "$status"