Archive for the ‘Linux’ Category.

openwrt路由器(小米路由)实现自定义DDNS(动态域名解析)

大部分路由器(包括非智能路由)都支持ddns,一般是集成花生壳、公云等有限的几家服务商。直接使用路由器集成的ddns功能,优点是简单,缺点就是慢。因为DDNS都是用服务商提供的域名,如果要使用我们自己的域名,需要cname到服务商的域名,这里就存在二次解析,更别说免费DDNS本身速度慢了。
现在的智能路由器都是基于linux的,我们完全可以写一个脚本检测外网ip,在路由器外网ip变化时,去DNS服务提供商直接更改dns设置新的IP,实现DDNS功能。

准备环境:

  • 路由器:小米路由3G 需root,否则登不上ssh, ip 192.168.0.1
  • DNS服务商:dnspod

理论上所有openwrt路由都支持,因为下面的脚本没用到小米路由的特性,都是linux上的命令,但我没有测其他路由器。
dnspod开放了api,可以调接口更新记录,现在已经被腾讯收购,也可以用腾讯的api,但腾讯的api比较复杂,反正我没调通。其他的像阿里云也开放了云解析接口,有需要的同学可以自己研究。

重点不在脚本,而在于思路:

  • linux 定时任务,每分钟执行一次脚本
  • 脚本访问外网指定服务器,获取当前外网ip地址,比较上次获取的外网ip地址,如果不一致,则调dns系统的api更新记录

ddns 脚本内容:

#!/bin/sh
oldIPFile=/tmp/oldip.txt
login_token=xxxxxxx
domain=pocketdigi.com
record_id=xxxxxxx
sub_domain=test

updateIp(){
  result=$(curl -s -d "login_token=$login_token&format=json&domain=$domain&record_id=$record_id&sub_domain=$sub_domain&value=$myip&record_type=A&record_line=默认" https://dnsapi.cn/Record.Modify)
  grepResult=$(echo $result | grep "\"code\":\"1\"")
  if [[ "$grepResult" != "" ]]
   then
       echo '更新成功'
       echo "$myip" > $oldIPFile
   else
       echo '更新失败'
  fi
}

myip=$(curl -s http://myip.dnsomatic.com/)
echo "当前ip:$myip"


if [ ! -f "$oldIPFile" ]; then
  echo "文件不存在,更新"
  updateIp;
else
  oldip=$(cat $oldIPFile)
  echo "旧IP:$oldip"
  if [ "$myip" = "$oldip" ]; then
    echo "当前IP与旧IP相同,不更新"
  else
    echo "当前IP与旧IP不同,更新"
    updateIp
  fi
fi

login_token需要登录dnspod获取,record_id可以使用chrome,在dnspod后台编辑保存那条记录时抓包找到。
使用scp将脚本拷到路由器上的/data目录,小米路由很多目录是只读的,写不进去

ssh登录路由器:

ssh root@192.168.0.1

密码需要到小米路由官网找
给ddns脚本增加可执行权限

chmod +x /data/ddns

添加定时任务

crontab -e

在末尾添加

* * * * * /data/ddns

大功告成!

Kibana 使用Google,高德地图

kibana默认的地图大部分都是英文,对国人不太友好。Kibana使用的是tilemap瓦片地图,支持配置其他地图,其标准与google的tilemap相同,采用这一标准的还有高德。所以,我们可以直接换成google或高德。
打开config下的kibana.yml,在文件底部添加:

    tilemap.url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'
    #tilemap.url: 'http://mt2.google.cn/vt/lyrs=m&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}'
    tilemap.options.maxZoom: 18

用google还是高德随意,google.cn在国内还是可以访问的,tilemap.options.maxZoom配置的是最大缩放级别,默认只能缩放到区级。
重启kibana,6.3.1实测有效。

Elasticsearch 用systemctl启动报max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]

已经修改了/etc/security/limits.conf ,把数值加到65536,用elasticsearch用户启动,一切正常,但一旦用systemctl启动,还是报max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536] 而且,我的配置文件已经指定使用elasticsearch用户,诡异的错误。

其实出现这个问题,原因在于/etc/security/limits.conf里的配置只针对PAM认证登录用户有效,而Systemd有自己的一套配置。全局配置在/etc/systemd/system.conf和/etc/systemd/user.conf,也可以对单个服务做配置,所以,elasticsearch的脚本要做下修改:

[Unit]
Description=Elasticsearch

[Service]
Environment=JAVA_HOME=/usr/local/jdk1.8.0_171
LimitCORE=infinity
LimitNOFILE=65536
LimitNPROC=65536
ExecStart=/usr/local/elasticsearch-6.3.1/bin/elasticsearch
User=elasticsearch
Group=elasticsearch

[Install]
WantedBy=multi-user.target

