paperless-ngx-install.sh 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. #!/usr/bin/env bash
  2. if [ "$VERBOSE" == "yes" ]; then set -x; fi
  3. YW=$(echo "\033[33m")
  4. RD=$(echo "\033[01;31m")
  5. BL=$(echo "\033[36m")
  6. GN=$(echo "\033[1;92m")
  7. CL=$(echo "\033[m")
  8. RETRY_NUM=10
  9. RETRY_EVERY=3
  10. NUM=$RETRY_NUM
  11. CM="${GN}✓${CL}"
  12. CROSS="${RD}✗${CL}"
  13. BFR="\\r\\033[K"
  14. HOLD="-"
  15. set -o errexit
  16. set -o errtrace
  17. set -o nounset
  18. set -o pipefail
  19. shopt -s expand_aliases
  20. alias die='EXIT=$? LINE=$LINENO error_exit'
  21. trap die ERR
  22. function error_exit() {
  23. trap - ERR
  24. local reason="Unknown failure occurred."
  25. local msg="${1:-$reason}"
  26. local flag="${RD}‼ ERROR ${CL}$EXIT@$LINE"
  27. echo -e "$flag $msg" 1>&2
  28. exit $EXIT
  29. }
  30. function msg_info() {
  31. local msg="$1"
  32. echo -ne " ${HOLD} ${YW}${msg}..."
  33. }
  34. function msg_ok() {
  35. local msg="$1"
  36. echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
  37. }
  38. function msg_error() {
  39. local msg="$1"
  40. echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
  41. }
  42. msg_info "Setting up Container OS "
  43. sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
  44. locale-gen >/dev/null
  45. while [ "$(hostname -I)" = "" ]; do
  46. echo 1>&2 -en "${CROSS}${RD} No Network! "
  47. sleep $RETRY_EVERY
  48. ((NUM--))
  49. if [ $NUM -eq 0 ]; then
  50. echo 1>&2 -e "${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
  51. exit 1
  52. fi
  53. done
  54. msg_ok "Set up Container OS"
  55. msg_ok "Network Connected: ${BL}$(hostname -I)"
  56. set +e
  57. alias die=''
  58. if nc -zw1 8.8.8.8 443; then msg_ok "Internet Connected"; else
  59. msg_error "Internet NOT Connected"
  60. read -r -p "Would you like to continue anyway? <y/N> " prompt
  61. if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]; then
  62. echo -e " ⚠️ ${RD}Expect Issues Without Internet${CL}"
  63. else
  64. echo -e " 🖧 Check Network Settings"
  65. exit 1
  66. fi
  67. fi
  68. RESOLVEDIP=$(nslookup "github.com" | awk -F':' '/^Address: / { matched = 1 } matched { print $2}' | xargs)
  69. if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi
  70. alias die='EXIT=$? LINE=$LINENO error_exit'
  71. set -e
  72. msg_info "Updating Container OS"
  73. apt-get update &>/dev/null
  74. apt-get -y upgrade &>/dev/null
  75. msg_ok "Updated Container OS"
  76. msg_info "Installing Paperless-ngx Dependencies"
  77. apt-get install -y --no-install-recommends \
  78. python3 \
  79. python3-pip \
  80. python3-dev \
  81. imagemagick \
  82. fonts-liberation \
  83. optipng \
  84. gnupg \
  85. libpq-dev \
  86. libmagic-dev \
  87. mime-support \
  88. libzbar0 \
  89. poppler-utils \
  90. default-libmysqlclient-dev \
  91. sudo &>/dev/null
  92. msg_ok "Installed Paperless-ngx Dependencies"
  93. msg_info "Installing OCR Dependencies"
  94. apt-get install -y --no-install-recommends \
  95. unpaper \
  96. ghostscript \
  97. icc-profiles-free \
  98. qpdf \
  99. liblept5 \
  100. libxml2 \
  101. pngquant \
  102. zlib1g \
  103. tesseract-ocr \
  104. tesseract-ocr-eng &>/dev/null
  105. msg_ok "Installed OCR Dependencies"
  106. msg_info "Installing Extra Dependencies"
  107. apt-get install -y --no-install-recommends \
  108. redis \
  109. postgresql \
  110. build-essential \
  111. python3-setuptools \
  112. python3-wheel &>/dev/null
  113. msg_ok "Installed Extra Dependencies"
  114. msg_info "Installing JBIG2"
  115. apt-get install -y --no-install-recommends \
  116. automake \
  117. libtool \
  118. pkg-config \
  119. git \
  120. curl \
  121. libtiff-dev \
  122. libpng-dev \
  123. libleptonica-dev &>/dev/null
  124. git clone https://github.com/agl/jbig2enc /opt/jbig2enc &>/dev/null
  125. cd /opt/jbig2enc
  126. /bin/bash -c "./autogen.sh" &>/dev/null &&
  127. /bin/bash -c "./configure && make" &>/dev/null &&
  128. /bin/bash -c "make install" &>/dev/null
  129. rm -rf /opt/jbig2enc
  130. msg_ok "Installed JBIG2"
  131. msg_info "Downloading Paperless-ngx"
  132. Paperlessngx=$(wget -q https://github.com/paperless-ngx/paperless-ngx/releases/latest -O - | grep "title>Release" | cut -d " " -f 5)
  133. cd /opt &&
  134. wget https://github.com/paperless-ngx/paperless-ngx/releases/download/$Paperlessngx/paperless-ngx-$Paperlessngx.tar.xz &>/dev/null &&
  135. tar -xf paperless-ngx-$Paperlessngx.tar.xz -C /opt/ &>/dev/null &&
  136. mv paperless-ngx paperless &&
  137. rm paperless-ngx-$Paperlessngx.tar.xz
  138. cd /opt/paperless
  139. ## python 3.10+ doesn't like the '-e', so we remove it from this the requirements file
  140. sed -i -e 's|-e git+https://github.com/paperless-ngx/django-q.git|git+https://github.com/paperless-ngx/django-q.git|' /opt/paperless/requirements.txt
  141. /usr/bin/python3 -m pip install --upgrade pip &>/dev/null
  142. /usr/bin/python3 -m pip install -r requirements.txt &>/dev/null
  143. msg_ok "Downloaded Paperless-ngx"
  144. msg_info "Setting up database"
  145. DB_USER=paperless
  146. DB_PASS="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13)"
  147. DB_NAME=paperlessdb
  148. sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';" &>/dev/null
  149. sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER TEMPLATE template0;" &>/dev/null
  150. echo "Paperless-ngx Database User" >>~/paperless.creds
  151. echo $DB_USER >>~/paperless.creds
  152. echo "Paperless-ngx Database Password" >>~/paperless.creds
  153. echo $DB_PASS >>~/paperless.creds
  154. echo "Paperless-ngx Database Name" >>~/paperless.creds
  155. echo $DB_NAME >>~/paperless.creds
  156. /bin/bash -c "mkdir -p {consume,media}"
  157. sed -i -e 's|#PAPERLESS_DBNAME=paperless|PAPERLESS_DBNAME=paperlessdb|' /opt/paperless/paperless.conf
  158. sed -i -e "s|#PAPERLESS_DBPASS=paperless|PAPERLESS_DBPASS=$DB_PASS|" /opt/paperless/paperless.conf
  159. SECRET_KEY="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)"
  160. sed -i -e "s|#PAPERLESS_SECRET_KEY=change-me|PAPERLESS_SECRET_KEY=$SECRET_KEY|" /opt/paperless/paperless.conf
  161. cd /opt/paperless/src
  162. /usr/bin/python3 manage.py migrate &>/dev/null
  163. msg_ok "Set up database"
  164. msg_info "Setting up admin Paperless-ngx User & Password"
  165. ## From https://github.com/linuxserver/docker-paperless-ngx/blob/main/root/etc/cont-init.d/99-migrations
  166. cat <<EOF | python3 /opt/paperless/src/manage.py shell
  167. from django.contrib.auth import get_user_model
  168. UserModel = get_user_model()
  169. if len(UserModel.objects.all()) == 1:
  170. user = UserModel.objects.create_user('admin', password='$DB_PASS')
  171. user.is_superuser = True
  172. user.is_staff = True
  173. user.save()
  174. EOF
  175. echo "" >>~/paperless.creds
  176. echo "Paperless-ngx WebUI User" >>~/paperless.creds
  177. echo admin >>~/paperless.creds
  178. echo "Paperless-ngx WebUI Password" >>~/paperless.creds
  179. echo $DB_PASS >>~/paperless.creds
  180. msg_ok "Set up admin Paperless-ngx User & Password"
  181. cat <<EOF >/etc/systemd/system/paperless-scheduler.service
  182. [Unit]
  183. Description=Paperless Celery beat
  184. Requires=redis.service
  185. [Service]
  186. WorkingDirectory=/opt/paperless/src
  187. ExecStart=celery --app paperless beat --loglevel INFO
  188. [Install]
  189. WantedBy=multi-user.target
  190. EOF
  191. cat <<EOF >/etc/systemd/system/paperless-task-queue.service
  192. [Unit]
  193. Description=Paperless Celery Workers
  194. Requires=redis.service
  195. [Service]
  196. WorkingDirectory=/opt/paperless/src
  197. ExecStart=celery --app paperless worker --loglevel INFO
  198. [Install]
  199. WantedBy=multi-user.target
  200. EOF
  201. cat <<EOF >/etc/systemd/system/paperless-consumer.service
  202. [Unit]
  203. Description=Paperless consumer
  204. Requires=redis.service
  205. [Service]
  206. WorkingDirectory=/opt/paperless/src
  207. ExecStart=python3 manage.py document_consumer
  208. [Install]
  209. WantedBy=multi-user.target
  210. EOF
  211. cat <<EOF >/etc/systemd/system/paperless-webserver.service
  212. [Unit]
  213. Description=Paperless webserver
  214. After=network.target
  215. Wants=network.target
  216. Requires=redis.service
  217. [Service]
  218. WorkingDirectory=/opt/paperless/src
  219. ExecStart=/usr/local/bin/gunicorn -c /opt/paperless/gunicorn.conf.py paperless.asgi:application
  220. [Install]
  221. WantedBy=multi-user.target
  222. EOF
  223. sed -i -e 's/rights="none" pattern="PDF"/rights="read|write" pattern="PDF"/' /etc/ImageMagick-6/policy.xml
  224. systemctl daemon-reload
  225. systemctl enable --now paperless-consumer paperless-webserver paperless-scheduler paperless-task-queue.service &>/dev/null
  226. msg_ok "Finished installing Paperless-ngx"
  227. PASS=$(grep -w "root" /etc/shadow | cut -b6)
  228. if [[ $PASS != $ ]]; then
  229. msg_info "Customizing Container"
  230. rm /etc/motd
  231. rm /etc/update-motd.d/10-uname
  232. touch ~/.hushlogin
  233. GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
  234. mkdir -p $(dirname $GETTY_OVERRIDE)
  235. cat <<EOF >$GETTY_OVERRIDE
  236. [Service]
  237. ExecStart=
  238. ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
  239. EOF
  240. systemctl daemon-reload
  241. systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//')
  242. msg_ok "Customized Container"
  243. fi
  244. msg_info "Cleaning up"
  245. apt-get autoremove >/dev/null
  246. apt-get autoclean >/dev/null
  247. msg_ok "Cleaned"