單機伺服器部署Nginx/Node/Nuxt/React/NG,常規優化及自啟指令碼

CRPER發表於2018-12-19

前言

作為小作坊,之前前後端的服務全部一股腦的在一個伺服器,

隨著業務多了些,前端這塊終於扔出來了(獨立)...雖然只有雙核2M頻寬;

需要部署的有這麼幾個,包括測試線及正式線(如下):

PC官網(Angular6)/管理後臺(umi+react)/移動端分享(Nuxt)/APP內嵌頁(Nuxt)

隨手記,有興趣的看看,也許可以幫你省點時間..


你能收穫什麼?

雜七雜八的知識點,linux的一些東東shell ,chmod,chgrp ,chown以及基礎運維的一些知識

nginx的一些東東,比較現代化的配置(不考慮IE11以下的);

pm2node什麼的一些東東


基礎環境

  • 系統版本選型是Centos 7.4,到手後麻溜升級到最新的
# 檢視版本號
cat /etc/redhat-release
# 更新
yum update 
# 重啟
reboot
# 適用於非跨版本大版本的(比如7.x的升級..跨版本的此法子不一定適用)
# 也不建議伺服器突然跨大版本升級,新機子就直接上新的,反正全部重新部署的
# 大版本的升級, 注意做好對應的防範措施,避免正式線直接GG,有主從的好一點,可以在從伺服器搞了再同步過去
cat /etc/redhat-release  # CentOS Linux release 7.6.1810 (Core)

複製程式碼
  • node版本選用的是非LTS版本,而是current快速迭代版本(11.x)

官方wiki已經提供: github.com/nodesource/…

  • 基礎依賴(gcc,make依賴)
yum install gcc-c++ make

複製程式碼

不然有些依賴編譯的會報這個錯,比如我在部署nuxt的時候遇到的

單機伺服器部署Nginx/Node/Nuxt/React/NG,常規優化及自啟指令碼

  • yarn,用起來比較舒服的包管理器(官方源)
# centos
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install yarn
複製程式碼
  • nginx,選用的是lts(1.14.2)

nginx 官方文件給出了源,自己造,vim編寫下即可

www.nginx.com/resources/w…

最新LTS的更新日誌: nginx.org/en/CHANGES-…

  • git,官網原始碼安裝

原始碼包: mirrors.edge.kernel.org/pub/softwar…

# 2.x.x 是你選擇版本(下載那個)
$ tar -zxf git-2.x.x.tar.gz
$ cd git-2.x.x
$ make configure # 編譯
$ ./configure --prefix=/usr # 指定安裝位置(--prefix)
$ make all doc info
$ sudo make install install-doc install-html install-info
# 走完這一些基本正常安裝(無報錯的情況,否則缺啥補啥)
複製程式碼

當然也可以直接用yum 安裝系統上游倉的git ,只不過版本比較老

還有第三方源也是一個可選的(安全隱患自己承擔)


部署

安裝好nginx之後,預設的常用有這麼幾個:

  • html(/usr/share/nginx/html): 存放網頁的地方
  • conf(/etc/nginx/conf.d/): 此目錄下的conf檔案會追加到nginx.conf中,具體看nginx.conf用到了include
  • logs(/var/logs/nginx): nginx預設日誌的存放位置

比如include你自己也可以指定,配置檔案要抽離的多細緻都行

我用的最新的lts,初始化的nginx.conf大體是這樣的,有些是我自己加進去的

騰訊雲有對應的nginx中文手冊

注意點

最新版預設的執行使用者是nginx , 有些版本的是www-data;

所以你的程式碼區域,不放在預設nginx預設路徑的話,記得修正好許可權,切莫放在root家目錄下;

否則你必須讓nginx超管許可權(加入對應的使用者組),且更改該目錄所屬,

比較合理做法是我們把程式碼目錄存放到根目錄下,新建一個資料夾存放;


# 修正該目錄的所屬
# 意思就是遞迴該目錄的擁有者為nginx,使用者組為nginx, chown(change owner)
chown -R nginx:nginx /code

