title | tags |
---|---|
CHSH AI2 Server Note |
AI2 |
https://ai2.linwebs.tw/
hackmd: https://hackmd.io/@linwebstw/BklO1UBEL
[TOC]
以下範例目錄以 /data-disk/ai2-server/appinventor-sources-20210223/
為例
Domain 以 ai2.linwebs.tw 為例
指定使用者名稱登入網址
https://ai2.linwebs.tw/login/google
- 查看 remote
(local)$ git remote -v
- 新增 AI2 官方 source
(local)$ git remote add mit-cml https://github.com/mit-cml/appinventor-sources.git
- 取得更新
(local)$ git fetch mit-cml
- commit 更新
(local)$ git commit -am "commit message"
- push 回 GitHub
(local)$ git push
- SSH 進入 Server
(local)$ ssh hostname -l username
- 關閉 ai2 服務
(server)$ sudo screen -r ai2-sys-2021 [Ctrl + C] [Ctrl + A] [D] # 退出
- 關閉 ai2 打包服務
(server)$ sudo screen -r ai2-pack-2021 [Ctrl + C] [Ctrl + A] [D] # 退出
- ※ Server 先備份(非常重要:warning: )
(server)$ cd /data-disk/ai2-server/ (server)$ cp appinventor-sources-20210223 appinventor-sources-backup -R
- 存檔備份
(server)$ cd /data-disk/ai2-server/ (server)$ cp appinventor-sources-20210223/appinventor/appengine/build/war/WEB-INF/appengine-generated AllSource/Source-appinventor-sources-20210223
- Server pull 回更新
(server)$ cd /data-disk/ai2-server/appinventor-sources-20210223 (server)$ git pull
- ant 重新建置
(server)$ cd /data-disk/ai2-server/appinventor-sources-20210223/appinventor (server)$ ant clean all # 請注意,此動作會清除使用者存檔
- 重啟 ai2 服務
(server)$ sudo screen -r ai2-sys-2021 # ai2 server (server)$ /opt/google-cloud-sdk/bin/java_dev_appserver.sh -p 8888 -a 0.0.0.0 /data-disk/ai2-server/appinventor-sources-20210223/ainventor/appengine/build/war/
- 重啟 ai2 打包服務
(server)$ sudo screen -r ai2-pack-2021 (server)$ cd /data-disk/ai2-server/appinventor-sources-20210223/appinventor/buildserver (server)$ ant RunLocalBuildServer
- Reference:
/data-disk/ai2-server/appinventor-sources-20210223/appinventor/appengine/build/war
需新增以下網址轉址至login.jsp,以免從AI2 Server登出後,看到原生登入畫面
/data-disk/ai2-server/appinventor-sources-20210223/appinventor/appengine/build/war/login.jsp
<%
response.sendRedirect("https://ai2.chsh.chc.edu.tw");
%>
Logo更改需更改以下6個檔案
Logo原始檔位址: https://ai2.chsh.chc.edu.tw/images/codi_long.png
https://ai2.chsh.chc.edu.tw/images/logo2.png
小圖 (AI2):
小圖(英文) (AI2):
大圖 (reference):
修改請參照下方 AI2系統檔案存放位置 指示進行修改
BuildServer 運行狀況 https://ai2.linwebs.tw/status/buildserver/health
BuildServer 即時狀況 https://ai2.linwebs.tw/status/buildserver/vars
網址: https://ai2.linwebs.tw/db/
自動啟動TinyWebDB腳本位置
$ sudo vim /etc/rc.local
用root權限新增一個名稱為[ai2db]的 screen,並執行指令
自動啟動彰中AI2 Server腳本位置
$ sudo vim /etc/rc.local
用root權限新增
一個名稱為[ai2sys]的screen,執行AI2 Server
一個名稱為[ai2pack]的screen,執行LocalBuildServer
另外一個名稱為[ai2db]的 screen,是執行TinyWebDB (非必要)
screen -dmS ai2-sys sh
screen -S ai2-sys -p 0 -X stuff "/data-disk/ai2-server/appengine-java-sdk-1.9.77/bin/dev_appserver.sh -p 8888 -a 0.0.0.0 /data-disk/ai2-server/appinventor-sources-20210223/appinventor/appengine/build/war/
"
screen -dmS ai2-pack sh
screen -S ai2-pack -p 0 -X stuff "cd /data-disk/ai2-server/appinventor-sources-20210223/appinventor/buildserver/
sleep 30
ant RunLocalBuildServer address=ai2.chsh.chc.edu.tw
"
screen -dmS ai2-db sh
screen -S ai2-db -p 0 -X stuff "python2.7 /data-disk/ai2db/appengine_py/dev_appserver.py --port 9980 --host 0.0.0.0 /data-disk/ai2db/appinventordb/
"
設定檔位置
/etc/httpd/conf.d/vhost-2-ai2-linwebs-tw.conf
# ai2.linwebs.tw
<VirtualHost *:80>
ServerName ai2.linwebs.tw
ServerAdmin admin@linwebs.tw
Redirect permanent / https://ai2.linwebs.tw/
# ProxyRequests Off
# ProxyPreserveHost On
ErrorLog logs/ai2-linwebs-error_log
CustomLog logs/ai2-linwebs-access_log common
</VirtualHost>
# ai2.linwebs.tw SSL
<VirtualHost *:443>
ServerName ai2.linwebs.tw
ServerAdmin admin@linwebs.tw
ProxyRequests Off
ProxyPreserveHost On
<Location /db/>
ProxyPass http://localhost:9980/
ProxyPassReverse http://localhost:9980/
</Location>
<Location /status/>
ProxyPass http://localhost:9990/
ProxyPassReverse http://localhost:9990/
</Location>
<Location />
ProxyPass http://localhost:8888/
ProxyPassReverse http://localhost:8888/
</Location>
ErrorLog logs/ai2-linwebs-ssl-error_log
CustomLog logs/ai2-linwebs common
SSLEngine on
SSLProxyEngine on
SSLProtocol ALL -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLCertificateFile /etc/letsencrypt/live/ai2.linwebs.tw/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ai2.linwebs.tw/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/ai2.linwebs.tw/chain.pem
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
</VirtualHost>
SSL 自動更新腳本
# sudo crontab -e
每周一凌晨3:10自動更新SSL憑證
10 3 * * 1 /opt/letsencrypt/letsencrypt-auto certonly --apache --renew-by-default -d ai2.linwebs.tw && service httpd restart
檔案存放對應路徑:
Web Path:
https://ai2.linwebs.tw/static/images/codi_long.png
Document Root:
/data-disk/ai2-server/appinventor-sources-20210223/appinventor/appengine/build/war/static/images
切換至ai2 server目錄
$ cd /data-disk/ai2-server
取得source檔:
$ git clone https://github.com/mit-cml/appinventor-sources.git
更改source檔名稱: (yyyymmdd填入年-月-日)
$ mv appinventor-sources appinventor-sources-yyyymmdd
取得最新google app engine java 網址
$ wget https://cloud.google.com/appengine/docs/standard/java/download
解壓縮google app engine (xx填入版本號) https://cloud.google.com/appengine/docs/standard/java/download
$ unzip appengine-java-sdk-1.9.xx.zip
更改兩目錄權限為777
$ chmod 777 appengine-java-sdk-1.9.xx appinventor-sources-yyyymmdd -R
進入ai2 source目錄
$ cd appinventor-sources-yyyymmdd/
submodule update
$ git submodule update --init
進入ai2 目錄
$ cd appinventor
編譯ai2 source檔
$ ant
複製先前版本使用者資料
$ cp /data-disk/ai2-server/appinventor-sources-20180124/appinventor/appengine/build/war/WEB-INF/appengine-generated /data-disk/ai2-server/appinventor-sources-yyyymmdd/appinventor/appengine/build/war/WEB-INF/appengine-generated -r
:::warning :warning: 此指令已經不須再執行了,執行會使原本的使用者都無法登入 :::
AI2 系統須有 auth key 才可運作 預設是存在執行的使用者根目錄,所以使用 sudo 執行時是放在以下資料夾內
/root/.appinventor
執行指令
$ cd /data-disk/ai2-server/appinventor-sources-yyyymmdd/appinventor/
$ ant MakeAuthKey
以下內容撰寫中,請暫時不要使用
註: 以下 $AI2_SOURCE_PATH
的值為 /data-disk/ai2-server/appinventor-sources-yyyymmdd
- 所有語言
$AI2_SOURCE_PATH/appinventor/appengine/src/com/google/appinventor/client/languages.json
- 繁「体」中文 => 繁體中文
- 繁體中文翻譯
$AI2_SOURCE_PATH/appinventor/appengine/src/com/google/appinventor/client/OdeMessages_zh_TW.properties
- web 設定檔
$AI2_SOURCE_PATH/appinventor//appengine/war/WEB-INF/appengine-web.xml
- 登入參數
- 靜態網址... 等
/opt/google-cloud-sdk/bin/java_dev_appserver.sh
- logo.png
- /appinventor/appengine/war/static/images/
- codi_long.png
- /appinventor/appengine/war/static/images/codi_long.png
- /appinventor/docs/markdown/reference/blocks/images/codi_long.png
- /appinventor/docs/markdown/reference/components/images/codi_long.png
- /appinventor/docs/html/reference/blocks/images/codi_long.png
- /appinventor/docs/html/reference/components/images/codi_long.png
- 圖片 /appinventor/appengine/src/com/google/appinventor/images/
- 語言 /appinventor/appengine/src/com/google/appinventor/client/
00 4 1 4,8,12 * sh /data-disk/ai2-server/update/update.sh > /data-disk/ai2-server/update/update.log
solution: https://community.appinventor.mit.edu/t/aistarter-update-mit-ai2-companion2-to-2-58au/7587
Error from Companion: java.lang.RuntimeException: invalid syntax in eval form: :9:1: caught exception in inliner for # - java.lang.RuntimeException: no such class: com.google.appinventor.components.runtime.com.google.appinventor.components.runtime.Label gnu.bytecode.ObjectType.getReflectClass(ObjectType.java:148) gnu.bytecode.ClassType.getModifiers(ClassType.java:103) gnu.bytecode.ClassType.isInterface(ClassType.java:471) gnu.expr.InlineCalls.checkType(InlineCalls.java:56) gnu.expr.InlineCalls.visit(InlineCalls.java:49) gnu.expr.InlineCalls.visitSetExpValue(InlineCalls.java:363) gnu.expr.InlineCalls.visitSetExpValue(InlineCalls.java:28) gnu.expr.ExpVisitor.visitSetExp(ExpVisitor.java:114) gnu.expr.InlineCalls.visitSetExp(InlineCalls.java:369) gnu.expr.InlineCalls.visitSetExp(InlineCalls.java:28) gnu.expr.SetExp.visit(SetExp.java:406) gnu.expr.ExpVisitor.visit(ExpVisitor.java:55) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visitBeginExp(InlineCalls.java:272) gnu.expr.InlineCalls.visitBeginExp(InlineCalls.java:28) gnu.expr.BeginExp.visit(BeginExp.java:156) gnu.expr.ExpVisitor.visit(ExpVisitor.java:51) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visitBeginExp(InlineCalls.java:272) gnu.expr.InlineCalls.visitBeginExp(InlineCalls.java:28) gnu.expr.BeginExp.visit(BeginExp.java:156) gnu.expr.ExpVisitor.visit(ExpVisitor.java:51) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visitLetExp(InlineCalls.java:317) gnu.expr.InlineCalls.visitLetExp(InlineCalls.java:28) gnu.expr.LetExp.visit(LetExp.java:207) gnu.expr.ExpVisitor.visit(ExpVisitor.java:51) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visit(InlineCalls.java:28) gnu.expr.LambdaExp.visitChildrenOnly(LambdaExp.java:1664) gnu.expr.LambdaExp.visitChildren(LambdaExp.java:1651) gnu.expr.InlineCalls.visitScopeExp(InlineCalls.java:279) gnu.expr.InlineCalls.visitLambdaExp(InlineCalls.java:349) gnu.expr.InlineCalls.visitLambdaExp(InlineCalls.java:28) gnu.expr.LambdaExp.visit(LambdaExp.java:1640) gnu.expr.ExpVisitor.visit(ExpVisitor.java:55) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visit(InlineCalls.java:28) gnu.expr.ExpVisitor.visitAndUpdate(ExpVisitor.java:162) gnu.expr.ExpVisitor.visitExps(ExpVisitor.java:176) gnu.expr.ApplyExp.visitArgs(ApplyExp.java:416) gnu.kawa.reflect.CompileInvoke.validateApplyInvoke(CompileInvoke.java:23) java.lang.reflect.Method.invokeNative(Native Method) java.lang.reflect.Method.invoke(Method.java:521) gnu.expr.InlineCalls.maybeInline(InlineCalls.java:467) gnu.expr.QuoteExp.validateApply(QuoteExp.java:150) gnu.expr.ReferenceExp.validateApply(ReferenceExp.java:191) gnu.kawa.functions.CompilationHelpers.validateApplyToArgs(CompilationHelpers.java:66) java.lang.reflect.Method.invokeNative(Native Method) java.lang.reflect.Method.invoke(Method.java:521) gnu.expr.InlineCalls.maybeInline(InlineCalls.java:467) gnu.expr.QuoteExp.validateApply(QuoteExp.java:150) gnu.expr.ReferenceExp.validateApply(ReferenceExp.java:191) gnu.expr.InlineCalls.visitApplyExp(InlineCalls.java:119) gnu.expr.InlineCalls.visitApplyExp(InlineCalls.java:28) gnu.expr.ApplyExp.visit(ApplyExp.java:411) gnu.expr.ExpVisitor.visit(ExpVisitor.java:55) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.QuoteExp.validateApply(QuoteExp.java:162) gnu.expr.ReferenceExp.validateApply(ReferenceExp.java:191) gnu.kawa.functions.CompilationHelpers.validateApplyToArgs(CompilationHelpers.java:66) java.lang.reflect.Method.invokeNative(Native Method) java.lang.reflect.Method.invoke(Method.java:521) gnu.expr.InlineCalls.maybeInline(InlineCalls.java:467) gnu.expr.QuoteExp.validateApply(QuoteExp.java:150) gnu.expr.ReferenceExp.validateApply(ReferenceExp.java:191) gnu.expr.InlineCalls.visitApplyExp(InlineCalls.java:119) gnu.expr.InlineCalls.visitApplyExp(InlineCalls.java:28) gnu.expr.ApplyExp.visit(ApplyExp.java:411) gnu.expr.ExpVisitor.visit(ExpVisitor.java:51) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visitBeginExp(InlineCalls.java:272) gnu.expr.InlineCalls.visitBeginExp(InlineCalls.java:28) gnu.expr.BeginExp.visit(BeginExp.java:156) gnu.expr.ExpVisitor.visit(ExpVisitor.java:51) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.visit(InlineCalls.java:28) gnu.expr.LambdaExp.visitChildrenOnly(LambdaExp.java:1664) gnu.expr.LambdaExp.visitChildren(LambdaExp.java:1651) gnu.expr.InlineCalls.visitScopeExp(InlineCalls.java:279) gnu.expr.InlineCalls.visitLambdaExp(InlineCalls.java:349) gnu.expr.InlineCalls.visitLambdaExp(InlineCalls.java:28) gnu.expr.ExpVisitor.visitModuleExp(ExpVisitor.java:103) gnu.expr.ModuleExp.visit(ModuleExp.java:482) gnu.expr.ExpVisitor.visit(ExpVisitor.java:51) gnu.expr.InlineCalls.visit(InlineCalls.java:46) gnu.expr.InlineCalls.inlineCalls(InlineCalls.java:33) gnu.expr.Compilation.walkModule(Compilation.java:994) gnu.expr.Compilation.process(Compilation.java:1965) gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:330) gnu.expr.ModuleExp.evalModule1(ModuleExp.java:238) gnu.expr.ModuleExp.evalModule(ModuleExp.java:198) gnu.expr.Language.eval(Language.java:943) gnu.expr.Language.eval(Language.java:883) gnu.expr.Language.eval(Language.java:865) com.google.appinventor.components.runtime.util.AppInvHTTPD.serve(AppInvHTTPD.java:188) com.google.appinventor.components.runtime.util.NanoHTTPD$HTTPSession.run(NanoHTTPD.java:470) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561) java.lang.Thread.run(Thread.java:1096)