Posts in category windows

nginx 反向代理功能介绍及在Windows下使用的Portable版本

想做一个公网访问内网的反向代理,但是在公网机器上的 Apache 怎么也安装不上(那个机器已经安装了两个 Apache,不知道是不是这方面的原因),于是就研究了一下如何使用 nginx 来实现反向代理。

搜索了一下资料,发现 nginx 似乎比 Apache 更好用,包括:

  • 配置的方式类似 json,比较容易阅读;
  • 运行简单,Windows 平台上的二进制文件本身就是解压即可运行,够 “Portable”;
  • 在网上找到了使用 Windows Service Wrapper 将 nginx 转为一个 Windows 服务的方法,经试验简单有效,见 Nginx Windows Service

nginx 自然在其 官网下载,本文使用的是 Stable version, nginx/Windows-1.2.7;

winsw(Windows Service Wrapper)原来 host 在 https://kenai.com/,不过Oracle 收购 Sun 之后这个网站似乎受到一些影响,目前已经转到了 github 上: https://github.com/kohsuke/winsw/ (是用 C# 编写的,呵呵), 其二进制文件可以在 Nginx Windows Service 文中提到的地点 http://download.java.net/maven/2/com/sun/winsw/winsw/ 下载(似乎是一个 maven 的仓库?);

