启动报错

启动nginx服务时如果遇到这个错误 Job for nginx.service failed because the control process exited with error code. See “systemctl stat 可能原因如下

1.nginx配置文件有错误

运行下面命令查看修改
nginx -t

2.已经启动nginx或者配置文件中的端口号被占用

检查端口是否被占用
netstat -tnlp

如果端口已经被占用,自己权衡一下是换个端口还是把占用端口的进程杀掉
检查nginx是否已经启动
ps -aux | grep nginx

如果已经启动使用下面命令干掉即可

pkill -9 nginx

解决Nginx出现403 forbidden (13: Permission denied)报错

查看nginx日志,路径为/var/log/nginx/error.log。打开日志发现报错Permission denied,详细报错如下

"/app/index.html" is forbidden (13: Permission denied), client: 10.43.25.6, server: localhost, request: "GET / HTTP/1.1", host: "10.42.1.50"

由于启动用户和nginx工作用户不一致所致

# 查看nginx的启动用户,发现是nginx,而为是用root启动的
ps aux | grep nginx

# 显示如下:
nginx      1180  0.0  0.0 121164  3740 ?        S    14:03   0:00 nginx: worker process
nginx      1181  0.0  0.0 121164  3740 ?        S    14:03   0:00 nginx: worker process

# 将nginx.config的user改为和启动用户一致
vi conf/nginx.conf

# 修改如下:
# user  nginx;
user  root;

权限问题,如果nginx没有web目录的操作权限,也会出现403错误

# 修改权限
chmod -R 777 /app

SELinux设置为开启状态(enabled)的原因

# 查看当前selinux的状态
/usr/sbin/sestatus

# 显示如下:
SELinux status:                 enabled

# 将SELINUX=enforcing 修改为 SELINUX=disabled 状态
vi /etc/selinux/config

# 修改如下:
#SELINUX=enforcing
SELINUX=disabled

# 重启生效
reboot

AES 加密、解密

填充模式的区别

填充模式: PKCS7Padding/PKCS5Padding/ZeroPadding/NoPadding

某些加密算法要求明文需要按一定长度对齐,叫做块大小(BlockSize),比如16字节,那么对于一段任意的数据,加密前需要对最后一个块填充到16 字节,解密后需要删除掉填充的数据。

- ZeroPadding,数据长度不对齐时使用0填充,否则不填充。
- PKCS7Padding,假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都- 是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。
- PKCS5Padding,PKCS7Padding的子集,块大小固定为8字节。两者的区别在于PKCS5Padding是限制块大小的PKCS7Padding

由于使用PKCS7Padding/PKCS5Padding填充时,最后一个字节肯定为填充数据的长度,所以在解密后可以准确删除填充的数据,而使用ZeroPadding填充时,没办法区分真实数据与填充数据,所以只适合以\0结尾的字符串加解密

前端 crypto-js AES 加解密

# vue 使用 npm install crypto-js --save
# util.js
import Vue from 'vue';
import CryptoJS from 'crypto-js';
// 由于对称解密使用的算法是 AES-128-CBC算法,数据采用 PKCS#7 填充, BASE64输出, 字符集utf8, 因此这里的 key 需要为16位!
const key = CryptoJS.enc.Utf8.parse("1234123412ABCDEF");  //十六位十六进制数作为密钥
const iv = CryptoJS.enc.Utf8.parse('ABCDEF1234123412');   //十六位十六进制数作为密钥偏移量
/**
* 加密 AES + BASE64
* @param {*} word 
*/
export function encrypt(word) {
  var encrypted = CryptoJS.AES.encrypt(word, key, {
      iv: iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    });
  return String(encrypted);
};

/**
* 解密
* @param {*} word 
*/
export function decrypt(word) {
  var decrypt = CryptoJS.AES.decrypt(word, key, {
      iv: iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    });
  let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
  return decryptedStr;
};

后端 java AES 加解密

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;

public class AES {
//    密钥
    private static String keyWord = "1234123412ABCDEF";
//    密钥偏移量
    private static String iv = "ABCDEF1234123412";
    /**
    * 加密
    * @param src 加密字符串
    * @param key 密钥
    * @return 加密后的字符串
    */
    public static String Encrypt(String src, String key) throws Exception {
        // 判断密钥是否为空
        if (key == null) {
            key = keyWord;
//            System.out.print("密钥不能为空");
//            return null;
        }
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// 算法/模式/补码方式
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(iv.getBytes()));
        byte[] encrypted = cipher.doFinal(src.getBytes("utf-8"));
        return new Base64().encodeToString(encrypted);//base64
//        return binary(encrypted, 16); //十六进制
    }

    /**
    * 解密
    * @param src 解密字符串
    * @param key 密钥
    * @return 解密后的字符串
    */
    public static String Decrypt(String src, String key) throws Exception {
        try {
            // 判断Key是否正确
            if (key == null) {
                key = keyWord;
//            System.out.print("密钥不能为空");
//            return null;
            }
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(iv.getBytes()));

            byte[] encrypted1 = new Base64().decode(src);//base64
//            byte[] encrypted1 = toByteArray(src);//十六进制
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original,"utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    /**
    * 将byte[]转为各种进制的字符串
    * @param bytes byte[]
    * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
    * @return 转换后的字符串
    */
    public static String binary(byte[] bytes, int radix){
        return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
    }

    /**
    * 16进制的字符串表示转成字节数组
    *
    * @param hexString 16进制格式的字符串
    * @return 转换后的字节数组
    **/
    public static byte[] toByteArray(String hexString) {
        if (hexString.isEmpty())
            throw new IllegalArgumentException("this hexString must not be empty");

        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }

    public static void main(String[] args) throws Exception {
        // 密钥
        String key = "1234123412ABCDEF";
        // 需要加密的字符串
        String src = "123456";
        System.out.println(src);
        // 加密
        String enString = Encrypt(src, key);
        System.out.println("加密后的字串是:" + enString);
        // 解密
        String DeString = Decrypt(enString, key);
        System.out.println("解密后的字串是:" + DeString);
    }
}

POI word转html

maven配置

pom.xml
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>ooxml-schemas</artifactId>
    <version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>4.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/xdocreport -->
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>xdocreport</artifactId>
    <version>2.0.2</version>
</dependency>

