@cyberskill/shared 1.168.0 → 1.170.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tsup-dts-rollup.d.cts +2 -2
- package/dist/_tsup-dts-rollup.d.ts +2 -2
- package/dist/node/cli/cli.util.cjs +1 -1
- package/dist/node/cli/cli.util.js +1 -1
- package/dist/node/cli/index.cjs +1 -1
- package/dist/node/cli/index.js +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.js +1 -1
- package/dist/util/common/common.util.cjs +1 -1
- package/dist/util/common/common.util.js +1 -1
- package/dist/util/common/index.cjs +1 -1
- package/dist/util/common/index.js +1 -1
- package/dist/util/index.cjs +1 -1
- package/dist/util/index.js +1 -1
- package/package.json +4 -4
- package/public/renovate.base.json +1 -6
- package/public/wiki/clone-project.md +0 -99
- package/public/wiki/convention.md +0 -185
- package/public/wiki/setup-mongo.md +0 -29
- package/public/wiki/setup-nginx.md +0 -50
- package/public/wiki/setup-node.md +0 -29
- package/public/wiki/setup-pm2.md +0 -27
- package/public/wiki/setup-redis.md +0 -17
- package/public/wiki/setup-ssl.md +0 -102
package/dist/util/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(e,r){if(r==null||r>e.length)r=e.length;for(var t=0,n=new Array(r);t<r;t++)n[t]=e[t];return n}function r(e){if(Array.isArray(e))return e}function t(r){if(Array.isArray(r))return e(r)}function n(e,r,t){if(r in e){Object.defineProperty(e,r,{value:t,enumerable:true,configurable:true,writable:true})}else{e[r]=t}return e}function i(e,r){if(r!=null&&typeof Symbol!=="undefined"&&r[Symbol.hasInstance]){return!!r[Symbol.hasInstance](e)}else{return e instanceof r}}function a(e){if(typeof Symbol!=="undefined"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function u(e,r){var t=e==null?null:typeof Symbol!=="undefined"&&e[Symbol.iterator]||e["@@iterator"];if(t==null)return;var n=[];var i=true;var a=false;var u,o;try{for(t=t.call(e);!(i=(u=t.next()).done);i=true){n.push(u.value);if(r&&n.length===r)break}}catch(e){a=true;o=e}finally{try{if(!i&&t["return"]!=null)t["return"]()}finally{if(a)throw o}}return n}function o(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function l(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function f(e){for(var r=1;r<arguments.length;r++){var t=arguments[r]!=null?arguments[r]:{};var i=Object.keys(t);if(typeof Object.getOwnPropertySymbols==="function"){i=i.concat(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))}i.forEach(function(r){n(e,r,t[r])})}return e}function c(e,t){return r(e)||u(e,t)||d(e,t)||o()}function s(e){return t(e)||a(e)||d(e)||l()}function y(e){"@swc/helpers - typeof";return e&&typeof Symbol!=="undefined"&&e.constructor===Symbol?"symbol":typeof e}function d(r,t){if(!r)return;if(typeof r==="string")return e(r,t);var n=Object.prototype.toString.call(r).slice(8,-1);if(n==="Object"&&r.constructor)n=r.constructor.name;if(n==="Map"||n==="Set")return Array.from(n);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return e(r,t)}var v=Object.defineProperty;var p=function(e,r){return v(e,"name",{value:r,configurable:!0})};import g from"unorm";var m=function(e){return e.PRODUCTION="production",e.STAGING="staging",e.DEVELOPMENT="development",e}({});var b={a:["\xe0","\xe1","ạ","ả","\xe3","\xe2","ầ","ấ","ậ","ẩ","ẫ","ă","ằ","ắ","ặ","ẳ","ẵ"],e:["\xe8","\xe9","ẹ","ẻ","ẽ","\xea","ề","ế","ệ","ể","ễ"],i:["\xec","\xed","ị","ỉ","ĩ"],o:["\xf2","\xf3","ọ","ỏ","\xf5","\xf4","ồ","ố","ộ","ổ","ỗ","ơ","ờ","ớ","ợ","ở","ỡ"],u:["\xf9","\xfa","ụ","ủ","ũ","ư","ừ","ứ","ự","ử","ữ"],y:["ỳ","\xfd","ỵ","ỷ","ỹ"],d:["đ"]},h=Object.entries(b).reduce(function(e,r){var t=c(r,2),n=t[0],i=t[1];return e[n.toUpperCase()]=i.map(function(e){return e.toUpperCase()}),e},{});function
|
|
1
|
+
function e(e,r){if(r==null||r>e.length)r=e.length;for(var t=0,n=new Array(r);t<r;t++)n[t]=e[t];return n}function r(e){if(Array.isArray(e))return e}function t(r){if(Array.isArray(r))return e(r)}function n(e,r,t){if(r in e){Object.defineProperty(e,r,{value:t,enumerable:true,configurable:true,writable:true})}else{e[r]=t}return e}function i(e,r){if(r!=null&&typeof Symbol!=="undefined"&&r[Symbol.hasInstance]){return!!r[Symbol.hasInstance](e)}else{return e instanceof r}}function a(e){if(typeof Symbol!=="undefined"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function u(e,r){var t=e==null?null:typeof Symbol!=="undefined"&&e[Symbol.iterator]||e["@@iterator"];if(t==null)return;var n=[];var i=true;var a=false;var u,o;try{for(t=t.call(e);!(i=(u=t.next()).done);i=true){n.push(u.value);if(r&&n.length===r)break}}catch(e){a=true;o=e}finally{try{if(!i&&t["return"]!=null)t["return"]()}finally{if(a)throw o}}return n}function o(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function l(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function f(e){for(var r=1;r<arguments.length;r++){var t=arguments[r]!=null?arguments[r]:{};var i=Object.keys(t);if(typeof Object.getOwnPropertySymbols==="function"){i=i.concat(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))}i.forEach(function(r){n(e,r,t[r])})}return e}function c(e,t){return r(e)||u(e,t)||d(e,t)||o()}function s(e){return t(e)||a(e)||d(e)||l()}function y(e){"@swc/helpers - typeof";return e&&typeof Symbol!=="undefined"&&e.constructor===Symbol?"symbol":typeof e}function d(r,t){if(!r)return;if(typeof r==="string")return e(r,t);var n=Object.prototype.toString.call(r).slice(8,-1);if(n==="Object"&&r.constructor)n=r.constructor.name;if(n==="Map"||n==="Set")return Array.from(n);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return e(r,t)}var v=Object.defineProperty;var p=function(e,r){return v(e,"name",{value:r,configurable:!0})};import g from"unorm";var m=function(e){return e.PRODUCTION="production",e.STAGING="staging",e.DEVELOPMENT="development",e}({});var b={a:["\xe0","\xe1","ạ","ả","\xe3","\xe2","ầ","ấ","ậ","ẩ","ẫ","ă","ằ","ắ","ặ","ẳ","ẵ"],e:["\xe8","\xe9","ẹ","ẻ","ẽ","\xea","ề","ế","ệ","ể","ễ"],i:["\xec","\xed","ị","ỉ","ĩ"],o:["\xf2","\xf3","ọ","ỏ","\xf5","\xf4","ồ","ố","ộ","ổ","ỗ","ơ","ờ","ớ","ợ","ở","ỡ"],u:["\xf9","\xfa","ụ","ủ","ũ","ư","ừ","ứ","ự","ử","ữ"],y:["ỳ","\xfd","ỵ","ỷ","ỹ"],d:["đ"]},h=Object.entries(b).reduce(function(e,r){var t=c(r,2),n=t[0],i=t[1];return e[n.toUpperCase()]=i.map(function(e){return e.toUpperCase()}),e},{});function O(e){e=g.nfkc(e);var r=f({},b,h);var t=true,n=false,i=undefined;try{for(var a=Object.entries(r)[Symbol.iterator](),u;!(t=(u=a.next()).done);t=true){var o=c(u.value,2),l=o[0],y=o[1];var d="[".concat(l).concat(y.join(""),"]"),v="(".concat([l].concat(s(y)).join("|"),")");e=e.replace(new RegExp(d,"g"),v)}}catch(e){n=true;i=e}finally{try{if(!t&&a.return!=null){a.return()}}finally{if(n){throw i}}}return e}p(O,"regexSearchMapper");function S(e){return e.normalize("NFD").replace(RegExp("\\p{Diacritic}","gu"),"")}p(S,"removeAccent");function E(e,r){if(!r)return Array.from(new Set(e));var t=new Set,n=[];var i=true,a=false,u=undefined;try{for(var o=e[Symbol.iterator](),l;!(i=(l=o.next()).done);i=true){var f=l.value;var c=r(f);t.has(c)||(t.add(c),n.push(f))}}catch(e){a=true;u=e}finally{try{if(!i&&o.return!=null){o.return()}}finally{if(a){throw u}}}return n}p(E,"uniqueArray");function w(e){var r=e.NODE_ENV,t=r===void 0?m.DEVELOPMENT:r,n=e.NODE_ENV_MODE,i=n===void 0?m.DEVELOPMENT:n,a=t===m.DEVELOPMENT&&i===m.DEVELOPMENT,u=t===m.PRODUCTION&&i===m.STAGING,o=t===m.PRODUCTION&&i===m.PRODUCTION;if(t===m.PRODUCTION&&i===m.DEVELOPMENT)throw new Error("NODE_ENV_MODE must be set to staging or production in production environment");return{IS_DEV:a,IS_STAG:u,IS_PROD:o}}p(w,"mapEnvironment");function A(e){try{return JSON.parse(e),!0}catch(e){return!1}}p(A,"isJson");function z(e){return(typeof e==="undefined"?"undefined":y(e))=="object"&&e!==null&&!Array.isArray(e)}p(z,"isObject");function N(){for(var e=arguments.length,r=new Array(e),t=0;t<e;t++){r[t]=arguments[t]}var n={};var i=true,a=false,u=undefined,o=true,l=false,f=undefined;try{for(var y=r.flat()[Symbol.iterator](),d;!(o=(d=y.next()).done);o=true){var v=d.value;try{for(var p=Object.entries(v)[Symbol.iterator](),g;!(i=(g=p.next()).done);i=true){var m=c(g.value,2),b=m[0],h=m[1];var O=n[b];if(Array.isArray(h)){var S=Array.isArray(O)?O:[];n[b]=s(new Set(s(S).concat(s(h))));continue}if(z(h)){n[b]=N(z(O)?O:{},h);continue}n[b]=h}}catch(e){a=true;u=e}finally{try{if(!i&&p.return!=null){p.return()}}finally{if(a){throw u}}}}}catch(e){l=true;f=e}finally{try{if(!o&&y.return!=null){y.return()}}finally{if(l){throw f}}}return n}p(N,"deepMerge");var D={Date:{is:p(function(e){return i(e,Date)},"is"),serialize:p(function(e){return{__type:"Date",value:e.toISOString()}},"serialize"),deserialize:p(function(e){return new Date(e)},"deserialize")},Map:{is:p(function(e){return i(e,Map)},"is"),serialize:p(function(e){return{__type:"Map",value:Array.from(e.entries())}},"serialize"),deserialize:p(function(e){return new Map(e)},"deserialize")},Set:{is:p(function(e){return i(e,Set)},"is"),serialize:p(function(e){return{__type:"Set",value:Array.from(e)}},"serialize"),deserialize:p(function(e){return new Set(e)},"deserialize")},RegExp:{is:p(function(e){return i(e,RegExp)},"is"),serialize:p(function(e){return{__type:"RegExp",value:{source:e.source,flags:e.flags}}},"serialize"),deserialize:p(function(e){var r=e.source,t=e.flags;return new RegExp(r,t)},"deserialize")},BigInt:{is:p(function(e){return(typeof e==="undefined"?"undefined":y(e))=="bigint"},"is"),serialize:p(function(e){return{__type:"BigInt",value:e.toString()}},"serialize"),deserialize:p(function(e){return BigInt(e)},"deserialize")}},I={serialize:function e(e){return JSON.stringify(e,function(e,r){var t=true,n=false,i=undefined;try{for(var a=Object.keys(D)[Symbol.iterator](),u;!(t=(u=a.next()).done);t=true){var o=u.value;var l=D[o];if(l.is(r))return l.serialize(r)}}catch(e){n=true;i=e}finally{try{if(!t&&a.return!=null){a.return()}}finally{if(n){throw i}}}return r})},deserialize:function e(e){return JSON.parse(e,function(e,r){if(r&&(typeof r==="undefined"?"undefined":y(r))=="object"&&"__type"in r&&typeof r.__type=="string"){var t=r.__type,n=D[t];if(n)return n.deserialize(r.value)}return r})}};import j from"crypto-js";import _ from"slugify";var x=_.default||_;function M(e,r){var t=p(function(e){var t,n;return x(e!==null&&e!==void 0?e:"",f({lower:(t=r===null||r===void 0?void 0:r.lower)!==null&&t!==void 0?t:!0,locale:(n=r===null||r===void 0?void 0:r.locale)!==null&&n!==void 0?n:"vi"},r))},"slugifyWithOptions");if(z(e)){var n={};var i=true,a=false,u=undefined;try{for(var o=Object.entries(e)[Symbol.iterator](),l;!(i=(l=o.next()).done);i=true){var s=c(l.value,2),y=s[0],d=s[1];n[y]=t(d)}}catch(e){a=true;u=e}finally{try{if(!i&&o.return!=null){o.return()}}finally{if(a){throw u}}}return n}return t(e)}p(M,"generateSlug");function P(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:4;return j.SHA256(e).toString(j.enc.Hex).slice(0,r)}p(P,"generateShortId");function T(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:8;var r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+[]{}|;:,.<>?",t="";for(var n=0;n<e;n++){var i=Math.floor(Math.random()*r.length);t+=r.charAt(i)}return t}p(T,"generateRandomPassword");function R(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;var t=e.split(/[?#]/)[0]||"",n=t.substring(t.lastIndexOf("/")+1);if(r)return n;var i=n.lastIndexOf(".");return i>0?n.slice(0,i):n}p(R,"getFileName");function V(e,r,t){var n=e.indexOf(r);if(n===-1)return"";var i=n+r.length,a=e.indexOf(t,i);return a===-1?"":e.slice(i,a)}p(V,"substringBetween");var C={isEmpty:function e(e){return e==null?!0:typeof e=="string"?e.trim().length===0:Array.isArray(e)?e.length===0:(typeof e==="undefined"?"undefined":y(e))=="object"?i(e,Date)?!1:i(e,Map)||i(e,Set)?e.size===0:i(e,WeakMap)||i(e,WeakSet)?!0:ArrayBuffer.isView(e)?e.byteLength===0:Object.keys(e).length===0:!1},isValidIP:function e(e){var r=e.split(".");return r.length===4&&r.every(function(e){return/^\d+$/.test(e)&&Number(e)>=0&&Number(e)<=255})?!0:/^(([a-f\d]{1,4}:){7}[a-f\d]{1,4}|((?:[a-f\d]{1,4}:){1,7}:)|((?:[a-f\d]{1,4}:){1,6}:[a-f\d]{1,4})|::)$/i.test(e)}};export{N as deepMerge,T as generateRandomPassword,P as generateShortId,M as generateSlug,R as getFileName,A as isJson,z as isObject,w as mapEnvironment,O as regexSearchMapper,S as removeAccent,I as serializer,V as substringBetween,E as uniqueArray,C as validate};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyberskill/shared",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.170.0",
|
|
5
5
|
"description": "CyberSkill Shared",
|
|
6
6
|
"author": "Stephen Cheng",
|
|
7
7
|
"license": "MIT",
|
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
"@antfu/eslint-config": "4.13.1",
|
|
226
226
|
"@apollo/client": "3.13.8",
|
|
227
227
|
"@apollo/server": "4.12.1",
|
|
228
|
-
"@dotenvx/dotenvx": "1.44.
|
|
228
|
+
"@dotenvx/dotenvx": "1.44.1",
|
|
229
229
|
"@eddeee888/gcg-typescript-resolver-files": "0.12.1",
|
|
230
230
|
"@eslint-react/eslint-plugin": "1.49.0",
|
|
231
231
|
"@graphql-codegen/cli": "5.0.6",
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
"@testing-library/jest-dom": "6.6.3",
|
|
238
238
|
"@testing-library/react": "16.3.0",
|
|
239
239
|
"@vitejs/plugin-react-swc": "3.9.0",
|
|
240
|
-
"@vitest/browser": "3.1.
|
|
240
|
+
"@vitest/browser": "3.1.4",
|
|
241
241
|
"body-parser": "2.2.0",
|
|
242
242
|
"chalk": "5.4.1",
|
|
243
243
|
"classnames": "2.5.1",
|
|
@@ -288,7 +288,7 @@
|
|
|
288
288
|
"unorm": "1.6.0",
|
|
289
289
|
"uuid": "11.1.0",
|
|
290
290
|
"vite": "6.3.5",
|
|
291
|
-
"vitest": "3.1.
|
|
291
|
+
"vitest": "3.1.4",
|
|
292
292
|
"vitest-browser-react": "0.2.0",
|
|
293
293
|
"ws": "8.18.2",
|
|
294
294
|
"yargs": "17.7.2"
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Tạo SSH key
|
|
2
|
-
|
|
3
|
-
Mở terminal và chạy lệnh sau:
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
ssh-keygen -t ed25519 -C "địa-chỉ-email"
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
- Khi được hỏi "Enter a file in which to save the key", nhấn `Enter` để dùng mặc định (`~/.ssh/id_ed25519`)
|
|
10
|
-
|
|
11
|
-
> ⚠️ Lưu ý:
|
|
12
|
-
|
|
13
|
-
- Có thể đặt passphrase để tăng độ bảo mật (hoặc để trống nếu muốn nhanh)
|
|
14
|
-
- Nên thêm hậu tố để tránh trùng lặp đối với trường hợp dùng nhiều dự án/tài khoản, ví dụ `~/.ssh/id_ed25519_stephen_cyberskill` hoặc `~/.ssh/id_ed25519_project_xxx`
|
|
15
|
-
|
|
16
|
-
## ✅ Bước 2: Khởi động SSH Agent
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
eval "$(ssh-agent -s)"
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## ✅ Bước 3: Cấu hình SSH cho GitHub
|
|
23
|
-
|
|
24
|
-
Tạo và sửa file cấu hình SSH:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
touch ~/.ssh/config
|
|
28
|
-
nano ~/.ssh/config
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Thêm nội dung sau:
|
|
32
|
-
|
|
33
|
-
```ssh
|
|
34
|
-
Host github.com
|
|
35
|
-
User git
|
|
36
|
-
UseKeychain yes
|
|
37
|
-
HostName github.com
|
|
38
|
-
AddKeysToAgent yes
|
|
39
|
-
IdentitiesOnly yes
|
|
40
|
-
IdentityFile ~/.ssh/id_ed25519
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
> ⚠️ Lưu ý:
|
|
44
|
-
|
|
45
|
-
- `User git` có thể không cần để, trừ một số trường hợp đặc biệt như kết nối với google cloud VM, ví dụ `User stephen.cheng` và `HostName xxx.xxx.xxx.xxx` là địa chỉ IP của server
|
|
46
|
-
- `UseKeychain yes` chỉ áp dụng cho macOS, nếu dùng Linux/Windows thì không cần cấu hình này.
|
|
47
|
-
- Trường hợp dùng nhiều tài khoản có thể tạo nhiều Host với IdentityFile và Host khác nhau, ví dụ `Host github.com` và `IdentityFile ~/.ssh/id_ed25519` khi dùng các dự án cá nhân, `Host github.com-cyberskill` và `IdentityFile ~/.ssh/id_ed25519_cyberskill` khi dùng các dự án cyberskill
|
|
48
|
-
|
|
49
|
-
Lưu và thoát (`Ctrl + X`, nhấn `Y`, rồi `Enter`).
|
|
50
|
-
|
|
51
|
-
## ✅ Bước 4: Thêm SSH key vào GitHub
|
|
52
|
-
|
|
53
|
-
Hiển thị public key:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
cat ~/.ssh/id_ed25519.pub
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Copy toàn bộ nội dung và vào [GitHub SSH Keys Settings](https://github.com/settings/keys):
|
|
60
|
-
|
|
61
|
-
- Bấm **"New SSH key"**
|
|
62
|
-
- Đặt **Title** dễ nhớ (có thể dùng hậu tố ở bước 1)
|
|
63
|
-
- Dán public key vào phần **Key**
|
|
64
|
-
|
|
65
|
-
## ✅ Bước 5: Kiểm tra kết nối SSH
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
ssh -T git@XXX
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
> ⚠️ Lưu ý: XXX là Host đã đặt lúc tạo file config ở bước 3, ví dụ `ssh -T git@github.com`
|
|
72
|
-
|
|
73
|
-
Nếu thành công, terminal sẽ hiển thị:
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
Hi your-username! You've successfully authenticated, but GitHub does not provide shell access.
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## ✅ Bước 6: Clone dự án
|
|
80
|
-
|
|
81
|
-
Clone dự án bằng SSH:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
git clone git@XXX:tên-người-dùng/tên-dự-án.git
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
> ⚠️ Lưu ý:
|
|
88
|
-
|
|
89
|
-
- Tạo thư mục phù hợp trên máy và mở terminal tại thư mục đó trước khi clone dự án
|
|
90
|
-
- XXX là Host đã đặt lúc tạo file config ở bước 3, ví dụ `git clone git@github.com:cyberskill-world/cyberskill-example.git`
|
|
91
|
-
|
|
92
|
-
## 🛠 Tuỳ chọn: Cấu hình tên và email
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
git config --global user.name "Tên hiển thị"
|
|
96
|
-
git config --global user.email "địa-chỉ-email"
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
> ⚠️ Lưu ý: `--global` sẽ áp dụng mặc định cho toàn bộ dự án trong máy (kể cả các dự án sau này), nếu muốn dùng riêng cho từng dự án thì mở terminal tại vị trí dự án rồi chạy lệnh nhưng không để cấu hình `--global`, ví dụ `git config user.name "Stephen Cheng"`
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
# Hướng Dẫn Sử Dụng Dự Án
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-
|
|
6
|
-
<!-- Mục lục -->
|
|
7
|
-
|
|
8
|
-
- [Yêu Cầu](#yêu-cầu)
|
|
9
|
-
- [Cài Đặt](#cài-đặt)
|
|
10
|
-
- [Chạy Dự Án](#chạy-dự-án)
|
|
11
|
-
- [Chạy ở môi trường development với Docker](#chạy-ở-môi-trường-development-với-docker)
|
|
12
|
-
- [Chạy ở môi trường development (Local)](#chạy-ở-môi-trường-development-local)
|
|
13
|
-
- [Các Script & Ý Nghĩa](#các-script--ý-nghĩa)
|
|
14
|
-
- [Quy Ước Viết Code & Đặt Tên](#quy-ước-viết-code--đặt-tên)
|
|
15
|
-
- [Quy Ước Đặt Tên](#quy-ước-đặt-tên)
|
|
16
|
-
- [Quy Ước Đặt Tên Chung](#quy-ước-đặt-tên-chung)
|
|
17
|
-
- [Quy Ước Tiền Tố Trong TypeScript](#quy-ước-tiền-tố-trong-typescript)
|
|
18
|
-
- [Quy Ước Đặt Tên Type Trong GraphQL](#quy-ước-đặt-tên-type-trong-graphql)
|
|
19
|
-
- [Quy Ước Đặt Tên Biến Môi Trường](#quy-ước-đặt-tên-biến-môi-trường)
|
|
20
|
-
- [Quy Ước Khi Import](#quy-ước-khi-import)
|
|
21
|
-
- [Quy Ước Viết Code](#quy-ước-viết-code)
|
|
22
|
-
- [Quy Ước Đặt Commit Message](#quy-ước-đặt-commit-message)
|
|
23
|
-
- [Quy Trình Làm Việc Với Git](#quy-trình-làm-việc-với-git)
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Yêu Cầu
|
|
28
|
-
|
|
29
|
-
- **nvm (Node Version Manager):**
|
|
30
|
-
- MacOS: [nvm-sh/nvm](https://github.com/nvm-sh/nvm)
|
|
31
|
-
- Windows: [coreybutler/nvm-windows](https://github.com/coreybutler/nvm-windows)
|
|
32
|
-
- **Node.js:** 22.15.0
|
|
33
|
-
_(nvm sẽ tự động cài đặt phiên bản này nếu chưa có)_
|
|
34
|
-
- MacOS: [node-v22.15.0.pkg](https://nodejs.org/dist/v22.15.0/node-v22.15.0.pkg)
|
|
35
|
-
- Windows: [node-v22.15.0-x64.msi](https://nodejs.org/dist/v22.15.0/node-v22.15.0-x64.msi)
|
|
36
|
-
- **Docker:** [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
|
37
|
-
- **Ghi chú:** Dùng **pnpm** để tránh xung đột với các công cụ khác.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Cài Đặt
|
|
42
|
-
|
|
43
|
-
1. **Tạo file cấu hình môi trường:**
|
|
44
|
-
Sao chép file `.env.example` thành `.env`.
|
|
45
|
-
2. **Chỉnh sửa file `.env`:**
|
|
46
|
-
Cập nhật các trường cần thiết phù hợp với môi trường máy.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## Chạy Dự Án
|
|
51
|
-
|
|
52
|
-
### Chạy ở môi trường development với Docker
|
|
53
|
-
|
|
54
|
-
_(Lưu ý: Hãy bật Docker trước khi chạy)_
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
make build-development
|
|
58
|
-
make start-development
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Chạy ở môi trường development (Local)
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
pnpm i
|
|
65
|
-
pnpm run dev
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## Các Script & Ý Nghĩa
|
|
71
|
-
|
|
72
|
-
| Script | Ý nghĩa |
|
|
73
|
-
| ---------------- | --------------------------------------- |
|
|
74
|
-
| **lint** | Kiểm tra lỗi lint và typescript |
|
|
75
|
-
| **lint:fix** | Tự động sửa các lỗi có thể sửa |
|
|
76
|
-
| **lint:inspect** | Xem chi tiết các lint rule đang dùng |
|
|
77
|
-
| **reset** | Cài đặt lại dependencies |
|
|
78
|
-
| **prepare** | Tự động nâng cấp @cyberskill/shared |
|
|
79
|
-
| **inspect** | Xem chi tiết các dependencies đang dùng |
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Quy Ước Viết Code & Đặt Tên
|
|
84
|
-
|
|
85
|
-
### Quy Ước Đặt Tên
|
|
86
|
-
|
|
87
|
-
| Loại | Quy Ước | Ví Dụ |
|
|
88
|
-
| ------------- | ------------ | ------------------- |
|
|
89
|
-
| **Biến** | `camelCase` | `userName` |
|
|
90
|
-
| **Hàm** | `camelCase` | `getUserInfo()` |
|
|
91
|
-
| **Parameter** | `camelCase` | `id, userData` |
|
|
92
|
-
| **Argument** | `camelCase` | `fetchData(userId)` |
|
|
93
|
-
| **Private** | `_camelCase` | `_isHidden` |
|
|
94
|
-
| **Class** | `PascalCase` | `UserProfile` |
|
|
95
|
-
| **Hằng số** | `UPPER_CASE` | `MAX_RETRY_COUNT` |
|
|
96
|
-
| **File** | `kebab-case` | `user-service.ts` |
|
|
97
|
-
| **Thư mục** | `kebab-case` | `services/` |
|
|
98
|
-
|
|
99
|
-
### Quy Ước Đặt Tên Chung
|
|
100
|
-
|
|
101
|
-
| Loại | Tiền Tố | Quy Tắc | Ví Dụ |
|
|
102
|
-
| ------------------------ | ------------- | ----------------------------- | --------------------------- |
|
|
103
|
-
| **Biến đại diện input** | `I_Input_` | Tiền tố + loại + kiểu dữ liệu | `interface I_Input_User` |
|
|
104
|
-
| **Biến đại diện output** | `I_Response_` | Tiền tố + loại + kiểu dữ liệu | `interface I_Response_User` |
|
|
105
|
-
|
|
106
|
-
### Quy Ước Tiền Tố Trong TypeScript
|
|
107
|
-
|
|
108
|
-
| Loại | Tiền Tố | Ví Dụ |
|
|
109
|
-
| ------------- | ------- | ------------------ |
|
|
110
|
-
| **Interface** | `I_` | `interface I_User` |
|
|
111
|
-
| **Type** | `T_` | `type T_User` |
|
|
112
|
-
| **Enum** | `E_` | `enum E_User` |
|
|
113
|
-
| **Constant** | `C_` | `enum C_User` |
|
|
114
|
-
|
|
115
|
-
### Quy Ước Đặt Tên Type Trong GraphQL
|
|
116
|
-
|
|
117
|
-
| Loại | Tiền Tố | Ví Dụ |
|
|
118
|
-
| ------------- | -------- | ------------------------ |
|
|
119
|
-
| **Type** | `T_` | `type T_User` |
|
|
120
|
-
| **Input** | `Input_` | `input Input_CreateUser` |
|
|
121
|
-
| **Interface** | `I_` | `input I_User` |
|
|
122
|
-
| **Union** | `U_` | `input U_SearchResult` |
|
|
123
|
-
|
|
124
|
-
### Quy Ước Đặt Tên Biến Môi Trường
|
|
125
|
-
|
|
126
|
-
| Loại | Tiền Tố | Ví Dụ |
|
|
127
|
-
| ----------- | -------------- | --------------------- |
|
|
128
|
-
| **Vite** | `VITE_` | `VITE_API_SECRET` |
|
|
129
|
-
| **Next.js** | `NEXT_PUBLIC_` | `NEXT_PUBLIC_API_KEY` |
|
|
130
|
-
| **Node.js** | `NODE_` | `NODE_ENV` |
|
|
131
|
-
|
|
132
|
-
### Quy Ước Khi Import
|
|
133
|
-
|
|
134
|
-
1. Các thư viện bên ngoài **ở trên cùng**.
|
|
135
|
-
2. Các module/hàm tiện ích **ở dưới**, cách một dòng trắng với phần trên.
|
|
136
|
-
3. Định cấu hình đường dẫn để **import nhanh** trong `tsconfig.json`.
|
|
137
|
-
|
|
138
|
-
```ts
|
|
139
|
-
import React from 'react'; // Thư viện bên ngoài
|
|
140
|
-
|
|
141
|
-
import { formatDate } from '#shared/util'; // Module nội bộ
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Quy Ước Viết Code
|
|
145
|
-
|
|
146
|
-
✅ **Làm**
|
|
147
|
-
|
|
148
|
-
- Dùng `let` và `const` thay vì `var`.
|
|
149
|
-
- Dùng `===` thay vì `==`.
|
|
150
|
-
- Xóa `console.log`, `alert` và `debugger` trước khi commit.
|
|
151
|
-
|
|
152
|
-
❌ **Không làm**
|
|
153
|
-
|
|
154
|
-
- Không dùng `any`, `unknown`, `never`.
|
|
155
|
-
- Không dùng `@ts-ignore`, `@ts-nocheck`.
|
|
156
|
-
|
|
157
|
-
### Quy Ước Đặt Commit Message
|
|
158
|
-
|
|
159
|
-
| Loại Commit | Cú Pháp | Ví Dụ |
|
|
160
|
-
| ----------------- | ------------------------ | ------------------------------------------ |
|
|
161
|
-
| **Tính năng mới** | `feat(module): message` | `feat(user): add user login form` |
|
|
162
|
-
| **Sửa lỗi** | `fix(module): message` | `fix(auth): incorrect password validation` |
|
|
163
|
-
| **Dọn dẹp** | `chore(module): message` | `chore(product): refactor product filter` |
|
|
164
|
-
|
|
165
|
-
## Quy Trình Làm Việc Với Git
|
|
166
|
-
|
|
167
|
-
1. **Tạo nhánh mới từ `develop`**:
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
git checkout develop
|
|
171
|
-
git pull origin develop
|
|
172
|
-
git checkout -b feature/new-feature
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
2. **Commit theo chuẩn**:
|
|
176
|
-
|
|
177
|
-
```bash
|
|
178
|
-
git commit -m "feat(module): mô tả ngắn gọn"
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
3. **Tạo Pull Request (PR)** và đợi review trước khi merge vào `develop`.
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
> **Ghi chú:** Nếu có bất kỳ thắc mắc nào, vui lòng liên hệ team phát triển!
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Cài đặt mongo 8.0 (Ubuntu 24.04)
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
sudo apt-get install gnupg curl
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \
|
|
9
|
-
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
|
|
10
|
-
--dearmor
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
sudo apt-get update
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
sudo apt-get install -y mongodb-org
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## ✅ Bước 2: Chạy mongo
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
sudo systemctl start mongod
|
|
29
|
-
```
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Cài đặt nginx
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
sudo apt update
|
|
5
|
-
sudo apt install nginx
|
|
6
|
-
```
|
|
7
|
-
|
|
8
|
-
## ✅ Bước 2: Cấu hình nginx
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
cd /etc/nginx/sites-enabled
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
sudo nano default
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Thiết lập cấu hình
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
server {
|
|
22
|
-
listen port-sẽ-chạy;
|
|
23
|
-
server_name địa-chỉ-ip;
|
|
24
|
-
|
|
25
|
-
location / {
|
|
26
|
-
proxy_pass http://localhost:port-sẽ-chạy;
|
|
27
|
-
proxy_http_version 1.1;
|
|
28
|
-
proxy_set_header Upgrade $http_upgrade;
|
|
29
|
-
proxy_set_header Connection 'upgrade';
|
|
30
|
-
proxy_set_header Host $host;
|
|
31
|
-
proxy_cache_bypass $http_upgrade;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## ✅ Bước 3: Kiểm tra cấu hình
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
sudo nginx -t
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Nếu hiện như sau là cấu hình ok
|
|
43
|
-
`nginx: the configuration file /etc/nginx/nginx.conf syntax is ok`
|
|
44
|
-
`nginx: configuration file /etc/nginx/nginx.conf test is successful`
|
|
45
|
-
|
|
46
|
-
## ✅ Bước 4: Khởi động lại nginx với cấu hình mới
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
sudo nginx -s reload
|
|
50
|
-
```
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Cài đặt homebrew (nếu chưa cài)
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
## ✅ Bước 2: Cài đặt nvm
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
brew install nvm
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Thêm đoạn script dưới đây vào `~/.profile` hoặc `~/.zshrc`
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
export NVM_DIR="$HOME/.nvm"
|
|
17
|
-
[ -s "/home/linuxbrew/.linuxbrew/opt/nvm/nvm.sh" ] && \. "/home/linuxbrew/.linuxbrew/opt/nvm/nvm.sh" # This loads nvm
|
|
18
|
-
[ -s "/home/linuxbrew/.linuxbrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/home/linuxbrew/.linuxbrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Tắt mở lại terminal hoặc chạy lệnh `source ~/.profile` hoặc `source ~/.zshrc`
|
|
22
|
-
|
|
23
|
-
## ✅ Bước 3: Cài đặt phiên bản node tương ứng
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
nvm install phiên-bản-node
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
> ⚠️ Lưu ý: ví dụ `nvm install 22.15.0`
|
package/public/wiki/setup-pm2.md
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Cài đặt node (nếu chưa cài)
|
|
2
|
-
|
|
3
|
-
[Xem tại đây](./setup-node.md)
|
|
4
|
-
|
|
5
|
-
## ✅ Bước 2: Cài đặt pm2
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
npm install pm2 -g
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## ✅ Bước 3: Chạy pm2
|
|
12
|
-
|
|
13
|
-
Chạy bằng node mặc định
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
pm2 start tên-file.js --name tên-app
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
> ⚠️ Lưu ý: ví dụ `pm2 start index.js --name cyberskill-example`
|
|
20
|
-
|
|
21
|
-
Đối với dự án có script chạy từ package.json
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
pm2 start pnpm --name tên-app -- run tên-script-chạy
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
> ⚠️ Lưu ý: ví dụ `pm2 start pnpm --name cyberskill-example -- run start`
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Cài đặt homebrew (nếu chưa cài)
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
## ✅ Bước 2: Cài đặt redis
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
brew install redis
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## ✅ Bước 3: Chạy redis
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
brew services start redis
|
|
17
|
-
```
|
package/public/wiki/setup-ssl.md
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
## ✅ Bước 1: Cài đặt certbot
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
sudo apt update
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
sudo apt install certbot python3-certbot-nginx
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## ✅ Bước 2: Chạy certbot
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
sudo certbot --nginx -d tên-miền
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
> ⚠️ Lưu ý: nếu có nhiều tên miền có thể ghi liên tục, ví dụ `sudo certbot --nginx -d cyberskill.example -d api.cyberskill.example -d www.cyberskill.example`
|
|
18
|
-
|
|
19
|
-
Nếu hiện như sau là cấu hình ok
|
|
20
|
-
`Successfully received certificate.`
|
|
21
|
-
`Certificate is saved at: đường-dẫn/fullchain.pem`
|
|
22
|
-
`Key is saved at: đường-dẫn/privkey.pem`
|
|
23
|
-
`This certificate expires on năm-tháng-ngày.`
|
|
24
|
-
`These files will be updated when the certificate renews.`
|
|
25
|
-
`Certbot has set up a scheduled task to automatically renew this certificate in the background.`
|
|
26
|
-
|
|
27
|
-
## ✅ Bước 3: Cập nhật cấu hình nginx
|
|
28
|
-
|
|
29
|
-
Ví dụ cho cấu hình Backend và Frontend
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
server {
|
|
33
|
-
listen 80 default_server;
|
|
34
|
-
listen [::]:80 default_server;
|
|
35
|
-
|
|
36
|
-
server_name cyberskill.example www.cyberskill.example api.cyberskill.example;
|
|
37
|
-
|
|
38
|
-
return 301 https://$host$request_uri;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
server {
|
|
42
|
-
listen 443 ssl;
|
|
43
|
-
listen [::]:443 ssl;
|
|
44
|
-
|
|
45
|
-
server_name cyberskill.example www.cyberskill.example;
|
|
46
|
-
|
|
47
|
-
ssl_certificate /etc/letsencrypt/live/cyberskill.example/fullchain.pem;
|
|
48
|
-
ssl_certificate_key /etc/letsencrypt/live/cyberskill.example/privkey.pem;
|
|
49
|
-
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
50
|
-
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
|
51
|
-
|
|
52
|
-
location / {
|
|
53
|
-
proxy_pass http://localhost:port-frontend;
|
|
54
|
-
proxy_http_version 1.1;
|
|
55
|
-
proxy_set_header Upgrade $http_upgrade;
|
|
56
|
-
proxy_set_header Connection 'upgrade';
|
|
57
|
-
proxy_set_header Host $host;
|
|
58
|
-
proxy_cache_bypass $http_upgrade;
|
|
59
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
60
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
server {
|
|
65
|
-
listen 443 ssl;
|
|
66
|
-
listen [::]:443 ssl;
|
|
67
|
-
|
|
68
|
-
server_name api.cyberskill.example;
|
|
69
|
-
|
|
70
|
-
ssl_certificate /etc/letsencrypt/live/cyberskill.example/fullchain.pem;
|
|
71
|
-
ssl_certificate_key /etc/letsencrypt/live/cyberskill.example/privkey.pem;
|
|
72
|
-
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
73
|
-
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
|
74
|
-
|
|
75
|
-
location / {
|
|
76
|
-
proxy_pass http://localhost:port-backend;
|
|
77
|
-
proxy_http_version 1.1;
|
|
78
|
-
proxy_set_header Upgrade $http_upgrade;
|
|
79
|
-
proxy_set_header Connection 'upgrade';
|
|
80
|
-
proxy_set_header Host $host;
|
|
81
|
-
proxy_cache_bypass $http_upgrade;
|
|
82
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
83
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## ✅ Bước 4: Kiểm tra cấu hình
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
sudo nginx -t
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Nếu hiện như sau là cấu hình ok
|
|
95
|
-
`nginx: the configuration file /etc/nginx/nginx.conf syntax is ok`
|
|
96
|
-
`nginx: configuration file /etc/nginx/nginx.conf test is successful`
|
|
97
|
-
|
|
98
|
-
## ✅ Bước 5: Khởi động lại nginx với cấu hình mới
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
sudo nginx -s reload
|
|
102
|
-
```
|