# 也能用chgrp來修改使用者組(change group)

然後給該目下新增對應的檔案許可權,我們給他755
chmod -R 755 /code


`755 : rwx-rx-rX => u(user)-g(group)-o(other) => r(read[讀]:4)-x(excute[執行]:1)-w(write[寫]:2)`

# 查詢機子的一些資訊,比如cpu ,記憶體這些,可以進到  /proc目錄檢視
#比如/proc/cpuinfo(cpu資訊) ,meminfo(記憶體資訊)等

複製程式碼

nginx最常用的命令

  • nginx -t: 測試nginx配置檔案是否正常,若錯誤會直接丟擲,切忌改動配置檔案後直接重啟服務!校驗是唯一的真理
  • nginx -s reload: 過載配置檔案,無需重啟nginx服務,變動nginx配置可以直接用這個直接生效,不當機

nginx.conf


# 使用使用者
user  nginx;
worker_processes auto; # 程式數,自動就可以
worker_rlimit_nofile 65535; # worker程式的最大開啟檔案數限制

events { # 處理連結的額外引數,如名事件
    multi_accept on; # 允許儘可能多的連線接入
    use epoll; # 輪詢方案
    worker_connections 65535; # 最大的連線數
}

# 錯誤日誌存放
error_log  /var/log/nginx/error.log warn;

# pid(process id), 更多的用於linux操作程式的時候用到,該pid代表nginx例項
pid        /var/run/nginx.pid;