异常 找不到org/apache/poi/POIXMLDocumentPart类

POIXMLDocumentPart已全版本更换放置的位置到org.apache.poi.ooxml包下,更新xdocreport至2.0.2
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>xdocreport</artifactId>
    <version>2.0.2</version>
</dependency>

Java代码

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;


import fr.opensagres.poi.xwpf.converter.core.*;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.w3c.dom.Document;

/**
* @ClassName DocConvertHtmlUtil
* @Description: word 转 html 工具类
* @Author huapisong
* @Date 2020/3/24
* @Version V1.0
**/
public class DocConvertHtmlUtil {
    private final static String tempPath = "E:\\srv\\apps\\data\\";

    public static void main(String[] args) throws ParserConfigurationException, TransformerException, IOException {
        String sourceFilePath = "E:\\home\\testPdfObject\\JL20012000000128.docx";
        String sourceFilePathDoc = "E:\\home\\testPdfObject\\CG2020032400002782.doc";
        String filePath = "E:\\srv\\apps\\data\\doc.html";
//        doc2Html(sourceFilePathDoc, filePath);
//        docConvertHtml(sourceFilePath);

        docxConvertHtml(sourceFilePath);
    }

    /**
    * docx 转 html
    * @param sourceFilePath 
    */
    public static void docxConvertHtml(String sourceFilePath) {

        try {
            String outPutFile = "E:\\srv\\apps\\data\\";
            String htmlName = "docx.html";
            String fileOutName = outPutFile;
            long startTime = System.currentTimeMillis();
            XWPFDocument document = new XWPFDocument(new FileInputStream(sourceFilePath));

            XHTMLOptions options = XHTMLOptions.create();
//            options.URIResolver(new BasicURIResolver(outPutFile));
            // 导出图片
//            File imageFolder = new File(outPutFile);
//            options.setExtractor(new FileImageExtractor(imageFolder));
            // URI resolver
//            options.setIgnoreStylesIfUnused(false);
//            options.setFragment(true);
            // Extract image
            //  File imageFolder = new File( FileTools.getInstance().getRoot() + savePath);
            IImageExtractor extractor = new IImageExtractor() {
                private String savePath = "";

                public IImageExtractor setSavePath(String savePath) {
                    this.savePath = savePath;
                    return this;
                }

                @Override
                public void extract(String arg0, byte[] arg1) throws IOException {
                    byte[] bytev = arg1;
                    String fileName = arg0.substring(arg0.lastIndexOf("/") + 1);
                    FileTools.getInstance().saveFile(savePath, fileName, bytev);
                }
            }.setSavePath(outPutFile);
            options.setExtractor(extractor);
            options.URIResolver(new IURIResolver() {
                private String savePath = "";

                public IURIResolver init(String savePath) {
                    this.savePath = savePath;
                    return this;
                }

                @Override
                public String resolve(String arg0) {
                    String fileName = arg0.substring(arg0.lastIndexOf("/") + 1);
                    return savePath + fileName + ".html";
                }
            }.init(outPutFile));
            // 3) 将 XWPFDocument转换成XHTML
            OutputStream out = new FileOutputStream(new File(outPutFile + htmlName));
            XHTMLConverter.getInstance().convert(document, out, options);

            System.out.println("Generate " + fileOutName + " with " + (System.currentTimeMillis() - startTime) + " ms.");

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
    * doc转换为html
    *
    * @param fileName
    * @param outPutFile
    * @throws TransformerException
    * @throws IOException
    * @throws ParserConfigurationException
    */
    public static void doc2Html(String fileName, String outPutFile) throws TransformerException, IOException, ParserConfigurationException {
        long startTime = System.currentTimeMillis();
        HWPFDocument wordDocument = new HWPFDocument(new FileInputStream(fileName));
        WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
        wordToHtmlConverter.setPicturesManager(new PicturesManager() {
            public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
                return "test/" + suggestedName;
            }
        });
        wordToHtmlConverter.processDocument(wordDocument);
        // 保存图片
        List<Picture> pics = wordDocument.getPicturesTable().getAllPictures();
        if (pics != null) {
            for (int i = 0; i < pics.size(); i++) {
                Picture pic = (Picture) pics.get(i);
                System.out.println();
                try {
                    pic.writeImageContent(new FileOutputStream(tempPath + pic.suggestFullFileName()));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        Document htmlDocument = wordToHtmlConverter.getDocument();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DOMSource domSource = new DOMSource(htmlDocument);
        StreamResult streamResult = new StreamResult(out);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer serializer = tf.newTransformer();
        serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
        serializer.setOutputProperty(OutputKeys.METHOD, "html");
        serializer.transform(domSource, streamResult);
        out.close();
        writeFile(new String(out.toByteArray()), outPutFile);
        System.out.println("Generate " + outPutFile + " with " + (System.currentTimeMillis() - startTime) + " ms.");
    }

    /**
    * 写文件
    *
    * @param content
    * @param path
    */
    public static void writeFile(String content, String path) {
        FileOutputStream fos = null;
        BufferedWriter bw = null;
        try {
            File file = new File(path);
            fos = new FileOutputStream(file);
            bw = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"));
            bw.write(content);
        } catch (FileNotFoundException fnfe) {
            fnfe.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } finally {
            try {
                if (bw != null)
                    bw.close();
                if (fos != null)
                    fos.close();
            } catch (IOException ie) {
            }
        }
    }

    /**
    * doc 转 html
    * @param sourceFilePath
    */
    public static void docConvertHtml(String sourceFilePath) {

        String filePath = "E:\\srv\\apps\\data\\";
        String htmlName = "doc.html";

        try {
            FileInputStream input = new FileInputStream(sourceFilePath);
            HWPFDocument wordDocument = new HWPFDocument(input);
            WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
            //解析word文档
            wordToHtmlConverter.processDocument(wordDocument);
            Document htmlDocument = wordToHtmlConverter.getDocument();
            File htmlFile = new File(filePath + htmlName);
            OutputStream outStream = new FileOutputStream(htmlFile);
            DOMSource domSource = new DOMSource(htmlDocument);
            StreamResult streamResult = new StreamResult(outStream);
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer serializer = factory.newTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty(OutputKeys.METHOD, "html");
            serializer.transform(domSource, streamResult);
            outStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    static class LocalFile{
        /**
        * 保存文件
        * @param fileName
        * @param foldPath
        * @param bins
        * @return
        */
        public static void saveFile(String foldPath,String fileName,byte[] bins){
            try {
                //data格式为:data:image/png;base64,iVBOR
                //以,分割
                StringBuilder filePath = new StringBuilder();
                filePath.append(foldPath).append(File.separatorChar).append(StringUtil.getUUID()).append(fileName);

                File localFile = new File(filePath.toString());
                FileOutputStream os = new FileOutputStream(localFile);
                os.write(bins);
                os.flush();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private static class FileTools {
        public static LocalFile getInstance() {
            return null;
        }
    }
}

nginx for windows

下载&准备

下载 http://nginx.org/en/download.html

文档 http://nginx.org/en/docs/windows.html

解压安装

配置启动

# 启动
cd c:\
unzip nginx-1.17.3.zip
cd nginx-1.17.3
start nginx

# 双击nginx.exe 启动

通过访问http://localhost:80,检查是否启动

Nginx在Windows环境下查看nginx进程

cmd命令窗口输入命令检查是否启动

$ tasklist -fi "imagename eq nginx.exe"

映像名称                       PID 会话名              会话#       内存使用
========================= ======== ================ =========== ============
nginx.exe                     3716 Console                    1      7,432 K
nginx.exe                     3204 Console                    1      7,596 K
# 强制杀进程
taskkill /PID 10920 /F

nginx的配置文件是conf目录下的nginx.conf,默认配置的nginx监听的端口为80,如果80端口被占用可以修改为未被占用的端口即可
检查80端口是否被占用的命令是:

netstat -ano | findstr 0.0.0.0:80
# 或
netstat -ano | findstr "80"

当我们修改了nginx的配置文件nginx.conf 时,不需要关闭nginx后重新启动nginx,只需要执行命令 nginx -s reload 即可让改动生效

nginx -s stop 快速退出
nginx -s quit 优雅退出
nginx -s reload 更换配置,启动新的工作进程,优雅的关闭以往的工作进程
nginx -s reopen 重新打开日志文件

设置debug的日志级别

# 配置文件中设置error_log的级别为:
error_log  logs/error.log  debug;

Windows temp 的修改和清除

修改 temp 位置

  • 1.windows临时文件夹分布在三个地方,1:C:\WINDOWS\Temp,这是系统公用的
  • 2.还有一个在当前登录账户的配置文件夹下,一般是C:\Users\登录的帐号\AppData\Local\Temp

它们都在C盘里面,这样对于控制磁盘碎片是很不利的,所以我们首先要做的就是把Temp统一移到C盘之外的分区,这里以D盘为例。

1.在D盘建立D:\AppData\Local\Temp目录
2.右击”我的电脑”,”属性”,”高级”,打开“环境变量”对话框,将用户变量和系统变量”TEMP”和”TMP” 的值 “%USERPROFILE%\AppData\Local\Temp” 改为 “D:\AppData\Local\Temp”。

清空 temp

新建一个文本文档 CleanTEMP.bat,在里面写入两行指令:

1
2
RD %TEMP% /S/Q
MKDIR %TEMP%

双击CleanTEMP.bat文件就自动清空Temp文件夹了。

启动、关机 清空temp

打开组策略(运行gpedit.msc),依次打开“计算机配置-Windows 设置-脚本(启动/关机)”,然后随便打开“启动”或“关机”,效果一样,一个是登录时清空Temp一个是关机时清空,这里我选择“关机”。点击“添加”把刚才做好的*.bat(CleanTEMP.bat)文件导入,点“确定”后一切就搞定了。

Bash 常用命令

基础常用命令

  • 某个命令 --h,对这个命令进行解释
  • 某个命令 --help,解释这个命令(更详细)
  • man某个命令,文档式解释这个命令(更更详细)(执行该命令后,还可以按/+关键字进行查询结果的搜索)
  • Ctrl + c,结束命令
  • TAB键,自动补全命令(按一次自动补全,连续按两次,提示所有以输入开头字母的所有命令)
  • 键盘上下键,输入临近的历史命令
  • history,查看所有的历史命令
  • Ctrl + r,进入历史命令的搜索功能模式
  • clear,清除屏幕里面的所有命令
  • pwd,显示当前目录路径(常用)
  • firefox&,最后后面的 & 符号,表示使用后台方式打开 Firefox,然后显示该进程的 PID 值
  • jobs,查看后台运行的程序列表
  • ifconfig,查看内网 IP 等信息(常用)
  • curl ifconfig.me,查看外网 IP 信息
  • curl ip.cn,查看外网 IP 信息
  • locate 搜索关键字,快速搜索系统文件/文件夹(类似 Windows 上的 everything 索引式搜索)(常用)
    • updatedb,配合上面的 locate,给 locate 的索引更新(locate 默认是一天更新一次索引)(常用)
  • date,查看系统时间(常用)
    • date -s20080103,设置日期(常用)
    • date -s18:24,设置时间,如果要同时更改 BIOS 时间,再执行 hwclock --systohc(常用)
  • cal,在终端中查看日历,肯定没有农历显示的
  • uptime,查看系统已经运行了多久,当前有几个用户等信息(常用)
  • cat 文件路名,显示文件内容(属于打印语句)
  • cat -n 文件名,显示文件,并每一行内容都编号
  • more 文件名,用分页的方式查看文件内容(按 space 翻下一页,按 Ctrl + B 返回上页)
  • less文件名,用分页的方式查看文件内容(带上下翻页)
    • j 向下移动,按 k 向上移动
    • / 后,输入要查找的字符串内容,可以对文件进行向下查询,如果存在多个结果可以按 n 调到下一个结果出
    • 后,输入要查找的字符串内容,可以对文件进行向上查询,如果存在多个结果可以按 n 调到下一个结果出
  • shutdown
    • shutdown -hnow,立即关机
    • shutdown -h+10,10 分钟后关机
    • shutdown -h23:30,23:30 关机
    • shutdown -rnew,立即重启
  • poweroff,立即关机(常用)
  • reboot,立即重启(常用)
  • zip mytest.zip /opt/test/,把 /opt 目录下的 test/ 目录进行压缩,压缩成一个名叫 mytest 的 zip 文件
    • unzip mytest.zip,对 mytest.zip 这个文件进行解压,解压到当前所在目录
    • unzip mytest.zip -d /opt/setups/,对 mytest.zip 这个文件进行解压,解压到 /opt/setups/ 目录下
  • tar -cvf mytest.tar mytest/,对 mytest/ 目录进行归档处理(归档和压缩不一样)
  • tar -xvf mytest.tar,释放 mytest.tar 这个归档文件,释放到当前目录
    • tar -xvf mytest.tar -C /opt/setups/,释放 mytest.tar 这个归档文件,释放到 /opt/setups/ 目录下
  • last,显示最近登录的帐户及时间
  • lastlog,显示系统所有用户各自在最近登录的记录,如果没有登录过的用户会显示 从未登陆过
  • ls,列出当前目录下的所有没有隐藏的文件 / 文件夹。
    • ls -a,列出包括以.号开头的隐藏文件 / 文件夹(也就是所有文件)
    • ls -R,显示出目录下以及其所有子目录的文件 / 文件夹(递归地方式,不显示隐藏的文件)
    • ls -a -R,显示出目录下以及其所有子目录的文件 / 文件夹(递归地方式,显示隐藏的文件)
    • ls -al,列出目录下所有文件(包含隐藏)的权限、所有者、文件大小、修改时间及名称(也就是显示详细信息)
    • ls -ld 目录名,显示该目录的基本信息
    • ls -t,依照文件最后修改时间的顺序列出文件名。
    • ls -F,列出当前目录下的文件名及其类型。以 / 结尾表示为目录名,以 * 结尾表示为可执行文件,以 @ 结尾表示为符号连接
    • ls -lg,同上,并显示出文件的所有者工作组名。
    • ls -lh,查看文件夹类文件详细信息,文件大小,文件修改时间
    • ls /opt | head -5,显示 opt 目录下前 5 条记录
    • ls -l | grep '.jar',查找当前目录下所有 jar 文件
    • ls -l /opt |grep "^-"|wc -l,统计 opt 目录下文件的个数,不会递归统计
    • ls -lR /opt |grep "^-"|wc -l,统计 opt 目录下文件的个数,会递归统计
    • ls -l /opt |grep "^d"|wc -l,统计 opt 目录下目录的个数,不会递归统计
    • ls -lR /opt |grep "^d"|wc -l,统计 opt 目录下目录的个数,会递归统计
    • ls -lR /opt |grep "js"|wc -l,统计 opt 目录下 js 文件的个数,会递归统计
    • ls -l,列出目录下所有文件的权限、所有者、文件大小、修改时间及名称(也就是显示详细信息,不显示隐藏文件)。显示出来的效果如下:
1
2
3
-rwxr-xr-x. 1 root root 4096 3月 26 10:57,其中最前面的 - 表示这是一个普通文件
lrwxrwxrwx. 1 root root 4096 3月 26 10:57,其中最前面的 l 表示这是一个链接文件,类似 Windows 的快捷方式
drwxr-xr-x. 5 root root 4096 3月 26 10:57,其中最前面的 d 表示这是一个目录
  • cd,目录切换
    • cd ..,改变目录位置至当前目录的父目录(上级目录)。
    • cd ~,改变目录位置至用户登录时的工作目录。
    • cd 回车,回到家目录
    • cd -,上一个工作目录
    • cd dir1/,改变目录位置至 dir1 目录下。
    • cd ~user,改变目录位置至用户的工作目录。
    • cd ../user,改变目录位置至相对路径user的目录下。
    • cd /../..,改变目录位置至绝对路径的目录位置下。
  • cp 源文件 目标文件,复制文件
    • cp -r 源文件夹 目标文件夹,复制文件夹
    • cp -r -v 源文件夹 目标文件夹,复制文件夹(显示详细信息,一般用于文件夹很大,需要查看复制进度的时候)
    • cp /usr/share/easy-rsa/2.0/keys/{ca.crt,server.{crt,key},dh2048.pem,ta.key} /etc/openvpn/keys/,复制同目录下花括号中的文件
  • tar cpf - . | tar xpf - -C /opt,复制当前所有文件到 /opt 目录下,一般如果文件夹文件多的情况下用这个更好,用 cp 比较容易出问题
  • mv 文件 目标文件夹,移动文件到目标文件夹
    • mv 文件,不指定目录重命名后的名字,用来重命名文件
  • touch 文件名,创建一个空白文件/更新已有文件的时间(后者少用)
  • mkdir 文件夹名,创建文件夹
  • mkdir -p /opt/setups/nginx/conf/,创建一个名为 conf 文件夹,如果它的上级目录 nginx 没有也会跟着一起生成,如果有则跳过
  • rmdir 文件夹名,删除文件夹(只能删除文件夹里面是没有东西的文件夹)
  • rm 文件,删除文件
    • rm -r 文件夹,删除文件夹
    • rm -r -i 文件夹,在删除文件夹里的文件会提示(要的话,在提示后面输入yes)
    • rm -r -f 文件夹,强制删除
    • rm -r -f 文件夹1/ 文件夹2/ 文件夹3/删除多个
  • find,高级查找
    • find . -name *lin*,其中 . 代表在当前目录找,-name 表示匹配文件名 / 文件夹名,*lin* 用通配符搜索含有lin的文件或是文件夹
    • find . -iname *lin*,其中 . 代表在当前目录找,-iname 表示匹配文件名 / 文件夹名(忽略大小写差异),*lin* 用通配符搜索含有lin的文件或是文件夹
    • find / -name *.conf,其中 / 代表根目录查找,*.conf代表搜索后缀会.conf的文件
    • find /opt -name .oh-my-zsh,其中 /opt 代表目录名,.oh-my-zsh 代表搜索的是隐藏文件 / 文件夹名字为 oh-my-zsh 的
    • find /opt -type f -iname .oh-my-zsh,其中 /opt 代表目录名,-type f 代表只找文件,.oh-my-zsh 代表搜索的是隐藏文件名字为 oh-my-zsh 的
    • find /opt -type d -iname .oh-my-zsh,其中 /opt 代表目录名,-type d 代表只找目录,.oh-my-zsh 代表搜索的是隐藏文件夹名字为 oh-my-zsh 的
    • find . -name "lin*" -exec ls -l {} \;,当前目录搜索lin开头的文件,然后用其搜索后的结果集,再执行ls -l的命令(这个命令可变,其他命令也可以),其中 -exec 和 {} \; 都是固定格式
    • find /opt -type f -size +800M -print0 | xargs -0 du -h | sort -nr,找出 /opt 目录下大于 800 M 的文件
    • find / -name "*tower*" -exec rm {} \;,找到文件并删除
    • find / -name "*tower*" -exec mv {} /opt \;,找到文件并移到 opt 目录
    • find . -name "*" |xargs grep "youmeek",递归查找当前文件夹下所有文件内容中包含 youmeek 的文件
    • find . -size 0 | xargs rm -f &,删除当前目录下文件大小为0的文件
    • du -hm --max-depth=2 | sort -nr | head -12,找出系统中占用容量最大的前 12 个目录
  • cat /etc/resolv.conf,查看 DNS 设置
  • netstat -tlunp,查看当前运行的服务,同时可以查看到:运行的程序已使用端口情况
  • env,查看所有系统变量
  • export,查看所有系统变量
  • echo
    • echo $JAVA_HOME,查看指定系统变量的值,这里查看的是自己配置的 JAVA_HOME。
    • echo "字符串内容",输出 “字符串内容”
    • echo > aa.txt,清空 aa.txt 文件内容(类似的还有:: > aa.txt,其中 : 是一个占位符, 不产生任何输出)
  • unset $JAVA_HOME,删除指定的环境变量
  • ln -s /opt/data /opt/logs/data,表示给 /opt/logs 目录下创建一个名为 data 的软链接,该软链接指向到 /opt/data
  • grep
    • shell grep -H '安装' *.sh,查找当前目录下所有 sh 类型文件中,文件内容包含 安装 的当前行内容
    • grep 'test' java*,显示当前目录下所有以 java 开头的文件中包含 test 的行
    • grep 'test' spring.ini docker.sh,显示当前目录下 spring.ini docker.sh 两个文件中匹配 test 的行
  • ps
    • ps –ef|grep java,查看当前系统中有关 java 的所有进程
    • ps -ef|grep --color java,高亮显示当前系统中有关 java 的所有进程
  • kill
    • kill 1234,结束 pid 为 1234 的进程
    • kill -9 1234,强制结束 pid 为 1234 的进程(慎重)
    • killall java,结束同一进程组内的所有为 java 进程
    • ps -ef|grep hadoop|grep -v grep|cut -c 9-15|xargs kill -9,结束包含关键字 hadoop 的所有进程
  • head
    • head -n 10 spring.ini,查看当前文件的前 10 行内容
  • tail
    • tail -n 10 spring.ini,查看当前文件的后 10 行内容
    • tail -200f 文件名,查看文件被更新的新内容尾 200 行,如果文件还有在新增可以动态查看到(一般用于查看日记文件)

用户、权限-相关命令

  • 使用 pem 证书登录:ssh -i /opt/mykey.pem root@192.168.0.70
    • 证书权限不能太大,不然无法使用:chmod 600 mykey.pem
  • hostname,查看当前登陆用户全名
  • cat /etc/group,查看所有组
  • cat /etc/passwd,查看所有用户
  • groups youmeek,查看 youmeek 用户属于哪个组
  • useradd youmeek -g judasn,添加用户并绑定到 judasn 组下
  • userdel -r youmeek,删除名字为 youmeek 的用户
    • 参数:-r,表示删除用户的时候连同用户的家目录一起删除
  • 修改普通用户 youmeek 的权限跟 root 权限一样:

    • 常用方法(原理是把该用户加到可以直接使用 sudo 的一个权限状态而已):
    • 编辑配置文件:vim /etc/sudoers
    • 找到 98 行(预估),有一个:root ALL=(ALL) ALL,在这一行下面再增加一行,效果如下:
    1
    2
    root  ALL=(ALL)   ALL
    youmeek ALL=(ALL) ALL
    • 另一种方法:
    • 编辑系统用户的配置文件:vim /etc/passwd,找到 rootyoumeek 各自开头的那一行,比如 root 是:root:x:0:0:root:/root:/bin/zsh,这个代表的含义为:用户名:密码:UserId:GroupId:描述:家目录:登录使用的 shell
    • 通过这两行对比,我们可以直接修改 youmeek 所在行的 UserId 值 和 GroupId 值,都改为 0。
  • groupadd judasn,添加一个名为 judasn 的用户组
  • groupdel judasn,删除一个名为 judasn 的用户组(前提:先删除组下面的所有用户)
  • usermod 用户名 -g 组名,把用户修改到其他组下
  • passwd youmeek,修改 youmeek 用户的密码(前提:只有 root 用户才有修改其他用户的权限,其他用户只能修改自己的)
  • chmod 777 文件名/目录,给指定文件增加最高权限,系统中的所有人都可以进行读写。
    • linux 的权限分为 rwx。r 代表:可读,w 代表:可写,x 代表:可执行
    • 这三个权限都可以转换成数值表示,r = 4,w = 2,x = 1,- = 0,所以总和是 7,也就是最大权限。第一个 7 是所属主(user)的权限,第二个 7 是所属组(group)的权限,最后一位 7 是非本群组用户(others)的权限。
    • chmod -R 777 目录 表示递归目录下的所有文件夹,都赋予 777 权限
  • su:切换到 root 用户,终端目录还是原来的地方(常用)
    • su -:切换到 root 用户,其中 - 号另起一个终端并切换账号
    • su 用户名,切换指定用户帐号登陆,终端目录还是原来地方。
    • su - 用户名,切换到指定用户帐号登陆,其中 - 号另起一个终端并切换账号
  • exit,注销当前用户(常用)
  • sudo 某个命令,使用管理员权限使用命令,使用 sudo 回车之后需要输入当前登录账号的密码。(常用)
  • passwd,修改当前用户密码(常用)
  • 添加临时账号,并指定用户根目录,并只有可读权限方法
    • 添加账号并指定根目录(用户名 tempuser):useradd -d /data/logs -m tempuser
    • 设置密码:passwd tempuser 回车设置密码
    • 删除用户(该用户必须退出 SSH 才能删除成功),也会同时删除组:userdel tempuser

磁盘管理

  • df -h,自动以合适的磁盘容量单位查看磁盘大小和使用空间
    • df -k,以磁盘容量单位 K 为数值结果查看磁盘使用情况
    • df -m,以磁盘容量单位 M 为数值结果查看磁盘使用情况
  • du -sh /opt,查看 opt 这个文件夹大小 (h 的意思 human-readable 用人类可读性较好方式显示,系统会自动调节单位,显示合适大小的单位)
  • du -sh ./*,查看当前目录下所有文件夹大小 (h 的意思 human-readable 用人类可读性较好方式显示,系统会自动调节单位,显示合适大小的单位)
  • du -sh /opt/setups/,显示 /opt/setups/ 目录所占硬盘空间大小(s 表示 –summarize 仅显示总计,即当前目录的大小。h 表示 –human-readable 以 KB,MB,GB 为单位,提高信息的可读性)
  • mount /dev/sdb5 /newDir/,把分区 sdb5 挂载在根目录下的一个名为 newDir 的空目录下,需要注意的是:这个目录最好为空,不然已有的那些文件将看不到,除非卸载挂载。
    • 挂载好之后,通过:df -h,查看挂载情况。
  • umount /newDir/,卸载挂载,用目录名
    • 如果这样卸载不了可以使用:umount -l /newDir/
  • umount /dev/sdb5,卸载挂载,用分区名

wget 下载文件

  • 常规下载:wget http://www.gitnavi.com/index.html
  • 自动断点下载:wget -c http://www.gitnavi.com/index.html
  • 后台下载:wget -b http://www.gitnavi.com/index.html
  • 伪装代理名称下载:wget --user-agent="Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16" http://www.gitnavi.com/index.html
  • 限速下载:wget --limit-rate=300k http://www.gitnavi.com/index.html
  • 批量下载:wget -i /opt/download.txt,一个下载地址一行
  • 后台批量下载:wget -b -c -i /opt/download.txt,一个下载地址一行

其他常用命令

  • 编辑 hosts 文件:vim /etc/hosts,添加内容格式:127.0.0.1 www.youmeek.com
  • RPM 文件操作命令:
    • 安装
      • rpm -i example.rpm,安装 example.rpm 包
      • rpm -iv example.rpm,安装 example.rpm 包并在安装过程中显示正在安装的文件信息
      • rpm -ivh example.rpm,安装 example.rpm 包并在安装过程中显示正在安装的文件信息及安装进度
    • 查询
      • rpm -qa | grep jdk,查看 jdk 是否被安装
      • rpm -ql jdk,查看 jdk 是否被安装
    • 卸载
      • rpm -e jdk,卸载 jdk(一般卸载的时候都要先用 rpm -qa 看下整个软件的全名)
  • YUM 软件管理:
    • yum install -y httpd,安装 apache
    • yum remove -y httpd,卸载 apache
    • yum info -y httpd,查看 apache 版本信息
    • yum list --showduplicates httpd,查看可以安装的版本
    • yum install httpd-查询到的版本号,安装指定版本
    • 更多命令可以看:http://man.linuxde.net/yum
  • 查看某个配置文件,排除掉里面以 # 开头的注释内容:
    • grep '^[^#]' /etc/openvpn/server.conf
  • 查看某个配置文件,排除掉里面以 # 开头和 ; 开头的注释内容:
    • grep '^[^#;]' /etc/openvpn/server.conf

Vim 安装和配置、优化

Vim 介绍

Vim 安装

Vim 配置(CentOS 环境)

  • 编辑配置文件是:sudo vim /etc/vimrc

Vim 基础快捷键

  • 注意
    • 严格区分字母大小写
    • 含有 Ctrl 字眼都表示 Ctrl 键盘按钮
    • 特定符号需要配合 Shift 键,比如字母键盘区上面的数字区:!@#%%^&*()
    • 要按出冒号键 : 也是需要 Shift 的
  • 移动
    • j,下
    • k,上
    • h,左
    • l,右
    • v,按 v 之后按方向键可以选中你要选中的文字
    • gg,跳到第 1 行
    • G,跳到最后一行
    • 16G:16,跳到第 16 行
    • $,到本行 行尾
    • 0,到本行 行头
    • w,到下一个单词的 开头
    • e,到下一个单词的 结尾
    • Ctrl + u,向文件 首翻 半屏
    • Ctrl + d,向文件 尾翻 半屏
    • Ctrl + f,向文件 尾翻 一屏
    • Ctrl + b,向文件 首翻 一屏
    • *,匹配光标当前所在的单词,移动光标到 下一个 匹配单词
    • #,匹配光标当前所在的单词,移动光标到 上一个 匹配单词
    • ^,到本行第一个单词头
    • g_,到本行最后一个单词尾巴
    • %,匹配括号移动,包括 (、{、[
  • 插入
    • I,在当前 行首 插入
    • A,在当前 行尾 插入
    • i,在当前字符的 左边 插入
    • a,在当前字符的 右边 插入
    • o,在当前行 下面 插入一个新行
    • O,在当前行 上面 插入一个新行
  • 编辑
    • 删除
    • x,删除 光标后 的 1 个字符
    • 2x,删除 光标后 的 2 个字符
    • X,删除 光标前 的 1 个字符
    • 2X,删除 光标前 的 2 个字符
    • dd,删除当前行
    • cc,删除当前行后进入 insert 模式
    • dw,删除当前光标下的单词/空格
    • d$,删除光标至 行尾 所有字符
    • dG,删除光标至 文件尾 所有字符
    • 3dd,从当前光标开始,删掉 3 行
    • echo > aa.txt,从 bash 角度清空文件内容,这个比较高效
    • 复制
    • y,复制光标所选字符
    • yw,复制光标后单词
    • yy,复制当前行
    • 4yy,复制当前行及下面 4 行
    • y$,复制光标位置至 行尾 的内容
    • y^,复制光标位置至 行首 的内容
    • 粘贴
    • p,将粘贴板中内容复制到 光标之后
    • P,将粘贴板中内容复制到 光标之前
    • 其他
      • ddp,交换当前光标所在行和下一行的位置
      • u,撤销
      • :wq,退出并 保存
      • :q!,退出并 不保存
      • Ctrl + v,进入 Vim 列编辑
      • guu,把当前行的字母全部转换成 小写
      • gUU,把当前行的字母全部转换成 大写
      • g~~,把当前行的字母是大写的转换成小写,是小写的转换成大写
      • :saveas /opt/setups/text.txt,另存到 /opt/setups/text.txt
  • 搜索
    • /YouMeek,从光标开始处向文件尾搜索 YouMeek 字符,按 n 继续向下找,按 N 继续向上找
    • ?YouMeek,从光标开始处向文件首搜索 YouMeek 字符,按 n 继续向下找,按 N 继续向上找
  • 替换
    • :%s/YouMeek/Judasn/g,把文件中所有 YouMeek 替换为:Judasn
    • :%s/YouMeek/Judasn/,把文件中所有行中第一个 YouMeek 替换为:Judasn
    • :s/YouMeek/Judasn/,把光标当前行第一个 YouMeek 替换为 Judasn
    • :s/YouMeek/Judasn/g,把光标当前行所有 YouMeek 替换为 Judasn
    • :s#YouMeek/#Judasn/#,除了使用斜杠作为分隔符之外,还可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符,该命令表示:把光标当前行第一个 YouMeek/ 替换为 Judasn/
    • :10,31s/YouMeek/Judasn/g,把第 10 行到 31 行之间所有 YouMeek 替换为 Judasn

Vim 的特殊复制、黏贴

  • Vim 提供了 12 个剪贴板,分别是:0,1,2,3,4,5,6,7,8,9,a,",默认采用的是 ",也就是双引号,可能你初读感觉很奇怪。你可以用 Vim 编辑某个文件,然后输入::reg。你可以看到如下内容:
    • vim
  • 复制到某个剪切板的命令:"7y,表示使用 7 号剪切板。
  • 黏贴某个剪切板内容:"7p,表示使用 7 号剪切板内容进行黏贴

Vim 配置

  • 我个人本地不使用 Vim 的,基本上都是在操作服务器的时候使用,所以这里推荐这个配置文件
    • vim-for-server
    • 在假设你已经备份好你的 Vim 配置文件后,使用该配置文件:curl https://raw.githubusercontent.com/wklken/vim-for-server/master/vimrc > ~/.vimrc
    • 效果如下:
      • vim-for-server
  • 需要特别注意的是,如果你平时粘贴内容到终端 Vim 出现缩进错乱,一般需要这样做:
    • 进入 vim 后,按 F5,然后 shift + insert 进行粘贴。这种事就不会错乱了。
    • 原因是:vim ~/.vimrc 中有一行这样的设置:set pastetoggle=<F5>

其他常用命令

  • 对两个文件进行对比:vimdiff /opt/1.txt /opt/2.txt

hexo页脚添加访客人数和总访问量

昨天刚刚为博客添加了页脚显示访客人数和总访问量的功能,今天整理一下为hexo博客添加页脚访客人数和总访问量的两种方法,本人使用的是不蒜子来进行统计的。

首先还是得先说一下基本配置:hexo搭建博客,使用NexT主题,利用不蒜子来进行统计,然后进入正题
基本介绍

“不蒜子”与百度统计谷歌分析等有区别:“不蒜子”可直接将访问次数显示在您在网页上(也可不显示);对于已经上线一段时间的网站,“不蒜子”允许您初始化首次数据。

不蒜子就是那么一款记录访客和访问量的插件,接下来就介绍两种使用不蒜子计数的方法。
一、脚本方法使用不蒜子计数
1.安装脚本(必选)

要使用不蒜子必须在页面中引入busuanzi.js,代码如下:

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

本人使用的是next主题,所以在themes/next/layout/_partial/footer.swig中添加上述脚本,也可以把脚本添加在header中,如果使用的是其他主题,大致也是一样的,不过可能后缀是ejs,没有影响。
2.安装标签(可选)

要显示站点总访问量,复制以下代码添加到你需要显示的位置。有两种算法可选:

算法a:pv的方式,单个用户连续点击n篇文章,记录n次访问量。

<span id="busuanzi_container_site_pv">
    本站总访问量<span id="busuanzi_value_site_pv"></span>次
</span>

算法b:uv的方式,单个用户连续点击n篇文章,只记录1次访客数。

<span id="busuanzi_container_site_uv">
本站访客数<span id="busuanzi_value_site_uv"></span>人次
</span>

3.安装教程

一般显示站点访问量在页脚,所以我们选择在footer.swig中添加标签,同时我们还可以通过修改主题配置来方便选择是否显示访问量,步骤如下:首先,我们在next主题下的_config.yml中加入以下配置:

# visitors count
counter: true

之后可以更改counter的值为false来隐藏页脚的访问量统计,然后,我们在themes/next/layout/_partial/footer.swig中添加以下代码:

{% if theme.footer.counter %}
        
        本站总访问量
        
        本站访客数
    {% endif %}

这样便可以在底部显示访问量了,并且可以通过更改主题配置中的参数来选择是否显示访问量,只要引入busuanzi.js之后,即使不显示访问量也会统计。
二、配置方式使用不蒜子计数

第一种引入脚本的方法适用于任何类型的个人站点,如果你使用的主题是NexT,那么你可以很方便的进行不蒜子的访客统计设置,仅仅只需要一步:

打开主题的配置文件/theme/next/_config.yml,找到如下配置:

# Show PV/UV of the website/page with busuanzi.
# Get more information on http://ibruce.info/2015/04/04/busuanzi/
busuanzi_count:
# count values only if the other configs are false
enable: false
# custom uv span for the whole site
site_uv: true
site_uv_header: <i class="fa fa-user"></i>
site_uv_footer:
# custom pv span for the whole site
site_pv: true
site_pv_header: <i class="fa fa-eye"></i>
site_pv_footer:
# custom pv span for one page only
page_pv: true
page_pv_header: <i class="fa fa-file-o"></i>
page_pv_footer:

将enable的值由false改为true,便可以看到页脚出现访问量,上述配置表示:

site_uv表示是否显示整个网站的UV数
site_pv表示是否显示整个网站的PV数
page_pv表示是否显示每个页面的PV数
当然,对于不蒜子的配置可以随意更改,一下附上本人的配置:

# Show PV/UV of the website/page with busuanzi.
# Get more information on http://ibruce.info/2015/04/04/busuanzi/
busuanzi_count:
# count values only if the other configs are false
enable: true
# custom uv span for the whole site
site_uv: true
site_uv_header: 访客数
site_uv_footer: 人
# custom pv span for the whole site
site_pv: true
site_pv_header: 总访问量
site_pv_footer: 次
# custom pv span for one page only
page_pv: true
page_pv_header: <i class="fa fa-file-o"></i>  阅读数
page_pv_footer:

注意事项

两种方法选择一种使用即可,都使用可能会出现无法显示的问题
使用hexo s部署在本地预览效果的时候,uv数和pv数会过大,这是由于不蒜子用户使用一个存储空间,所以使用localhost:4000进行本地预览的时候会导致数字异常,这是正常现象,只需要将博客部署至云端即可恢复正常。
网站运行一段时间后想要初始化访问次数,官方回答是可以注册登录自行修改阅读次数,但是我登录官网依旧显示无法注册,如果有方法可以在评论中指出。

以上hexo统计访客的方法属于个人整理,如果有错误欢迎在评论中指出。

黑客入侵检查

思路

  • 扫描木马工具:clamAV
    官网:http://pkgs.repoforge.org/clamav/
  • CentOS 安装:yum install -y clamav*
  • 启动 clamAV 服务:service clamd restart
  • 更新病毒库:freshclam
  • 扫描方法:
    • 扫描 /etc 目录,并把扫描结果放在 /root 目录下:clamscan -r /etc –max-dir-recursion=5 -l /root/etcclamav.log
    • 扫描 /bin 目录,并把扫描结果放在 /root 目录下:clamscan -r /bin –max-dir-recursion=5 -l /root/binclamav.log
    • 扫描 /usr 目录,并把扫描结果放在 /root 目录下:clamscan -r /usr –max-dir-recursion=5 -l /root/usrclamav.log
  • 如果日志有类似内容,表示有木马病毒:
    • /usr/bin/.sshd: Linux.Trojan.Agent FOUND
    • /usr/sbin/ss: Linux.Trojan.Agent FOUND
    • /usr/sbin/lsof: Linux.Trojan.Agent FOUND
  • 看下当前有多少登录者:who
  • 看下最近有哪些登录者:last
  • 查看最近尝试登录的账号信息:grep “sshd” /var/log/secure
    • 很多这种信息就表示有人在不断地尝试用 root 登录:Failed password for root from 222.186.56.168 port 4080 ssh2
  • 查看最近登录成功的账号信息:grep “Accepted” /var/log/secure,可以看到:pop3, ssh, telnet, ftp 类型
  • 看下查看系统资源占用有无异常:top
  • 看下所有进程:ps aux
  • 查看当前系统登录者有哪些,及其登录记录:last | more
  • 把最近执行的所有命令输出到一个文件,然后下载下来细细研究:history >> /opt/test.txt
  • 查看当前系统所有用户有哪些:cat /etc/passwd |awk -F \: ‘{print $1}’
    • 更多详细可以用:cat /etc/passwd
  • 查看开放的端口,比如常用的80,22,8009,后面的箭头表示端口对应占用的程序:netstat -lnp
  • 检查某个端口的具体信息:lsof -i :18954
  • 检查启动项:chkconfig
  • 检查定时器(重要):cat /etc/crontab
  • 检查定时器(重要):crontab -l
    • vim /var/spool/cron/crontabs/root
    • vim /var/spool/cron/root
  • 检查其他系统重要文件:
    • cat /etc/rc.local
    • cd /etc/init.d;ll
  • 检查文件:
    • find / -uid 0 –perm -4000 –print
    • find / -size +10000k –print
    • find / -name “…” –print
    • find / -name “.. “ –print
    • find / -name “. “ –print
    • find / -name “ “ –print
  • 下载 iftop 分析流量,查看是否被黑客当做肉鸡使用
  • 安装 iftop
  • 运行:iftop
    • 显示端口与 IP 信息:iftop -nP
1
2
3
4
5
6
7
8
9
10
11
中间部分:外部连接列表,即记录了哪些ip正在和本机的网络连接

右边部分:实时参数分别是该访问 ip 连接到本机 2 秒,10 秒和 40 秒的平均流量

=> 代表发送数据,<= 代表接收数据

底部会显示一些全局的统计数据,peek 是指峰值情况,cumm 是从 iftop 运行至今的累计情况,而 rates 表示最近 2 秒、10 秒、40 秒内总共接收或者发送的平均网络流量。

TX:(发送流量) cumm: 143MB peak: 10.5Mb rates: 1.03Mb 1.54Mb 2.10Mb
RX:(接收流量) 12.7GB 228Mb 189Mb 191Mb 183Mb
TOTAL:(总的流量) 12.9GB 229Mb 190Mb 193Mb 185MbW
  • 禁用 root 账号登录:vim /etc/ssh/sshd_config
    把 PermitRootLogin 属性 yes 改为 no
  • 如果安全度要更高,可以考虑禁用口令登录,采用私钥/公钥方式:vim /etc/ssh/sshd_config
    设置属性:PasswordAuthentication 为 no
  • 如果还要限制指定 IP 登录,可以考虑编辑:hosts.allow 和 hosts.deny 两个文件
  • 重要系统软件更新(更新之前最好先做好系统镜像或是快照,以防万一):
1
2
3
4
5
6
7
yum update kernel
yum update kernel-devel
yum update kernel-firmware
yum update kernel-headers
yum update openssh
yum update openssh-clients
yum update openssh-server

实战
挖矿程序

  • 先查看调度任务是否有新增内容
    • vim /var/spool/cron/root
    • vim /var/spool/cron/crontabs/root
  • 如果有,先停止定时任务:systemctl stop crond
  • 如果对方有去 wget curl 指定网站,则先在 hosts 里面映射为 127.0.0.1,比如:127.0.0.1 prax0zma.ru
    • 查看当前最占用 CPU 的进程 PID,加入发现是 22935,则:cd /proc/22935 && ll,_发现程序目录是:/root/.tmp00/bash64
    • 我们就把该程序去掉执行任务的权限:chmod -R -x /root/.tmp00/,然后再 kill 掉该程序
  • 打开别人的脚本,看下是如何书写的,发现有写入几个目录,这里进行删除:
    • rm -rf /tmp/.ha /boot/.b /boot/.0 /root/.tmp00
  • 最后检查下是否有免密内容被修改:cd ~/.ssh/ && cat authorized_keys