Преглед на файлове

:wrench: add support for laravel branch

Jeremy Zheng преди 3 години
родител
ревизия
09b2dd0ac2

+ 3 - 0
deploy/.gitignore

@@ -0,0 +1,3 @@
+/clients/
+/tmp/
+*.log

+ 88 - 0
deploy/README.md

@@ -0,0 +1,88 @@
+# Deployment
+
+## Setup a cluster
+
+```bash
+# create cluster
+mkdir -p clients/CLUSTER/.ssh
+cd clients/CLUSTER
+# append your cluster hosts
+touch hosts
+# generate ssh key
+ssh-keygen -t ed25519 -f .ssh/id_ed25519
+# upload the ssh public key to target host
+ssh-copy-id -i .ssh/id_ed25519 USER@HOST
+```
+
+## Deploy
+
+```bash
+# test ssh connections
+peony -i clients/CLUSTER ping.yml
+# run on all hosts
+peony -i clients/CLUSTER ping.yml
+# run on only group
+peony -i clients/CLUSTER ping.yml -l GROUP
+```
+
+## System image
+
+- [Raspberry Pi OS Lite](https://www.raspberrypi.com/software/operating-systems/)
+- [Armbian](https://www.armbian.com/download/)
+- [wiringPi for Orange Pi](https://github.com/orangepi-xunlong/WiringOP)
+
+## Import Database Data
+
+### on deploy a new server
+
+```bash
+php ../../public/app/install/db_insert_templet_cli.php 1 217
+php ../../public/app/install/db_update_toc_cli.php 1 217 pali
+php ../../public/app/install/db_update_toc_cli.php 1 217 zh-hans
+php ../../public/app/install/db_update_toc_cli.php 1 217 zh-hant
+php ../../public/app/install/db_insert_palitext_cli.php 1 217
+php ../../public/app/install/db_update_palitext_cli.php 1 217
+php ../../public/app/install/db_insert_bookword_from_csv_cli.php 1 217
+php ../../public/app/install/db_insert_word_from_csv_cli.php 1 217
+php ../../public/app/install/db_insert_wordindex_from_csv_cli.php
+
+php ./migrations/20211202084900_init_pali_serieses.php
+php ./migrations/20211125155600_word_statistics.php
+php ./migrations/20211125155700_pali_sent_org.php
+php ./migrations/20211125165700-pali_sent-upgrade.php
+php ./migrations/20211126220400-pali_sent_index-upgrade.php
+php ./migrations/20211127214800_sent_sim.php
+php ./migrations/20211127214900-sent_sim_index.php
+
+php ../../public/app/fts/sql.php
+
+php ../../public/app/admin/word_index_weight_refresh.php 1 217
+```
+
+### on update
+
+```bash
+# public/pali_title目录下文件*_pali.csv改变时触发
+php ../../public/app/install/db_update_palitext_cli.php 1 217
+
+# public/pali_title目录下文件其他改变时触发
+php ../../public/app/install/db_update_toc_cli.php 1 217 pali
+php ../../public/app/install/db_update_toc_cli.php 1 217 zh-hans
+php ../../public/app/install/db_update_toc_cli.php 1 217 zh-hant
+
+# public/dependence/pali_sentence/data 目录下文件其他改变时触发
+# TODO 导入pali_sent使用上述目录csv文件。目前用的是sqlite db文件
+php ./migrations/20211125165700-pali_sent-upgrade.php
+php ./migrations/20211126220400-pali_sent_index-upgrade.php
+
+```
+
+## Crontab
+
+### Daily
+
+1. upgrade_pali_toc.php
+
+```bash
+/public/app/upgrade/upgrade_pali_toc.php
+```

+ 8 - 0
deploy/group_vars/all.yml

@@ -0,0 +1,8 @@
+ansible_user: "deploy"
+ansible_python_interpreter: /usr/bin/python3
+ansible_ssh_private_key_file: "{{ inventory_dir }}/.ssh/id_ed25519"
+
+app_deploy_target: "/var/www/{{ inventory_hostname }}"
+app_php_version: "8.1"
+app_downloads: "{{ ansible_env.HOME }}/downloads"
+app_backup: "{{ ansible_env.HOME }}/backups"

+ 9 - 0
deploy/mint.yml

@@ -0,0 +1,9 @@
+- hosts: all
+  roles:
+    - ubuntu
+    - os
+
+- hosts: www
+  roles:
+    - php
+    - mint

+ 4 - 0
deploy/ping.yml

@@ -0,0 +1,4 @@
+- hosts: all
+  roles:
+    - ping
+

+ 86 - 0
deploy/roles/mint/tasks/main.yml

@@ -0,0 +1,86 @@
+- name: Git checkout source code
+  ansible.builtin.git:
+    repo: "https://github.com/iapt-platform/mint.git"
+    dest: "{{ app_deploy_target }}/htdocs"
+    version: laravel
+
+- name: Setup storage folder
+  become: true
+  ansible.builtin.file:
+    path: "{{ app_deploy_target }}/storage"
+    state: directory
+    recurse: true
+    owner: www-data
+    group: www-data
+
+- name: Install v2 php dependencies
+  ansible.builtin.shell: "php{{ app_php_version }} {{ ansible_env.HOME }}/.local/bin/composer install"
+  args:
+    chdir: "{{ app_deploy_target }}"
+
+- name: Install v2 nodejs dependencies
+  # ansible.builtin.file:
+  #   src: "/var/www/{{ inventory_hostname }}/node_modules/v2"
+  #   dest: "{{ app_deploy_target }}/node_modules"
+  #   state: link
+  ansible.builtin.shell: npm install
+  args:
+    chdir: "{{ app_deploy_target }}"
+
+# TODO will remove in future
+- name: Install v1 php dependencies
+  ansible.builtin.shell: "php{{ app_php_version }} {{ ansible_env.HOME }}/.local/bin/composer install"
+  args:
+    chdir: "{{ app_deploy_target }}/public"
+
+# TODO will remove in future
+- name: Install v1 nodejs dependencies
+  # ansible.builtin.file:
+  #   src: "/var/www/{{ inventory_hostname }}/node_modules/v1"
+  #   dest: "{{ app_deploy_target }}/public/node_modules"
+  #   state: link
+  ansible.builtin.shell: npm install
+  args:
+    chdir: "{{ app_deploy_target }}/public"
+
+# TODO will remove in future
+- name: Install v1 tmp
+  ansible.builtin.file:
+    src: "/var/www/{{ inventory_hostname }}/tmp"
+    dest: "{{ app_deploy_target }}/public/tmp"
+    state: link
+
+- name: .env(v2)
+  become: true
+  ansible.builtin.template:
+    src: env-v2.j2
+    dest: "{{ app_deploy_target }}/.env"
+    owner: www-data
+    group: www-data
+    mode: "0400"
+
+# TODO will remove in future
+- name: config.php(v1)
+  become: true
+  ansible.builtin.template:
+    src: config-v1.php.j2
+    dest: "{{ app_deploy_target }}/public/app/config.php"
+    owner: www-data
+    group: www-data
+    mode: "0400"
+
+# TODO will remove in future
+- name: config.js(v1)
+  become: true
+  ansible.builtin.template:
+    src: config-v1.js.j2
+    dest: "{{ app_deploy_target }}/public/app/config.js"
+    owner: www-data
+    group: www-data
+    mode: "0400"
+
+- name: Create a current link
+  ansible.builtin.file:
+    src: "{{ app_deploy_target }}"
+    dest: /var/www/{{ inventory_hostname }}/current
+    state: link

+ 14 - 0
deploy/roles/mint/templates/config-v1.js.j2

@@ -0,0 +1,14 @@
+var RPC_SERVER="https://{{ app_rpc_host }}";
+
+/*
+  |---------------
+  |网站资源文件,非用户的图片,音频,视频
+  |---------------
+  |对应/public/tmp/ 目录 开发线可以设置为 http://127.0.0.1:8000/tmp
+  |所有文件存储在 https://drive.google.com/drive/folders/1-4dn4juD-0-lsKndDui2W9nT9wcS_Y33?usp=sharing
+  |开发线可自行下载放到/public/tmp/
+  |或直接引用离您最近的assets server
+  |------------------------
+*/
+
+var ASSETS_SERVER = "https://assets-{{ app_cluster_domain }}"

+ 60 - 0
deploy/roles/mint/templates/config-v1.php.j2

@@ -0,0 +1,60 @@
+<?php
+
+#域名设置
+define("RPC_SERVER","https://{{ app_rpc_host }}");
+define("ASSETS_SERVER","https://assets-{{ app_cluster_domain }}");
+/*
+电子邮件设置
+PHPMailer
+*/
+define("Email", [
+				 "Host"=>"smtp.gmail.com",//Set the SMTP server to send through
+				 "SMTPAuth"=>true,//Enable SMTP authentication
+				 "Username"=>'{{ app_smtp_username }}',//SMTP username
+				 "Password"=>'{{ app_smtp_password }}',//SMTP password
+				 "Port"=>465,//TCP port to connect to 465; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
+				 "From"=>"{{ app_smtp_username }}",
+				 "Sender"=>"webmaster"
+				 ]);
+
+/*
+数据库设置
+*/
+define("Database",[
+	"type"=>"pgsql",
+	"server"=>"{{ app_postgresql_host }}",
+	"port"=>{{ app_postgresql_port }},
+	"name"=>"{{ app_postgresql_name }}",
+	"sslmode" => "disable",
+	"user" => "{{ app_postgresql_user }}",
+	"password" => "{{ app_postgresql_password }}"
+]);
+
+
+/*
+Redis 设置,
+*/
+define("Redis",[
+	"host" => "{{ app_redis_host }}",
+	"port" => 6379,
+	"password" => "",
+	"namespace" => "{{ app_redis_namespace }}"
+]);
+
+# 雪花id
+define("SnowFlake",[
+	"DatacenterId"=>1,
+	"WorkerId"=>1
+]);
+
+#目录设置,不能更改
+require_once __DIR__."/config.dir.php";
+
+/*
+数据表
+*/
+#表设置,此行不能更改
+require_once __DIR__."/config.table.php";
+
+
+?>

+ 62 - 0
deploy/roles/mint/templates/env-v2.j2

@@ -0,0 +1,62 @@
+BASE_DIR="{{ app_deploy_target }}/.env.global"
+CACHE_DIR="${BASE_DIR}/cache"
+TMP_DIR="${BASE_DIR}/tmp"
+
+APP_NAME=wikipali
+APP_ENV=production
+APP_KEY="{{ app_laravel_key }}"
+APP_DEBUG=false
+APP_URL="https://{{ inventory_hostname }}"
+
+LOG_CHANNEL=stack
+LOG_DEPRECATIONS_CHANNEL=null
+LOG_LEVEL=info
+
+DB_CONNECTION=pgsql
+DB_HOST={{ app_postgresql_host }}
+DB_PORT={{ app_postgresql_port }}
+DB_DATABASE={{ app_postgresql_name }}
+DB_USERNAME={{ app_postgresql_user }}
+DB_PASSWORD="{{ app_postgresql_password }}"
+
+BROADCAST_DRIVER=log
+CACHE_DRIVER=redis
+FILESYSTEM_DRIVER=local
+QUEUE_CONNECTION=sync
+SESSION_DRIVER=file
+SESSION_LIFETIME=120
+
+MEMCACHED_HOST=127.0.0.1
+
+REDIS_HOST={{ app_redis_host }}
+REDIS_PASSWORD=null
+REDIS_PORT=6379
+REDIS_NAMESPACE="{{ app_redis_namespace }}"
+
+MAIL_MAILER=smtp
+MAIL_HOST=smtp.gmail.com
+MAIL_PORT=465
+MAIL_USERNAME={{ app_smtp_username }}
+MAIL_PASSWORD="{{ app_smtp_password }}"
+MAIL_ENCRYPTION=ssl
+MAIL_FROM_ADDRESS={{ app_smtp_username }}
+MAIL_FROM_NAME="webmaster"
+
+AWS_ACCESS_KEY_ID=
+AWS_SECRET_ACCESS_KEY=
+AWS_DEFAULT_REGION=us-east-1
+AWS_BUCKET=
+AWS_USE_PATH_STYLE_ENDPOINT=false
+
+PUSHER_APP_ID=
+PUSHER_APP_KEY=
+PUSHER_APP_SECRET=
+PUSHER_APP_CLUSTER=mt1
+
+MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
+MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
+
+ASSETS_SERVER="https://assets-{{ app_cluster_domain }}"
+RPC_SERVER="https://{{ app_rpc_host }}"
+SNOWFLAKE_DATA_CENTER_ID=1
+SNOWFLAKE_WORKER_ID=1

+ 31 - 0
deploy/roles/os/tasks/main.yml

@@ -0,0 +1,31 @@
+- import_tasks: sshd.yml
+- import_tasks: ulimits.yml
+
+- name: Reset root password
+  become: true
+  shell: echo "root:$(pwgen 32 1)" | chpasswd
+
+- name: Reset {{ ansible_user }} password
+  become: true
+  shell: echo "{{ ansible_user }}:$(pwgen 32 1)" | chpasswd
+  when: ansible_user != 'root'
+
+- name: Set timezone
+  become: true
+  shell: timedatectl set-timezone UTC
+
+- name: Setup journald storage
+  become: true
+  lineinfile:
+    path: /etc/systemd/journald.conf
+    regexp: "^#Storage="
+    line: Storage=persistent
+
+# https://www.linode.com/docs/quick-answers/linux/how-to-use-journalctl/
+- name: Setup journald storage keep-free
+  become: true
+  lineinfile:
+    path: /etc/systemd/journald.conf
+    state: present
+    regexp: "^#SystemKeepFree="
+    line: SystemKeepFree=6%

+ 22 - 0
deploy/roles/os/tasks/sshd.yml

@@ -0,0 +1,22 @@
+- name: Backup sshd_config
+  become: true
+  copy:
+    src: /etc/ssh/sshd_config
+    dest: "{{ app_backup }}/etc_sshd_config"
+    remote_src: yes
+    backup: yes
+
+- name: Disable dns for sshd
+  become: true
+  lineinfile:
+    path: /etc/ssh/sshd_config
+    regexp: '^UseDNS '
+    line: UseDNS no
+
+- name: Disable GSS api auth for sshd
+  become: true
+  lineinfile:
+    path: /etc/ssh/sshd_config
+    regexp: '^GSSAPIAuthentication '
+    line: GSSAPIAuthentication no
+

+ 80 - 0
deploy/roles/os/tasks/ulimits.yml

@@ -0,0 +1,80 @@
+- name: Backup system.conf
+  become: true
+  copy:
+    src: /etc/systemd/system.conf
+    dest: "{{ app_backup }}/etc_systemd_system"
+    remote_src: yes
+    backup: yes
+
+- name: Setup nofile for system
+  become: true
+  lineinfile:
+    path: /etc/systemd/system.conf
+    regexp: "^DefaultLimitNOFILE="
+    line: DefaultLimitNOFILE=2097152
+
+- name: Setup nproc for system
+  become: true
+  lineinfile:
+    path: /etc/systemd/system.conf
+    regexp: "^DefaultLimitNPROC"
+    line: DefaultLimitNPROC=524288
+
+- name: Backup user.conf
+  become: true
+  copy:
+    src: /etc/systemd/user.conf
+    dest: "{{ app_backup }}/etc_systemd_user.conf"
+    remote_src: yes
+    backup: yes
+
+- name: Setup nofile for user
+  become: true
+  lineinfile:
+    path: /etc/systemd/user.conf
+    regexp: "^DefaultLimitNOFILE="
+    line: DefaultLimitNOFILE=1048576
+
+- name: Setup nproc for user
+  become: true
+  lineinfile:
+    path: /etc/systemd/user.conf
+    regexp: "^DefaultLimitNPROC"
+    line: DefaultLimitNPROC=262144
+
+- name: Backup limits.conf
+  become: true
+  copy:
+    src: /etc/security/limits.conf
+    dest: "{{ app_backup }}/etc_security_limits.conf"
+    remote_src: yes
+    backup: yes
+
+- name: Set user level ppen file limits for root
+  become: true
+  lineinfile:
+    path: /etc/security/limits.conf
+    line: root        soft nofile 10240
+
+- name: Set user level open file limits for {{ ansible_user }}
+  become: true
+  lineinfile:
+    path: /etc/security/limits.conf
+    line: "{{ ansible_user }}        soft nofile 10240"
+
+# https://docs.oracle.com/en/database/oracle/oracle-database/12.2/ladbi/changing-kernel-parameter-values.html#GUID-FB0CC366-61C9-4AA2-9BE7-233EB6810A31
+- name: Setup file max
+  become: true
+  lineinfile:
+    path: "/etc/sysctl.d/100-fs.conf"
+    state: present
+    line: fs.file-max = 6815744
+    create: true
+
+- name: Setup file max
+  become: true
+  lineinfile:
+    path: "/etc/sysctl.d/100-fs.conf"
+    state: present
+    line: fs.inotify.max_user_watches = 512000
+    create: true

+ 52 - 0
deploy/roles/php/tasks/main.yml

@@ -0,0 +1,52 @@
+- name: Add php repository
+  become: true
+  ansible.builtin.apt_repository:
+    repo: ppa:ondrej/php
+
+- name: Install php packages
+  become: true
+  apt:
+    pkg:
+      - php{{ app_php_version }}-cli
+      - php{{ app_php_version }}-fpm
+      - php{{ app_php_version }}-xml
+      - php{{ app_php_version }}-imap
+      - php{{ app_php_version }}-intl
+      - php{{ app_php_version }}-mbstring
+      - php{{ app_php_version }}-bcmath
+      - php{{ app_php_version }}-bz2
+      - php{{ app_php_version }}-zip
+      - php{{ app_php_version }}-curl
+      - php{{ app_php_version }}-gd
+      - php{{ app_php_version }}-imagick
+      - php{{ app_php_version }}-pgsql
+      - php{{ app_php_version }}-mysql
+      - php{{ app_php_version }}-sqlite3
+      - php{{ app_php_version }}-redis
+      - php{{ app_php_version }}-amqp
+
+- name: Creates composer install directory
+  file:
+    path: "{{ ansible_env.HOME }}/.local/bin"
+    state: directory
+
+# https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos
+- name: Download composer
+  get_url:
+    url: https://getcomposer.org/download/latest-stable/composer.phar
+    dest: "{{ ansible_env.HOME }}/.local/bin/composer"
+    mode: 0755
+
+- name: Restart php-fpm
+  become: true
+  ansible.builtin.systemd:
+    state: restarted
+    daemon_reload: yes
+    name: "php{{ app_php_version }}-fpm"
+
+- name: Restart nginx
+  become: true
+  ansible.builtin.systemd:
+    state: restarted
+    daemon_reload: yes
+    name: nginx

+ 6 - 0
deploy/roles/ping/tasks/main.yml

@@ -0,0 +1,6 @@
+- name: Test ssh connection
+  ping:
+
+- name: Show facts available on the system
+  ansible.builtin.debug:
+    var: ansible_facts

+ 15 - 0
deploy/roles/ubuntu/tasks/armbian.yml

@@ -0,0 +1,15 @@
+- name: backup /boot/armbianEnv.txt
+  become: true
+  copy:
+    src: /boot/armbianEnv.txt
+    dest: "{{ app_backup }}/boot_armbianEnv_txt"
+    remote_src: yes
+    backup: yes
+  
+- name: enable uart for armbian
+  become: true
+  lineinfile:
+    path: /boot/armbianEnv.txt
+    regexp: '^overlays='
+    line: overlays=usbhost2 usbhost3 uart1 uart2 analog-codec
+

+ 14 - 0
deploy/roles/ubuntu/tasks/clean.yml

@@ -0,0 +1,14 @@
+- name: Remove useless packages from the cache
+  become: true
+  apt:
+    autoclean: yes
+
+- name: Remove dependencies that are no longer required
+  become: true
+  apt:
+    autoremove: yes
+
+- name: Force systemd to reread configs
+  become: true
+  systemd:
+    daemon_reload: yes

+ 60 - 0
deploy/roles/ubuntu/tasks/friendly-core.yml

@@ -0,0 +1,60 @@
+
+- name: backup serial-getty@ttyAMA0.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf
+    dest: "{{ app_backup }}/ttyAMA0_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for ttyAMA0
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '
+
+- name: backup getty@tty1.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/getty@tty1.service.d/autologin.conf
+    dest: "{{ app_backup }}/tty1_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for tty1
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/getty@tty1.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '
+
+- name: backup serial-getty@ttyS0.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
+    dest: "{{ app_backup }}/ttyS0_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for ttyS0
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '
+
+- name: backup serial-getty@ttySAC0.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/serial-getty@ttySAC0.service.d/autologin.conf
+    dest: "{{ app_backup }}/ttySAC0_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for ttySAC0
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/serial-getty@ttySAC0.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '

+ 14 - 0
deploy/roles/ubuntu/tasks/init.yml

@@ -0,0 +1,14 @@
+- name: create downloads folder
+  become: true
+  ansible.builtin.file:
+    path: "{{ app_downloads }}"
+    state: directory
+    owner: "{{ ansible_user }}"
+
+- name: create backup folder
+  become: true
+  ansible.builtin.file:
+    path: "{{ app_backup }}"
+    state: directory
+    owner: "{{ ansible_user }}"
+

+ 38 - 0
deploy/roles/ubuntu/tasks/locales.yml

@@ -0,0 +1,38 @@
+- name: Backup locale.gen
+  become: true
+  copy:
+    src: /etc/locale.gen
+    dest: "{{ app_backup }}/etc_locale.gen"
+    remote_src: yes
+    backup: yes
+
+- name: Enable en-US locale
+  become: true
+  lineinfile:
+    path: /etc/locale.gen
+    state: present
+    line: en_US.UTF-8 UTF-8
+
+
+- name: Enable zh-CN locale
+  become: true
+  lineinfile:
+    path: /etc/locale.gen
+    state: present
+    line: zh_CN.UTF-8 UTF-8
+
+- name: Enable zh-TW locale
+  become: true
+  lineinfile:
+    path: /etc/locale.gen
+    state: present
+    line: zh_TW.UTF-8 UTF-8
+
+
+- name: Generate locales
+  become: true
+  shell: locale-gen
+
+- name: Use en_US as default locale
+  become: true
+  shell: update-locale LANG=en_US.UTF-8

+ 196 - 0
deploy/roles/ubuntu/tasks/main.yml

@@ -0,0 +1,196 @@
+# - name: Remove postfix at first
+#   become: true
+#   apt:
+#     name: postfix
+#     state: absent
+#     purge: yes
+
+# - name: Backup /etc/apt/sources.list.d
+#   become: true
+#   copy:
+#     src: /etc/apt/sources.list.d
+#     dest: "{{ app_backup }}/etc_apt_sources_list_d"
+#     remote_src: yes
+#     backup: yes
+
+# - name: Delete /etc/apt/sources.list.d
+#   become: true
+#   file:
+#     state: absent
+#     path: /etc/apt/sources.list.d
+
+- import_tasks: init.yml
+
+# https://github.com/nodesource/distributions#deb
+# - name: Download nodejs-ppa installer
+#   get_url:
+#     url: https://deb.nodesource.com/setup_lts.x
+#     dest: "{{ app_downloads }}/setup_node_lts.sh"
+#     mode: '0755'
+
+# - name: Install nodejs ppa
+#   become: true
+#   ansible.builtin.shell: "{{ app_downloads }}/setup_node_lts.sh"
+
+
+- name: add PPA for Ubuntu Toolchain
+  become: true
+  ansible.builtin.apt_repository:
+    repo: ppa:ubuntu-toolchain-r/test
+  when: ansible_distribution == 'Ubuntu'
+
+- name: Update system
+  become: true
+  apt:
+    upgrade: yes
+    update_cache: yes
+    cache_valid_time: 3600
+
+- name: Install dependicy packages
+  become: true
+  apt:
+    pkg:
+      - apt-transport-https
+      - software-properties-common
+      - gnupg
+      - openssh-server
+      - openssh-client
+      - sshpass
+      - wpasupplicant
+      - rsync
+      - at
+      - sysstat
+      - libtool
+      - ethtool
+      - dnsutils
+      - dnsmasq
+      - uuid-runtime
+      - lshw
+      - tcpdump
+      - lm-sensors
+      - hddtemp
+      - dmidecode
+      - net-tools
+      - iputils-arping
+      - iputils-ping
+      - telnet
+      - vim
+      - git
+      - pwgen
+      - locales
+      - ntpdate
+      - imagemagick
+      - mpg123
+      - ffmpeg
+      - sqlite3
+      - tree
+      - alsa-utils
+      - pulseaudio
+      - zsh
+      - wget
+      - curl
+      - zip
+      - unzip
+      - nginx
+      - libnginx-mod-http-upstream-fair
+      - certbot
+      - python3-certbot-nginx
+      - openvpn
+      - snmpd
+      - mutt
+      - systemd-cron
+      - screen
+      - tmux
+      - hugo
+      - nodejs
+      - python3
+      - python3-pip
+      - python3-distutils
+      - python3-dev
+      - libssl-dev
+      - libpq-dev
+      - libmysqlclient-dev
+
+- name: Install dependicy packages(>bionic)
+  become: true
+  apt:
+    pkg:
+      - systemd-timesyncd
+      - yarnpkg
+  # ansible_facts['distribution'] == "Ubuntu"
+  when: ansible_facts['distribution_major_version'] | int >= 20
+
+
+
+- import_tasks: locales.yml
+
+- name: Set default editor to vim
+  become: true
+  shell: update-alternatives --set editor /usr/bin/vim.basic
+
+- name: Set timezone
+  become: true
+  shell: timedatectl set-timezone UTC
+
+- name: Set git rebase mode
+  become: true
+  shell: git config --global pull.rebase false
+
+- import_tasks: zsh.yml
+
+# ---------------------------------------------------
+
+- name: check if friendlyelec
+  ansible.builtin.stat:
+    path: /etc/friendlyelec-release
+  register: app_os_friendlyelec
+
+- import_tasks: friendly-core.yml
+  when: app_os_friendlyelec.stat.islnk is defined and app_os_friendlyelec.stat.isreg
+
+- name: check if armbian
+  ansible.builtin.stat:
+    path: /etc/armbian-release
+  register: app_os_armbian
+
+- import_tasks: armbian.yml
+  when: app_os_armbian.stat.islnk is defined and app_os_armbian.stat.isreg
+
+- import_tasks: raspbian.yml
+  when: ansible_distribution == 'Raspbian'
+
+- import_tasks: pi.yml
+  when: ansible_distribution == 'Raspbian' or (app_os_armbian.stat.islnk is defined and app_os_armbian.stat.isreg) or (app_os_friendlyelec.stat.islnk is defined and app_os_friendlyelec.stat.isreg)
+
+# ---------------------------------------------------
+
+- name: enable nginx service
+  become: true
+  ansible.builtin.systemd:
+    name: nginx
+    enabled: yes
+    masked: no
+
+- name: enable cron service
+  become: true
+  ansible.builtin.systemd:
+    name: cron
+    enabled: yes
+    masked: no
+
+- name: enable ssh service
+  become: true
+  ansible.builtin.systemd:
+    name: ssh
+    enabled: yes
+    masked: no
+
+- name: enable systemd-timesyncd service
+  become: true
+  ansible.builtin.systemd:
+    name: systemd-timesyncd
+    enabled: yes
+    masked: no
+
+
+- import_tasks: clean.yml

+ 52 - 0
deploy/roles/ubuntu/tasks/raspbian.yml

@@ -0,0 +1,52 @@
+# https://www.raspberrypi.org/documentation/configuration/uart.md
+
+- name: backup /boot/config.txt
+  become: true
+  ansible.builtin.copy:
+    src: /boot/config.txt
+    dest: "{{ app_backup }}/boot_config_txt"
+    remote_src: yes
+    backup: yes
+
+- name: enable uart
+  become: true
+  lineinfile:
+    path: /boot/config.txt
+    regexp: '^enable_uart='
+    line: enable_uart=1
+
+- name: disable bluetooth
+  become: true
+  lineinfile:
+    path: /boot/config.txt
+    regexp: '^dtoverlay='
+    line: dtoverlay=disable-bt
+
+- name: hidden splash message
+  become: true
+  lineinfile:
+    path: /boot/config.txt
+    regexp: '^disable_splash='
+    line: disable_splash=1 
+
+- name: backup /boot/cmdline.txt
+  become: true
+  ansible.builtin.copy:
+    src: /boot/cmdline.txt
+    dest: "{{ app_backup }}/boot_cmdline_txt"
+    remote_src: yes
+    backup: yes
+
+- name: disable debug port & logo
+  become: true
+  ansible.builtin.replace:
+    path: /boot/cmdline.txt
+    regexp: 'console=serial0,115200'
+    replace: 'loglevel=3 logo.nologo'
+
+- name: disable hciuart service
+  become: true
+  ansible.builtin.systemd:
+    name: hciuart
+    enabled: no
+    masked: yes

+ 37 - 0
deploy/roles/ubuntu/tasks/zsh.yml

@@ -0,0 +1,37 @@
+- name: Clone oh-my-zsh
+  git:
+    repo: https://github.com/robbyrussell/oh-my-zsh.git
+    dest: "{{ansible_env.HOME}}/.oh-my-zsh"
+
+# - name: Extract ohmyzsh
+#   unarchive:
+#     src: ohmyzsh-master.zip
+#     dest: "{{ansible_env.HOME}}/"
+
+# - name: Rename ohmyzsh
+#   command: mv ohmyzsh-master .oh-my-zsh
+#   args:
+#     chdir: "{{ansible_env.HOME}}"
+#     creates: .oh-my-zsh
+
+- name: Setup .zshrc
+  copy:
+    src: "{{ansible_env.HOME}}/.oh-my-zsh/templates/zshrc.zsh-template"
+    dest: "{{ansible_env.HOME}}/.zshrc"
+    remote_src: true
+    mode: 0600
+
+- name: Enable $HOME/.local
+  ansible.builtin.lineinfile:
+    path: "{{ansible_env.HOME}}/.zshrc"
+    line: 'export PATH=$HOME/.local/bin:$PATH'
+
+
+- name: Setup EDITOR
+  ansible.builtin.lineinfile:
+    path: "{{ansible_env.HOME}}/.zshrc"
+    line: 'export EDITOR=vim'
+
+- name: Use zsh
+  become: true
+  shell: chsh -s /bin/zsh {{ansible_user}}

+ 44 - 0
deploy/scripts/assets.sh

@@ -0,0 +1,44 @@
+#!/bin/bash
+
+set -e
+
+# rclone copy --drive-shared-with-me $1:assets assets
+
+export WORKSPACE=$PWD
+
+function build_book(){
+    local target=$WORKSPACE/tmp/$1/$2
+    local dist=$WORKSPACE/roles/mint-assets/files/public/$1/$2
+    if [ ! -d $target ]
+    then
+        git clone -b $2 "https://github.com/iapt-platform/$1.git" $target
+    fi
+    cd $target
+    git pull
+    if [ -d $dist ]
+    then
+        rm -r $dist
+    fi
+    mkdir -p $dist
+    $HOME/.local/bin/mdbook build --dest-dir $dist
+}
+
+declare -a languages=(
+    "zh-Hans"
+)
+
+declare -a books=(
+    "pali-handbook"
+    "help"
+)
+
+for b in "${books[@]}"
+do
+    for l in "${languages[@]}"
+    do
+        build_book $b $l
+    done
+done
+
+echo 'done.'
+exit 0

+ 48 - 0
deploy/scripts/handbooks.sh

@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -e
+
+
+if [ $# -ne 1 ]
+then
+	echo "Usage: $0 FOLDER"
+	exit 1
+fi
+
+
+function build_book(){
+    local target=$HOME/tmp/$2/$3
+    local dist=$1/public/$2/$3
+    if [ ! -d $target ]
+    then
+        git clone -b $3 "https://github.com/iapt-platform/$2.git" $target
+    fi
+    cd $target
+    git pull
+    if [ -d $dist ]
+    then
+        rm -r $dist
+    fi
+    mkdir -p $dist
+    $HOME/.local/bin/mdbook build --dest-dir $dist
+    echo "done($dist)."
+}
+
+declare -a languages=(
+    "zh-Hans"
+)
+
+declare -a books=(
+    "pali-handbook"
+    "help"
+)
+
+for b in "${books[@]}"
+do
+    for l in "${languages[@]}"
+    do
+        build_book $1 $b $l
+    done
+done
+
+exit 0

+ 79 - 0
deploy/scripts/laravel-react.sh

@@ -0,0 +1,79 @@
+#!/bin/bash
+
+set -e
+
+
+if [ "$#" -ne 1 ]
+then
+    echo "USAGE: $0 DOMAIN"
+    exit 1
+fi
+
+echo "check $1.conf"
+if [ ! -d /var/www/$1/logs ]
+then
+  mkdir -p /var/www/$1/logs
+  chown -R www-data:www-data /var/www/$1/logs
+fi
+
+if [ ! -f /etc/nginx/sites-enabled/$1.conf ]
+then
+    # https://laravel.com/docs/10.x/deployment
+    cat > /etc/nginx/sites-enabled/$1.conf <<EOF
+server {
+
+  server_name $1;
+  root /var/www/$1/htdocs/public;
+  access_log /var/www/$1/logs/access.log;
+  error_log  /var/www/$1/logs/error.log;
+  
+  add_header X-Frame-Options "SAMEORIGIN";
+  add_header X-Content-Type-Options "nosniff";
+
+  index index.php;
+  charset utf-8;
+
+  gzip on;
+  gzip_comp_level 9;
+  gzip_min_length 1k;
+  gzip_types text/plain text/css application/xml application/javascript;
+  gzip_vary on;
+  client_max_body_size 128M;
+  
+
+  location /my/ {
+    alias /var/www/$1/current/dashboard/;
+    try_files \$uri \$uri/ /my/index.html;
+    
+    location ~* \\.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)\$ {
+      access_log off;
+      expires max;
+    }
+  }
+  
+  location / {
+    try_files \$uri \$uri/ /index.php?\$query_string;
+  }
+
+  location = /favicon.ico { access_log off; log_not_found off; }
+  location = /robots.txt  { access_log off; log_not_found off; }
+  error_page 404 /index.php;
+
+  location ~ \.php\$ {
+    fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
+    fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name;
+    include fastcgi_params;
+  }
+ 
+  location ~ /\.(?!well-known).* {
+      deny all;
+  }
+
+}
+EOF
+
+    chmod 644 /etc/nginx/sites-enabled/$1.conf
+fi
+
+echo "done($1)."
+exit 0

+ 13 - 0
deploy/scripts/sim_sent.sh

@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+export SIM=$(pgrep -f "php sim_sent")
+
+echo "find pid $SIM"
+renice +19 $SIM
+ionice -c 2 -n 7 -p $SIM
+
+echo "done."
+
+exit 0

+ 20 - 0
deploy/scripts/sqlite_fix.sh

@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -e
+if [ $# -ne 1 ]
+then
+	echo "Usage: $0 DB"
+	exit 1
+fi
+
+if [ ! -f $1 ]
+then
+	echo "$1 not exists"
+	exit 1
+fi
+
+echo '.dump'|sqlite3 $1|sqlite3 $1_repaired
+mv -v $1 $1_corrupt
+mv -v $1_repaired $1
+
+exit 0

+ 1 - 0
deploy/staging/.gitignore

@@ -0,0 +1 @@
+/.ssh/

+ 12 - 0
deploy/staging/hosts

@@ -0,0 +1,12 @@
+[www]
+
+
+[all:vars]
+; openssl rand -base64 32
+app_secret_key="4i3WKUvKtSGl59htK7XjUNsjalhkG5s7RJCmZruT2m4="
+; php artisan key:generate --show
+app_laravel_key="base64:IQD4vkmAN1oEsc8rVu1nRadQWPUX/LH/jaSbyFbmf/w="
+app_postgresql_host="db-hk-1.wikipali.org"
+app_postgresql_port=5433
+app_postgresql_password=change-me
+app_redis_host="ch-hk-1.wikipali.org"