http {
    charset utf-8; # 預設字符集
    sendfile on; # 提高靜態資源的託管效率
    tcp_nopush on; # 只有sendfile 開啟的情況下,才會生效,累計包達到一定數量或大小才會發出,降低開銷
    tcp_nodelay on; # 儘快傳送資料,只會針對處於 keep-alive 狀態的 TCP 連線才會啟用 tcp_nodelay
    server_tokens off; # 安全隱患規避,隱藏請求頭nginx版本
    log_not_found off; # 不存在部分資源的時候記錄到日誌,比如favico
    types_hash_max_size 2048; # 記憶體換效率,檢索依賴
    client_max_body_size 16M;  # 允許客戶端傳送body的最大值(看你們上傳檔案調整)
    include       /etc/nginx/mime.types; # 一個對映表,就是資源的mime表,就是允許的資源型別

    default_type  application/octet-stream; # nginx 預設傳送格式

    # 日誌格式
    log_format  main  '$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;


    # SSL
    ssl_session_timeout 1d; # 客戶端會話中ssl憑證的有效期,自行看著調整
    ssl_session_cache shared:SSL:50m; #ssl/tls會話快取的型別和大小,官網上說1M可以存放約4000個sessions
    ssl_session_tickets off; # 關閉會話憑證複用

    # 啟用TLS1.2及加密方式
    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
    ssl_prefer_server_ciphers on; # 優先使用服務端的加密演算法而非客戶端的

    # 啟用證照狀態線上校驗
    ssl_stapling on; 
    ssl_stapling_verify on;
    # 啟動上面的需要有DNS解析伺服器,最安全的是自己本地跑一個DNS伺服器.否則用第三方的
    resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s;
	resolver_timeout 2s;

    # 請求超時時長
    keepalive_timeout  65;

    #預設根配置不做壓縮(這裡會面向全域性)
    # 我們到專案級別做,比如測試線的不需要怎麼壓縮,正式線壓縮到一定程度
    #gzip  on; 
    

    include /etc/nginx/conf.d/*.conf;
}
複製程式碼

拿我手頭的一個nuxt和一個常規打包專案

  • react or ng6

常規部署:這類部署適用於build出來一個dist這類


server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name proadmin.xxxx.com;
    root /code/react-sx-admin/prod;
    # SSL證照路徑
    ssl_certificate /etc/nginx/conf.d/cert/proadmin/proadmin.crt;
    ssl_certificate_key /etc/nginx/conf.d/cert/proadmin/proadmin.key;
    ssl_trusted_certificate /etc/nginx/conf.d/cert/proadmin/proadmin.crt;
    # SPA啟用了history模式,必須做一個首頁定址,不然會找不到的
    location / {
        try_files $uri $uri/ /index.html;
    }
    # 拒絕訪問
    location ~ /\.(?!well-known) {
        deny all;
    }
    # 快取以下型別的靜態資源
    location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
        expires 7d;
        access_log off;
    }
    # 允許字元svg這些的訪問,且快取
    location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
        add_header Access-Control-Allow-Origin "*";
        expires 7d;
        access_log off;
    }
    # gzip 壓縮配置
    gzip on;
    gzip_vary on;
    # 無條件啟用壓縮,支援區域性壓縮(就是檢測部分請求頭)
    gzip_proxied any;
    # 壓縮等級,吃硬體
    gzip_comp_level 6;
    # 處理的檔案型別
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
}
# http這塊我們直接重定向到https
server {
    listen 80;
    listen [::]:80; # 雙冒號是全域
    server_name proadmin.xxx.com;
    location / {
        #域名也可以用 $host來替代(內建變數)
        return 301 https://proadmin.xxx.com$request_uri;
    }
}


複製程式碼
  • nuxt

反向代理 : 這種更多的適用於服務的,比如node帶動的及其他可以提供服務的


# 這段是nuxt官方文件推薦的寫法 ,響應的內容及過期時間
# https://zh.nuxtjs.org/faq/nginx-proxy/
map $sent_http_content_type $expires {
    "text/html" epoch; # epoch是1970開始的時間
    "text/html; charset=utf-8" epoch;
    default off;
}
server {
    listen 80;
    server_name proshare.xxx.com;
# Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name proshare.xxx.com;
    gzip on;
    gzip_types text/plain application/xml text/css application/javascript;
    gzip_min_length 1000;
    location / {
        expires $expires;
        proxy_redirect off;
        proxy_set_header Host               $host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout 1m;
        proxy_connect_timeout 1m;
        proxy_pass http://127.0.0.1:5555;
    }
    location ~ /\.ht {
        deny all;
    }
    ssl_certificate /etc/nginx/conf.d/cert/proshare/proshare.crt;
    ssl_certificate_key /etc/nginx/conf.d/cert/proshare/proshare.key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;
}

複製程式碼

常規指令碼

伺服器不可能不當機的,當機重啟情況下,必要的服務必須重新啟用

自啟指令碼

nginx啟動

systenctl維護就好,systemctl enable nginx;

yum安裝的nginx,要用這個維護,自行寫一個systemctl規範的服務;

然後chmod 754這個指令碼,放到/usr/lib/systemd/system,即可用systemctl維護;

754 : rwx-rx-r => u-g-o => r(read[讀]:4)-x(excute[執行]:1)-w(write[寫]:2)

  • 瞅瞅官方的nginx service的寫法
# /usr/lib/systemd/system/nginx.service
# 除了一些欄位有比較多的引數,大體上都可以一目瞭然
# 服務描述, 文件路徑,服務型別,執行路徑,過載路徑以及程式PID這些

[Unit] 
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

複製程式碼

有一篇文章對這個說的很細緻: www.cnblogs.com/sparkdev/p/…

pm2跑專案

pm2發展至今,最新版的功能都比較完善了,是有內建自啟動機制的;

會識別linux的自啟動機制,比如發現我們用的是systemctl就會生成一份nginx.service的服務描述檔案

  1. pm2 start [services] : 啟動你的服務
  2. pm2 list: 看看服務是否正常執行

單機伺服器部署Nginx/Node/Nuxt/React/NG,常規優化及自啟指令碼

  1. pm2 save : 儲存當前正在執行的任務

單機伺服器部署Nginx/Node/Nuxt/React/NG,常規優化及自啟指令碼

  1. 加入到自啟動裡面

單機伺服器部署Nginx/Node/Nuxt/React/NG,常規優化及自啟指令碼


至於程式碼釋出

  • node的用pm2deploy(通過ssh釋出到遠端)

記得配置公鑰配對(遠端倉用git ssh模式),不然沒法初始化的,比如Coding

單機伺服器部署Nginx/Node/Nuxt/React/NG,常規優化及自啟指令碼

因為有測試下和正式線,所以我把配置寫成兩個,又為了減少敲打的程式碼,我寫了一堆alias

# 這些命令是啥?
# 看pm2文件 : https://pm2.io/doc/en/runtime/guide/easy-deploy-with-ssh/?utm_source=pm2&utm_medium=website&utm_campaign=rebranding

# 函式
# 為什麼兩個佔位符都是$1, 我不想寫太多,就部署名字和配置檔案一致,只有dev和prod模式
pm2init(){
   pm2 deploy ./ecosystem.$1.config.js $1 setup;
   pm2 deploy ./ecosystem.$1.config.js $1;
}
pm2up(){
  pm2 deploy ./ecosystem.$1.config.js $1 update;
}
pm2rev(){
  pm2 deploy ./ecosystem.$1.config.js $1 revert;
}



#pm2
alias pm2init=pm2init
alias pm2up=pm2up
alias pm2rev=pm2rev

# 用法就是 
# pm2init depoly_name => pm2init dev

複製程式碼

ecosystem.config.js


module.exports = {
  apps: [
    {
      name: 'stag-sx-share',
      script: 'npm',
      args: 'run start',
      watch: ['.nuxt'], // 監控輸出目錄
      watch_options: {
        usePolling: true
      },
      env: {
        HOST: '0.0.0.0',
        PORT: 3333,
        NODE_ENV: 'development'
      },
      env_production: {
        NODE_ENV: 'production',
        HOST: '0.0.0.0',
        PORT: 3333
      },
      output: './logs/console.log',
      error: './logs/consoleError.log',
      merge_logs: true,
      log_date_format: 'YYYY-MM-DD HH:mm Z'
    }
  ],
  deploy: {
    dev: {
      // SSH user
      user: 'root',
      // SSH host
      host: ['xxxx'],
      // SSH options with no command-line flag, see 'man ssh'
      // can be either a single string or an array of strings
      ssh_options: 'StrictHostKeyChecking=no',
      // GIT remote/branch
      ref: 'origin/master',
      // GIT remote
      repo: 'git@git.dev.tencent.com:lqh/nuxt-sx-mobile-share.git',
      // path in the server
      path: '/code/stag-nuxt-sx-share',
      // Pre-setup command or path to a script on your local machine
      'pre-setup': 'ls -la',
      'pre-deploy': 'git pull',
      // deploy hook
      'post-deploy':
        'npm install && pm2 reload ./ecosystem.dev.config.js --env production --force'
    }
  }
}


複製程式碼
  • 打包的,直接用rsync釋出

就拿我寫的一條alias來講解吧,還是挺方便的;

# rsync 的幾個引數
# -r : 就是recursive,遞迴,必須的,你打包的檔案不可能沒有子目錄吧!
# -c : 對檔案進行校驗,必備的,穩一點總好
# -h : --human-readable     輸出傳送的數值變化比較符合人類閱讀的格式
# -v : 就是verbose, 就是進展過程
# --progress : 顯示傳輸檔案的過程
# --delete : 從目標目錄刪除無關檔案,就是不匹配的檔案會被幹掉,多出來的!

alias fdumi="rsync -vrch --progress --delete  /Users/linqunhe/Code/umi_dva_sx_admin/dist/* root@xxx.xxx.xxx:/code/umi-dva-sx-admin/dev"
複製程式碼

總結

碼玩了就準備寫小程式了,新鮮剛出爐的大需求,準備用Taro寫,

taro 0.x的時候寫過一個,現在1.2都不知道變化如何了...

一個人的戰鬥一直都是那麼酸爽,感覺下一個接盤俠不好接,估計會全部被推倒重做

我先去踩踩坑, nest那個系列要延期了,年末的需求一直穿插追加...迷之微笑.

不過還好,估計到時候nest 6也出來了..不對之處請留言,會及時修正.謝謝閱讀

相關文章