Docker私服Sonatype Nexus的搭建与使用

为什么要建docker私服

  • 官服在国外,速度慢
  • 创建的镜像是私有的,不想公开传到外部服务器上

Sonatype Nexus介绍

Sonatype Nexus是一个仓库管理软件,支持Maven、Docker、Bower、PyPI、Yum等类型仓库。使用Maven管理依赖的Java程序员一定不陌生,搭建Maven私服基本是用这个。注意:3.x版本才支持docker。

今天我们就用Nexus作Docker的私服,管理我们自己的私有镜像。

Sonatype Nexus安装

很简单,下载,解压,我的路径是
/usr/local/nexus-3.11.0-01
创建开机启动脚本
vim /etc/systemd/system/nexus.service
内容如下:

[Unit]
Description=nexus service
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/usr/local/nexus-3.11.0-01/bin/nexus start
ExecStop=/usr/local/nexus-3.11.0-01/bin/nexus stop
Restart=on-abort

[Install]
WantedBy=multi-user.target

设置开机启动
systemctl enable nexus
启动
systemctl start nexus

nexus默认端口是8081, 现在打开浏览器,访问http://ip:8081, 应该能看到如下界面

点击右上角Sign in,账号admin 密码admin123,登录

点击admin ,把默认的密码改掉,安装完成。

创建仓库

点击顶部配置图标,切到配置页面,左侧菜单选Repositories, 打开仓库配置,点击Create repository 创建仓库。

我之前已经创建好,配置如下图

注意,这里HTTP设置了一个10008端口,仅供docker使用,找个不冲突的就行。

docker配置

docker仓库默认需要https支持,但nexus没有配ssl,需要将服务器加到insecure-registries。
vim /etc/docker/daemon.json

{
  "registry-mirrors": ["https://registry.docker-cn.com"],
  "insecure-registries":["192.168.0.201:10008"]
}

我的nexus部署在192.168.0.201 后面的端口10008与创建仓库时对应。

登录仓库:
docker login 192.169.0.201:10008
按提示输入nexus的账号密码。登录一次以后,会自动保存,以后pull/push都不需要再登录。

docker 提交镜像

  1. 将正在运行的container打包成image

    如图,nginx2容器基于nginx镜像,但是改了一些配置, 现在我们将其打包成image
    docker commit -m "nginx modified" -a "Exception" cb4cbbcde646 nginx-modified

    -m 描述
    -a 作者
    cb4cbbcde646 container id
    nginx-modified 生成的image名
    现在再看镜像列表:
    
    发现我们刚刚commit的image已经在里面了。

  2. 给image打标签
    docker tag f3b408f36cf7 192.168.0.201:10008/nginx-modified

    f3b408f36cf7 image id
    192.168.0.201:10008/nginx-modified 仓库地址和保存路径

  3. 推送镜像
    docker push 192.168.0.201:10008/nginx-modified

  4. 下载镜像
    在另一台服务器上,如果要下载镜像,重复上面的docker配置步骤,然后pull
    docker pull 192.168.0.201:10008/nginx-modified

systemctl开机启动zookeeper

用systemctl使zookeeper开机启动,网上看了好多章,没一个好使,自己琢磨折腾了一个下午总算把它搞定。
直接上脚本:/etc/systemd/system/zookeeper.service

[Unit]
Description=zookeeper.service
After=network.target
[Service]
Type=forking
Environment=ZOO_LOG_DIR=/usr/local/zookeeper-3.4.11/
Environment=PATH=/usr/local/jdk1.8.0_152/bin:/usr/local/jdk1.8.0_152/jre/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin
ExecStart=/usr/local/zookeeper-3.4.11/bin/zkServer.sh start
ExecStop=/usr/local/zookeeper-3.4.11/bin/zkServer.sh stop
ExecReload=/usr/local/zookeeper-3.4.11/bin/zkServer.sh restart
PIDFile=/tmp/zookeeper/zookeeper_server.pid
User=www
[Install]
WantedBy=multi-user.target

重点在两行Environment。

  • 第一行设置日志目录,如果没有设置,默认是当前目录,对www用户来说,可能没有权限。
  • 第二行是配置环境变量,systemd用户实例不会继承类似.bashrc中定义的环境变量,所以是找不到jdk目录的,而zookeeper又必须有。

保存后,reload

systemctl daemon-reload

启用开机自启

systemctl enable zookeeper

启动服务

systemctl start zookeeper

Springboot 启动脚本

Springboot项目可以直接通过

java -jar xxx.jar

命令启动,但是开启关闭还是有个脚本会比较方便。自己写了个shell脚本,功能是查找当前目录下的jar文件,然后启动,也可以关闭,重启。经过几次修改,个人觉得比较完美了,放出源码:

