From 8e144751356a5137310adbb25295096728793bcc Mon Sep 17 00:00:00 2001 From: philc Date: Sat, 23 Mar 2024 16:52:39 +0100 Subject: [PATCH] setup --- README.md | 28 ++++--- apxtri.js | 119 +++------------------------- setup.js | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 122 deletions(-) create mode 100644 setup.js diff --git a/README.md b/README.md index 4517c31..d9dbab8 100644 --- a/README.md +++ b/README.md @@ -103,14 +103,14 @@ use a sudoer user and execute command line $, for security reason, do not use ap ```plaintext $ sudo apt update $ sudo apt upgrade -$ useradd -s /bin/bash -m -d /home/apxuser -c "apxuser" apxuser -$ passwd apxuser -$ sudo usermod -aG sudo apxuser +$ useradd -s /bin/bash -m -d /home/{apxuser} -c "{apxuser}" {apxuser} +$ passwd {apxuser} +$ sudo usermod -aG sudo {apxuser} $ sudo visudo # add the next line in the file -$ apxuser ALL=(ALL) NOPASSWD: ALL +$ {apxuser} ALL=(ALL) NOPASSWD: ALL # exit and save -$ su apxuser +$ su {apxuser} $ sudo apt install git vim libcap2-bin p7zip-full p7zip-rar curl nginx # Install last nvm** (check website to get latest v0.xx from https://github.com/nvm-sh/nvm) $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash @@ -123,18 +123,19 @@ $ nvm install node $ node --version #to check $ npm install --global yarn $ yarn --version -$ mkdir ~/apxtowns | mkdir ~/apxtowns/town-nation +# Find a non existing town to join to an existing nation see https://apxtri.crabedance.com +$ mkdir ~/apxtowns # if it does not exist +$ mkdir ~/apxtowns/{town}-{nation} ################################# # For dev ####################### ################################# -# you only need to clone the apXtri project in ~/apxtowns/town-nation/tribes/adminapi/ -# this allow you to dev foar a tribe api as well as to push features to the maintainers of the apXtri project: -$ curl -L https://wall-ants.fr/cdn/share/apxtriVx.tar && tar -xvzf - -C ~/apxtowns/town-nation/ -$ cd ~/apxtowns/town-nation/tribes/adminapi/ -$ git clone https://gitea.ndda.fr/apxtrib/apxtri.git +$ mkdir ~/apxtowns/{town}-{nation}/adminapi/ +$ cd ~/apxtowns/{town}-{nation}/adminapi/ +$ git clone https://gitea.ndda.fr/apxtri/apxtri.git $ yarn install -$ town=dev nation=ants dns=dev-ants yarn dev # for 1st install to set conf/nginx/adminapi_adminapx.conf with your parameter +# to setup run the 1st time +$ dns=apxtri.ydns.io user=apxuser yarn dev ################################# # For production ############### @@ -150,7 +151,8 @@ $ sudo apt remove certbot $ sudo snap install --classic certbot $ sudo ln -s /snap/bin/certbot /usr/bin/certbot $ curl -L https://wall-ants.ndda.fr/cdn/share/apxtriVx.tar | tar -xf - -C ~/apxtowns/town-nation/ | cd ~/apxtowns/town-nation/tribes/adminapi/apxtri | yarn install -$ town=townname nation=nationname dns=apxtri.ydns.io yarn startapx # for 1st install to set conf/nginx/adminapi_adminapx.conf with your parameter +$ town=townname nation=nationname dns=apxtri.ydns.io yarn startapx # for 1st install to set /etc/nginx/nginx.conf conf/nginx/adminapi_adminapx.conf with your parameter +# FYI: it changes nginx configuration + let's encrypt your dns to get a ssl $ yarn restartapx # if IT IS NOT a first install # open a browser and type https://domain to access to your admin console diff --git a/apxtri.js b/apxtri.js index 25bd8af..5dd2176 100755 --- a/apxtri.js +++ b/apxtri.js @@ -1,6 +1,6 @@ -const { argv } = require("process"); +//const { argv } = require("process"); const fs = require("fs-extra"); -const mustache = require("mustache"); +//const mustache = require("mustache"); const bodyParser = require("body-parser"); const glob = require("glob"); const path = require("path"); @@ -9,130 +9,31 @@ const express = require("express"); const process = require("process"); /******************************************* +SEE README.md to have a quick start +********************************************/ -SEE README.md to have a quick understanding to install a new town - - * @param {args} args key:value example node apxtri nationId:ants townId:devfarm dns:devfarm-ants - * if no parameter from adminapi/www/adminapx/conf/setup_xx.json - * - * Keyword townId = "devfarm" then this is unchain town to dev - * else this is a production town ready to chain to the nationId - * - * @returns listen onto http:/dns (80 and 443) for admin webapp and http://localhost:initconf.api.port - * by setting the nginx parameter - * A folder for town data is created at the same level than apxtri as /townId-nationId/conf.json ... - */ - -const nam = path.resolve("../..").split("/").slice(-1)[0].split("-"); -const town = nam[0]; -const nation = nam[1]; -const setup=()=>{ - const nam = path.resolve("../..").split("/").slice(-1)[0].split("-"); - const town = nam[0]; - const nation = nam[1]; - let setupdone=true - // check nginx exist - if (!fs.existsSync("/etc/nginx/nginx.conf")) { +if (!fs.existsSync("/etc/nginx/nginx.conf")) { setupdone=false; console.log( - "\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available, install then rerun yarn command." - ); - process.exit(); + "\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available, install then rerun yarn command."); } - if (! (param.dns && param.user) ) { - setupdone=false; - console.log("This is a first install you must run next command with a domain name (use town-nation for dev and the linux user that run apXtri) check ping dns answer and su user exist (check README) \n dns=domainname user=linuxuser yarn dev") - } - return setupdone; -} - -const param = {}; -argv.slice(2).forEach((arg) => { - const kv = arg.split(":"); - if (kv.length == 2) { - param[kv[0]] = kv[1]; - } -}); if (!fs.existsSync("../../conf.json")) { - // This is a first install - if (!setup(param)) process.exit(); + console.log("Warning, this is a first install you must run 'node setup.js dns=domainename user=sudoerlinux'") + process.exit(); } -// setup_xx.json is gitignore so at first install we are in dev configuration -/* -let infotown = { - nationId: "ants", - townId: "devfarm", - dns: "devfarm-ants", - comment: - "Auto generate setup from apxtri after node apxtri nationId:value townId:value dns:domaine_to_access", -}; -if (fs.existsSync(`${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`)) { - infotown = fs.readJsonSync( - `${__dirname}/adminapi/www/adminapx/conf/setup_xx.json` - ); -} -if ( - Object.keys(param).length > 0 && - param.nationId && - param.townId && - param.dns -) { - infotown.nationId = param.nationId; - infotown.townId = param.townId; - infotown.dns = param.dns; -} -fs.outputJsonSync( - `${__dirname}/adminapi/www/adminapx/conf/setup_xx.json`, - infotown -); -infotown.dirapi = __dirname; -infotown.dirtown = path.resolve( - `${__dirname}/../${infotown.townId}-${infotown.nationId}` -); -process.env.dirtown = infotown.dirtown; -infotown.dirapxwebapp = path.resolve(`${infotown.dirapi}/..`); //same level as apxtri -if ( - !fs.existsSync(`${infotown.dirtown}/conf.json`) || - !fs.existsSync(`${__dirname}/adminapi/www/nginx_adminapx.conf`) -) { - // Case of new town or request a reset of dns to access adminapx - // genere a minimum conf with nationId, townId, dns, dirapi, dirtown - fs.outputJsonSync(`${infotown.dirtown}/conf.json`, infotown, { space: 2 }); - const Towns = require("./api/models/Towns"); - const rescreate = Towns.create(); - if (rescreate.status != 200) { - console.log("Sorry error "); - process.exit(); - } -} -*/ - - const conf = require(path.resolve(`../../conf.json`)); let doms = conf.dns; // only dns of town during the init process - const currentmod = "apxtri"; const log = conf.api.activelog.includes(currentmod); -// Create and update ./nationchains plutot que cette fonction -// A creuser et voir comment synchro -/*const { updateobjectsfromfreshesttown } = require("./models/Nations.js"); -updateobjectsfromfreshesttown(conf.towns, { - pagans: "alias_all.json", - towns: "townId_all.json", - nations: "nationId_all.json", -}); -*/ -// Run main express process for a /towId-nationId/tribes - let tribelist = {}; if (fs.existsSync(`../../idx/tribeId_all.json`)) { tribelist = fs.readJsonSync(`../../idx/tribeId_all.json`); } let tribeIds = Object.keys(tribelist); -// context is store in tribes/itm/tribename.json ={contexte:{routes:[],models:[{model:,tplstringslg:[]}]} -//routes={url,route} check how to add plugin tribe route later +// context is store in /itm/tribename.json ={contexte:{routes:[],models:[{model:,tplstringslg:[]}]} +// routes={url,route} check how to add plugin tribe route later // keep only the 2 last part (.) of domain name to validate cors with it (generic domain) let routes=[] tribeIds.forEach((t) => { diff --git a/setup.js b/setup.js new file mode 100644 index 0000000..1f0a460 --- /dev/null +++ b/setup.js @@ -0,0 +1,230 @@ +const { argv } = require("process"); +const fs = require("fs-extra"); +const mustache = require("mustache"); +const glob = require("glob"); +const path = require("path"); + +const Setup = {}; + +Setup.dnstown=["apxtri.crabedance.com","apxtri.mooo.com"] + +Setup.nginxconf = ` +user {{user}}; +########################################## +## This file is auto generate by apXtri ## +########################################## +worker_processes auto; +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; +#include /etc/nginx/modules-enabled/*.conf; +events { worker_connections 1024;} +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + log_format main '$time_iso8601###$status###$request'; + log_format tracker escape=json + '{"time":"$time_iso8601","alias":"$arg_alias","uuid":"$arg_uuid",' + '"lg":"$arg_lg","consentcookie":"$arg_consentcookie","version":"$arg_version",' + '"srckey":"$arg_srckey","request_filename":"$request_filename",' + '"remoteaddr":"$remote_addr","httpxforwardedfor":"$http_x_forwarded_for",' + '"httpreferer":"$http_referer","httpuseragent":"$http_user_agent","request":"$request"}'; + log_format mainold '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + sendfile on; + keepalive_timeout 65; + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 4 32k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/x-font-ttf application/javascript font/eot font/opentype image/svg+xml image/x-icon; + ## + # Virtual Host Configs + ## + #include /etc/nginx/conf.d/*.conf; + include {{apxtownsfolder}}/apxtowns/*/*/nginx/*.conf; +} +`; +Setup.{{tribe}}nginxconf = ` +server { + server_name {{#dns}} {{.}} {{/dns}}; + # usefull to debug nginx conf 3 next line: + access_log {{/apxtowns/{{town}}-{{nation}}/{{tribe}}/logs/nginx/{{tribe}}_{{webspace}}.access.log main; + #error_log {{apxtownsfolder}}//{{tribe}}/logs/nginx/{{tribe}}_{{webspace}}.error.log debug; + #add_header xdebug "testmsg debug: $uri - $request - liste args: $args - url:$arg_url - alias:$arg_alias " always; + + set $trackme 0; + if ( $uri ~ ^/trk/ ){ + set $trackme 1; + } + #access_log {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/logs/nginx/{{tribe}}_{{webspace}}.trk.log tracker if=$trackme ; + access_log {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/logs/nginx/{{tribe}}_{{webspace}}.trk.log tracker if=$trackme ; + location ~* /trk/ { + if ( $uri ~ ^/trk/redirect ){ + return 301 $arg_url; + } + rewrite ^/trk/(.*)$ /$1; + } + location /adminapi/Checkjson.js { + alias {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/adminapi/apxtri/models/Checkjson.js; + } + location ~* /adminapi/objects/tplstrings/ { + rewrite /adminapi/objects/tplstrings/(.*$) /$1 break; + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/adminapi/objects/tplstrings/; + } + location ~* /adminapi/schema/ { + rewrite /adminapi/schema/(.*$) /$1 break; + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/adminapi/schema/; + } + location ~* /{{tribe}}/objects/tplstrings/ { + rewrite /{{tribe}}/objects/tplstrings/(.*$) /$1 break; + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/objects/tplstrings/; + } + location ~* /{{tribe}}/schema/ { + rewrite /{{tribe}}/schema/(.*$) /$1 break; + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/schema/; + } + location /cdn/ { + expires 1y; + add_header Cache-Control "public"; + rewrite /cdn/(.*$) /$1 break; + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/objects/wwws/cdn/; + } + location /api/ { + rewrite /api/(.*$) /$1 break; + proxy_pass http://localhost:3020; + proxy_redirect off; + include proxy_params; + } + //ASUP + location /apxwebapp/ { + rewrite /apxwebapp/(.*$) /$1 break; + root {{apxtownsfolder}}/apxtowns/apxwebapp; + index index.html index_fr.html index_en.html; + } + location /apidoc/ { + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/objects/wwws/; + index index.html; + } + location / { + root {{apxtownsfolder}}/apxtowns/{{town}}-{{nation}}/{{tribe}}/objects/wwws/{{webspace}}; + index index.html index_fr.html index_en.html; + } + error_page 404 /404.html; + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/local/nginx/html; + } +} +`; + +Setup.addtribe = (tribeId) => { + const idxtribf = `../../idx/tribeId_all.json`; + const idxtrib = fs.existsSync(idxtribf) ? fs.readJSONSync(idxtribf) : {}; + if (idxtrib[tribeId]) { + return { + status: 406, + ref: "Tribes", + msg: "alreadyexist", + data: { tribeId }, + }; + } + const tribdata = { + nationId: nationId, + townId: townId, + tribeId: tribeId, + }; + idxtrib[tribeId] = tribdata; + fs.outputJSON(idxtribf, idxtrib, { spaces: 2 }); + fs.outputJSON("../../itm/${tribeId}.json", tribdata, { space: 2 }); + [ + `../../${tribeId}/nginx`, + `../../${tribeId}/logs/nginx`, + `../../${tribeId}/objects`, + `../../${tribeId}/schema`, + ].forEach((d) => fs.ensureDirSync(d)); + return { + status: 200, + ref: "Tribes", + msg: "tribeaddsuccess", + data: { tribe: tribeId }, + }; +}; +Setup.addwww = (tribeId,webspace,confdata) => { + fs.outputFile( + "/etc/nginx/nginx.conf", + mustache.render(Setup.nginxconf, confdata), + "utf-8" + ); + fs.outputFile( + `${confdata.apxtowns}/{{tribe}}/nginx/{{tribe}}_{{webspace}}.conf`, + mustache.render(Setup.{{tribe}}nginxconf, confdata), + "utf-8" + ); + const res={status:200,ref:"setup",msg:"wwwssuccess",data:confdata} + const { exec } = require("child_process"); + exec("sudo systemctl restart nginx", (error, stdout, stderr) => { + if (error) { + res.status = 500; + res.msg = "nginxError"; + res.data = { msg: `${error}
${stdout}
${stderr}` }; + return res + } else { + // for production exec("sudo certbot --nginx -d dns[0] -d dns[1] ...") or do it from adminapx + console.log( + `\x1b[42m###########################################################################################\x1b[0m\n\x1b[42mWellcome into apxtri, you can now 'yarn dev' for dev or 'yarn startpm2' for prod or \n'yarn unittest' for testing purpose. Access to your town here \x1b[0m\x1b[32mhttp://adminapx\x1b[0m \x1b[42m \nto finish your town setup. Don't forget to set your localhost /etc/hosts by adding 127.0.0.1 adminapx or {LAN IP} adminapx . Check README's project to learn more. \x1b[0m\n\x1b[42m###########################################################################################\x1b[0m` + ); + return res + } + }); +}; + +Setup.init = (param) => { + const nam = path.resolve("../..").split("/").slice(-1)[0].split("-"); + const confdata = { + town: nam[0], + nation: nam[1], + apxtownsfolder: path.resolve("../../../.."), + }; + let setupdone = true; + // check nginx exist + if (!fs.existsSync("/etc/nginx/nginx.conf")) { + setupdone = false; + console.log( + "\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available, install then rerun yarn command." + ); + } + if (!(param.dns && param.user)) { + setupdone = false; + console.log( + "This is a first install you must run next command with a domain name (use town-nation for dev and the linux user that run apXtri) check ping dns answer and su user exist (check README) \n dns=domainname user=linuxuser yarn dev" + ); + } + if (!setupdone) return false; + confdata.dns = [param.dns]; + confdata.user = param.user; + const addtribe = Setup.addtribe("{{tribe}}", confdata.town, confdata.nation); + if (addtribe.status != 200) { + console.log("erreur de creation"); + return false; + } + // set nginx + const addwww = Setup.addwww("{{tribe}}","admibnapx",confdata); +}; + +const param = {}; +argv.slice(2).forEach((arg) => { + const kv = arg.split("="); + if (kv.length == 2) { + param[kv[0]] = kv[1]; + } +}); +if (Setup.init(param)) + console.log( + "Your town was set successfully. Run yarn dev or yarn startapx for production" + );