docker-entrypoint.sh 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/bin/sh
  2. # Bambuddy container entrypoint.
  3. #
  4. # Runs as root (the image leaves USER unset, so containers start as
  5. # root by default), chowns /app/data and /app/logs to PUID:PGID, then
  6. # drops to PUID:PGID via gosu and execs the application. This fixes the
  7. # class of "Permission denied" errors that bit users when:
  8. #
  9. # - a Docker named volume was first created with root ownership and
  10. # the container was running with `user: 1000:1000` (named volumes
  11. # created by the daemon take its ownership; Dockerfile chmod hacks
  12. # cover the parent path but not subdirs created at runtime).
  13. # - a bind-mount source path didn't exist on the host yet, so dockerd
  14. # created it as root before the container started, leaving it
  15. # unwritable by uid 1000 inside the container — see #1211 / #668
  16. # for the virtual_printer bind-mount case the shipped compose
  17. # template ships uncommented.
  18. #
  19. # If the container is started with an explicit `user:` directive
  20. # (compose `user:` or `docker run --user`), the entrypoint runs as that
  21. # user instead of root and chown isn't possible. The script falls
  22. # through to direct exec without modifying ownership — preserving the
  23. # previous behavior for users who pin a specific uid via compose.
  24. set -eu
  25. # Default to 1000:1000 to match the legacy `user: "1000:1000"` default
  26. # in our previously-shipped compose template; overridable via env so
  27. # users who run docker as a different uid can match their host without
  28. # editing the compose user: directive.
  29. PUID="${PUID:-1000}"
  30. PGID="${PGID:-1000}"
  31. # If requested, update and use the system trust store inside the container.
  32. # Users can set USE_SYSTEM_TRUST_STORE to any non-empty value to enable.
  33. if [ -n "${USE_SYSTEM_TRUST_STORE:-}" ]; then
  34. echo "[entrypoint] USE_SYSTEM_TRUST_STORE is set"
  35. if [ "$(id -u)" -ne 0 ]; then
  36. echo "[entrypoint] error: USE_SYSTEM_TRUST_STORE is set but not running as root; cannot update trust store"
  37. exit 1
  38. fi
  39. # Check if we have any certificates to process. Error if directory is empty
  40. if ls -1 /usr/local/share/ca-certificates/*.crt >/dev/null 2>&1; then
  41. echo "[entrypoint] .crt files found in /usr/local/share/ca-certificates"
  42. else
  43. echo "[entrypoint] no .crt files in /usr/local/share/ca-certificates"
  44. exit 1
  45. fi
  46. if command -v update-ca-certificates >/dev/null 2>&1; then
  47. echo "[entrypoint] update-ca-certificates found; updating system trust store"
  48. if update-ca-certificates --fresh ; then
  49. echo "[entrypoint] update-ca-certificates succeeded; exporting SSL_CERT_DIR=/etc/ssl/certs"
  50. export SSL_CERT_DIR="/etc/ssl/certs"
  51. else
  52. echo "[entrypoint] error: update-ca-certificates failed"
  53. exit 1
  54. fi
  55. else
  56. echo "[entrypoint] error: update-ca-certificates not found; cannot update trust store"
  57. exit 1
  58. fi
  59. else
  60. echo "[entrypoint] USE_SYSTEM_TRUST_STORE not set; skipping system trust store update"
  61. fi
  62. # If we're not root, we can't chown anything. Exec the original command
  63. # and trust that the user has set up host-side ownership themselves.
  64. if [ "$(id -u)" -ne 0 ]; then
  65. exec "$@"
  66. fi
  67. # `chown -R` is gated behind a top-level ownership check so a correctly-
  68. # owned directory isn't traversed on every container start. A user with
  69. # a multi-GB archive directory would otherwise pay seconds-to-minutes
  70. # of chown traversal at every restart.
  71. chown_if_needed() {
  72. target="$1"
  73. [ -d "$target" ] || mkdir -p "$target"
  74. current="$(stat -c '%u:%g' "$target" 2>/dev/null || echo '')"
  75. if [ "$current" != "$PUID:$PGID" ]; then
  76. echo "[entrypoint] chown -R ${PUID}:${PGID} ${target}"
  77. chown -R "${PUID}:${PGID}" "$target" || true
  78. fi
  79. }
  80. chown_if_needed /app/data
  81. chown_if_needed /app/logs
  82. # Bind-mount-source path needs the same treatment when present. dockerd
  83. # creates missing bind-mount sources as root on the host before the
  84. # container starts; the chown here propagates through the bind mount to
  85. # the host-side directory and fixes the issue once and for all.
  86. if [ -d /app/data/virtual_printer ]; then
  87. chown_if_needed /app/data/virtual_printer
  88. fi
  89. # Drop privileges and run the application. python's file capabilities
  90. # (cap_net_bind_service=+ep, set in the Dockerfile) survive the uid
  91. # switch, so binding to :322 / :990 still works post-drop.
  92. exec gosu "${PUID}:${PGID}" "$@"