#! /bin/bash
# springboot的jar放同级目录下即可,只能有一个jar文件
export PATH=$JAVA_HOME/bin:$PATH
CURRENT_PATH=$(cd "$(dirname "$0")"; pwd)
JAR=$(find $CURRENT_PATH -maxdepth 1 -name "*.jar")
PID=$(ps -ef | grep $JAR | grep -v grep | awk '{ print $2 }')

case "$1" in
    start)
        if [ ! -z "$PID" ]; then
            echo "$JAR 已经启动,进程号: $PID"
        else
            echo -n -e "启动 $JAR ... \n"
            cd $CURRENT_PATH
        nohup java -jar $JAR >/dev/null 2>&1 &
            if [ "$?"="0" ]; then
                echo "启动完成,请查看日志确保成功"
            else
                echo "启动失败"
            fi
        fi
        ;;
    stop)
        if [ -z "$PID" ]; then
            echo "$JAR 没有在运行,无需关闭"
        else
            echo "关闭 $JAR ..."
              kill -9 $PID
            if [ "$?"="0" ]; then
                echo "服务已关闭"
            else
                echo "服务关闭失败"
            fi
        fi
        ;;
    restart)
        ${0} stop
        ${0} start
        ;;
    kill)
        echo "强制关闭 $JAR"
        killall $JAR
        if [ "$?"="0" ]; then
            echo "成功"
        else
            echo "失败"
        fi
        ;;
    status)
        if [ ! -z "$PID" ]; then
            echo "$JAR 正在运行"
        else
            echo "$JAR 未在运行"
        fi
        ;;
  *)
    echo "Usage: ./springboot {start|stop|restart|status|kill}" >&2
        exit 1
esac

脚本会找到当前目录下的jar文件,所以,只能放一个jar文件。

开机启动脚本:

[Unit]
Description=Dubbo-admin
Wants=network.target
[Service]
Environment=JAVA_HOME=/usr/local/jdk1.8.0_171
Type=forking
ExecStart=/usr/local/xxx/springboot start
ExecStop=/usr/local/xxx/springboot stop
[Install]
WantedBy=multi-user.target

使用shell脚本实现定时备份mysql数据库

在经历过一次惨痛教训后,意识到数据库备份的重要性,所以昨天晚上写了个小脚本,用以备份mysql数据库。

转载请注明出处(http://www.pocketdigi.com), 谢谢。

mysql本身可以从日志文件恢复数据,其原理是日志文件会记录指定时间段的sql操作记录。但我们不可能存储从数据库安装到当前的日志文件,日志早爆炸了,后面的日志会覆盖之前的日志,所以,想从日志恢复完整数据,那是不可能的。而通过自己备份数据库,再从日志中找到备份时间到当前时间的更改记录,就可以恢复所有数据。

Continue reading “使用shell脚本实现定时备份mysql数据库” »

使用SSH实现内网穿透

前面写过一篇使用ngrok实现外网访问内网的文章,但实现起来稍复杂,而且我在实际使用过程中也发现经常断线,ngrok+nginx 实现内网穿透 共用80端口,ngrok的优点在于独立于任何其他服务,需要转发什么域名直接改客户端配置。

今天介绍的是通过SSH穿透内网

SSH内网穿透优点

  1. 无需额外安装服务端客户端(ssh你机器上肯定有)
  2. 可以转发到所以你的机器能直接访问的机器上(你可以给在同一局域网的前端妹子配个外网可访问域名,不用在她的电脑上配置,如果觉得浪费了搭讪机会,可以在她电脑上随便敲点啥)

缺点

如果要将这个功能开放给别人,要注意配置ssh账号权限,自己用无所谓。

一条命令实现

ssh -CfnNT -R 6666:192.168.10.120:8080 fff@server1.pocketdigi.com -p 4356
  • 6666:外网服务器的端口号,外网服务器所有6666的请求会转发
  • 192.168.10.120 转发目标机器,本机就是localhost
  • fff ssh账号
  • server1.pocketdigi.com 外网服务器域名
  • 4356 外网服务器的ssh端口号,默认是22,总有一班人天天扫,所以改了

此时所有访问server1.pocketdigi.com:6666的请求会转发到192.168.10.120:8080,可在外网服务器上执行

curl http://localhost:6666

查看,如果192.168.10.120:8080启了http服务,应该能看到.
鉴于ssh会超时断开,建议使用autossh,断开会自动重连

配置nginx

参考 ngrok+nginx 实现内网穿透 共用80端口

开机自启

  1. 增加启动文件 /usr/local/bin/nat_forward

    !/bin/bash

    autossh -M 5678 -CfnNT -R 6666:localhost:8080 fff@server1.pocketdigi.com -p 4356

2.增加执行权限

sudo chmod +x /usr/local/bin/nat_forward

3.增加启动项

偏好设置--用户与群组--登录项,添加/usr/local/bin/nat_forward