本文附件中的 “PortableNgnix” 只是简单的将解压后的 nginx Windows 程序和 winsw 合并在一起而已,其中包含一个简单的 proxy 写法示例(将 http://localhost/main/browser/AdminShells/ 反向代理连接到 http://thinkbase.net/main/browser/AdminShells/ ):

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    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  logs/access.log  main;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location /main/browser/AdminShells/ {
                proxy_pass              http://thinkbase.net/main/browser/AdminShells/;
                proxy_redirect          off;
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

其实很多时候还有更简单的写法,比如下面这个反向代理 svn 服务器的例子:

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    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  logs/access.log  main;

    keepalive_timeout  65;

    server {
        listen       81;
        server_name  localhost;

        location / {
                proxy_pass              http://192.168.0.77:8080/;
                proxy_redirect          off;
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

使用 winsw 创建 Windows Service 的过程也很简单,附件 PortableNginx.7z 中的例子是假设 nginx 解压后在 D:\PortableNginx 目录下的情况:

<service>
    <id>nginx-reverse-proxy</id>
    <name>nginx reverse proxy</name>
    <description>nginx reverse proxy</description>
    <executable>D:\PortableNginx\nginx\nginx.exe</executable>
    <logpath>D:\PortableNginx\nginx\logs</logpath>
    <logmode>roll</logmode>
    <depend></depend>
    <startargument>-p D:\PortableNginx\nginx -c D:\PortableNginx\nginx\proxy.conf</startargument>
    <stopargument>-p D:\PortableNginx\nginx -s stop</stopargument>
</service>

更多细节可以继续研究附件(参见其中的 readme.txt),或者把附件解压后自己体验,下面是 winsw 产生的 Windows Servicce 以及 Service 运行时产生的相关文件截图,供参考: .

Windows: 定义以较短时间间隔重复运行的计划任务

增强Windows计划任务执行用户的安全性 里面提到了如何增强计划任务的安全性, 其实计划任务中存在很多灵活应用的地方, 比如如何让一个任务以较短的时间间隔重复运行, 比如一个每小时执行一次的任务, 呆板地为每次运行设置一个日程安排条目(那么就有12个日程安排, 如果是每隔5分钟运行一次呢?!!!)显然不是最好的方案.

附图是在 Windows Server 2008(Win7、Win8 的计划任务设置界面也是这样的)中设置每5分钟执行一次的任务时的触发器定义, 供参考.

附加说明:截图中的"1430分钟"是这样计算的:1430/60 = 23.83 小时 = 23 小时 50 分钟.

批处理中很有用的命令 WMIC(补 20120503)

原文来自 https://code.google.com/p/thinkbasenet/wiki/20120503_WMIC

最典型的用法

通过命令行中的一些内容查找程序

wmic process where "( (CommandLine LIKE '%_notepad_%') AND NOT(CommandLine LIKE '%_wmic_%' ) )"
  • 为了防止有 '%notepad%' 这样的环境变量, 所以使用了 '%_notepad_%' 这样的查询语法, 一般情况下, 直接使用 '%notepad%' 也是可以的.
  • 另外, 查询条件中 LIKE 操作符是不区分字符串的大小写的.

将 wmic 的输出由 unicode 转为 ascii

wmic 输出到 stdout 和 stderr 的内容都是 unicode 的,因此重定向到文件后,看起来会是这个样子:

使用如下的代码可以将 wmic 的输出由 unicode 转为 ascii:

:: 需要将 wmic 的输出由 unicode 转为 ascii
set TMP_WMIC_OUT=%TEMP%\wmic-process-list.txt
wmic /output:"%TMP_WMIC_OUT%" process where name="cmd.exe" get sessionid,commandline
cmd /A /C type "%TMP_WMIC_OUT%"

通过命令行中的一些内容结束程序

wmic process where "( (CommandLine LIKE '%_notepad_%') AND NOT(CommandLine LIKE '%_wmic_%' ) )" delete

参考

  • 关于 wmic 命令输出的 unicode 转 ascii
  • MSDN:
  • Microsoft TechNet
  • 来自 http://lgj573.iteye.com/blog/327432
    # wmic 获取硬盘固定分区盘符:
    wmic logicaldisk where "drivetype=3" get name
    
    # wmic 获取硬盘各分区文件系统以及可用空间:
    wmic logicaldisk where "drivetype=3" get name,filesystem,freespace
    
    # wmic 获取进程名称以及可执行路径:
    wmic process get name,executablepath
    
    # wmic 删除指定进程(根据进程名称):
    wmic process where name="qq.exe" call terminate
    # 或者用
    wmic process where name="qq.exe" delete
    
    # wmic 删除指定进程(根据进程PID):
    wmic process where pid="123" delete
    
    # wmic 创建新进程
    wmic process call create "C:\Program Files\Tencent\QQ\QQ.exe"
    
    # 在远程机器上创建新进程:
    wmic /node:192.168.1.10 /user:administrator /password:123456 process call create cmd.exe
    
    # 关闭本地计算机
    wmic process call create shutdown.exe
    
    # 重启远程计算机
    wmic /node:192.168.1.10/user:administrator /password:123456 process call create "shutdown.exe -r -f -m"
    
    # 更改计算机名称
    wmic computersystem where "caption='%ComputerName%'" call rename newcomputername
    
    # 更改帐户名
    wmic USERACCOUNT where "name='%UserName%'" call rename newUserName
    
    # wmic 结束可疑进程(根据进程的启动路径)
    wmic process where "name='explorer.exe' and executablepath<>'%SystemDrive%\\windows\\explorer.exe'" delete
    
    # wmic 获取物理内存
    wmic memlogical get TotalPhysicalMemory|find /i /v "t"
    
    # wmic 获取文件的创建、访问、修改时间
    @echo off
    wmic datafile where name^="c:\\windows\\system32\\notepad.exe" get CreationDate^,LastAccessed^,LastModified
    
    # wmic 全盘搜索某文件并获取该文件所在目录
    wmic datafile where "FileName='qq' and extension='exe'" get drive,path
    
    for /f "skip=1 tokens=1*" %i in ('wmic datafile where "FileName='qq' and extension='exe'" get drive^,path') do (set "qPath=%i%j"&@echo %qPath:~0,-3%)
    
    # 获取屏幕分辨率
    wmic DESKTOPMONITOR where Status='ok' get ScreenHeight,ScreenWidth
    
    # 获取U盘盘符,并运行U盘上的QQ.exe
    @for /f "skip=1 tokens=*" %i in ('wmic logicaldisk where "drivetype=2" get name') do (if not "%i"=="" start d:\qq.exe)
    
    # 获得进程当前占用的内存和最大占用内存的大小:
    wmic process where caption='filename.exe' get WorkingSetSize,PeakWorkingSetSize
    # 把内存大小改成KB(MB的话可能有小数)
    @echo off
    for /f "skip=1 tokens=1-2 delims= " %%a in ('wmic process where caption^="conime.exe" get WorkingSetSize^,PeakWorkingSetSize') do (
    set /a m=%%a/1024
    set /a mm=%%b/1024
    echo 进程conime.exe现在占用内存:%m%K;最高占用内存:%mm%K
    )
    pause 
    

增强Windows计划任务执行用户的安全性

为了避免计划任务执行与当前登录到Windows桌面的用户操作之间的相互干扰(在Win2003上, 如果计划任务的执行用户和当前桌面登录用户相同, 计划任务执行时的命令执行窗口会显示在该用户登录的桌面上, Win2008似乎没有这个问题), 一般需要为计划任务专门指定一个用户, 我习惯于叫cron;

为了方面任务的执行, 通常会简单的把这个用户归到Administrators组, 考虑到Administrators组用户的权限很大, 因此对这个cron帐号需要进行一定的安全控制, 简单的来说就是"限制该用户登录到服务器":

  • 用于计划任务执行用户的创建:
  • 该用户划入管理员组:
  • 通过"组策略编辑器"(gpedit.msc)设置"拒绝本地登录":
  • 通过"组策略编辑器"(gpedit.msc)设置"拒绝从网络访问":
  • 终端服务配置中设置RDP-Tcp连接的访问权限:

经过以上配置, 实际测试该用户无法使用终端服务登录服务器, 这个帐号可以比较安全的用于计划任务了:

使用 w32tm 命令定期同步服务器时间

有时候因为各种原因, Windows服务器的时间可能不准, 比如虚拟机中服务器的时间会受主机时间的影响, 或者机器的BIOS时钟不准确等;

可以简单通过Windows计划任务, 使用 w32tm.exe /resync 命令就可以实现定期自动同步服务器时间的功能:

  • 在"计划任务"中设置执行的命令:
  • 设置定期执行:

如果发现定期时间同步不起作用, 建议直接在命令行中执行 w32tm.exe /resync 命令进行测试, 如果报错 "此计算机没有重新同步,因为没有可用的时间数据。", 可以在 日期和时间 属性 中选择其他的服务器试试:

  • 通过双击 Taskbar 右边的时间显示区域, 或者执行控制面板的"日期和时间", 都可以进入 日期和时间 属性: