paperless-ngx-v5-install.sh 7.8 KB

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