Nginx下配置webssh
0x00 前言
作为学校数据中心机房的维护人员,有时候总有一个电话打过来说咋咋咋哪台服务器出了点问题啥的。平时在宿舍或者工作室还好,关键是有时候TM正在上课啊。也就是说只能处在3G/4G网络环境下,由于学校防火墙那边对外的控制端口都控制的比较死,所以总得想个法子能在任何时候随时随地的连上校内集群,所以,本篇blog应运而生。
技术上基本没啥含量,只是在配置Nginx通过虚拟主机的方式做反向代理的时候遇到了点小问题,在此和大家分享。
0x01 关于webssh
初次认识webssh也是之前在一些技术类的门户网站上了解到的,了解到它是一个基于web的ssh连接客户端。这样以来,就很方便在任何时候连接远程服务器了,只要有个浏览器就行,就不用找啥putty、xshell等工具了。
webssh项目地址:https://github.com/xsank/webssh
知道有这么个好东西,这会儿总算是找上用场了。所以,就搭了个试试。如果只是简单运行下那是很简单的,只是我目前的网络环境还是有点复杂,而且为了安全考虑,最好做虚拟主机只能通过域名访问。由于webssh的web框架是采用Tornado开发的,所以一般采用Nginx做反向代理比较靠谱。所以,基本要求就是:Nginx做反向代理、虚拟主机。当然为了安全考虑,防止有人扫描到我的域名暴露了web借口,我还简单添加了我邮件通知的功能,以防入侵者通过我的webssh接口爆破我的内网服务器。
0x02 Nginx相关配置
nginx.conf做虚拟主机,只需要做server模块的配置,我的服务器是有多个虚拟主机。而Nginx的代理功能是通过http proxy模块来实现的。默认在安装Nginx时已经安装了http proxy模块因此可直接使用http proxy模块。所以nginx.conf的配置如下:
# server1 server { listen 80; server_name 222.24.xx.xx; root /usr/share/nginx/html; index index.php index.html index.htm; location / { root /usr/share/nginx/html; index index.php index.html; } location ~ \.php$ { root /usr/share/nginx/html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } charset utf-8; access_log /var/log/nginx/local.web.access.log main; error_log /var/log/nginx/local.web.error.log error; } # server2 server { listen 80; server_name ooxx.s0nnet.com; location / { proxy_pass http://127.0.0.1:9520; proxy_http_version 1.1; proxy_read_timeout 300; } charset utf-8; access_log /var/log/nginx/ooxx.s0nnet.com.access.log main; error_log /var/log/nginx/ooxx.s0nnet.com.error.log error; } # server3 server{ ........ }
上面的服务器做了多虚拟主机,有php的,有静态的,也有我们的webssh的应用。通过上面的配置,页面访问基本没啥问题都可以打开,但是没法连接,一直显示连接失败“connection closed”,而且根据webssh的错误信息显示如下:
据此应该是请求的资源找不到,再通过F12查看JS发现,这个Tornado是基于Websocket的,所以需要咋们的Nginx还要支持Websocket。浏览器里头的JS错误:
于是查了下,Nginx下的相关配置,有些给出的配置如下:
server { listen 80; location / { proxy_pass http://127.0.0.1:9520; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } }
更该了配置后发现还是不能使用,又查了一些配置,有些在location里又给出了下面的配置 :
proxy_set_header Host $host;
索性加了这个,发现可以正常使用了。所以对server2的完整配置如下:
# server2 server { listen 80; server_name ooxx.s0nnet.com; location / { proxy_pass http://127.0.0.1:9520; proxy_http_version 1.1; proxy_read_timeout 300; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } charset utf-8; access_log /var/log/nginx/ooxx.s0nnet.com.access.log main; error_log /var/log/nginx/ooxx.s0nnet.com.error.log error; }
这是参考的博文连接: https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/
至此,webssh的配置算是完成了。下面是正常使用的状态:
但还是对nginx的反向代理配置不太熟悉啊,所以在此总结下关于这方面的配置。一般的反向代理大都涉及到下面这些方面的:
location / { proxy_pass http://apachephp; #Proxy Settings 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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_max_temp_file_size 0; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; }
对上面的配置参数一一做个解释:
1. 指令 proxy_pass
这个指令设置被代理服务器的地址和被映射的URI,地址可以使用主机名或IP加端口号的形式,例如:proxy_pass http://localhost:8000/uri/;
2. 指令 proxy_redirect
它是个URL重定向的功能。如果需要修改从被代理服务器传来的应答头中的”Location”和”Refresh”字段,可以用这个指令设置。具体可以参考:Nginx的proxy_redirect作用
3. 指令 proxy_next_upstream
如果后端的服务器返回500、502、503、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
4.指令 proxy_set_header
设置由后端的服务器获取用户的主机名或者真实IP地址,以及代理者的真实IP地址。
5.指令 client_body_buffer_size
用于指定客户端请求主体缓冲区大小,可以理解为先保存到本地再传给用户。
6.指令 proxy_connect_timeout
表示与后端服务器连接的超时时间,即发起握手等候响应的超时时间。
7.指令 proxy_send_timeout
表示后端服务器的数据回传时间,即在规定时间之内后端服务器必须传完所有的数据,否则,Nginx将断开这个连接。
8.指令 proxy_read_timeout
设置Nginx从代理的后端服务器获取信息的时间,表示连接建立成功后,Nginx等待后端服务器的响应时间,其实是Nginx已经进入后端的排队之中等候处理的时间。
9.指令 proxy_buffer_size:设置缓冲区大小, 默认,该缓冲区大小等于指令proxy_buffers设置的大小。
10.指令 proxy_buffers:设置缓冲区的数量和大小。nginx从代理的后端服务器获取的响应信息,会放置到缓冲区。
11.指令 proxy_busy_buffers_size:用于设置系统很忙时可以使用的proxy_buffers大小,官方推荐的大小为proxy_buffers*2。
12.指令 proxy_temp_file_write_size:指定proxy缓存临时文件的大小。
0x03 开发邮件通知功能
简单分析一下webssh的源码,主要有这么几个重要的处理模块:
daemon.py 到远程SSH服务器的登录、传输数据的处理
data.py 对服务器端与客户端(浏览器)的json的数据的处理
handlers.py 响应客户连接请求处理
进一步查看源码,可以看出咋们需要在远程服务器登录成功之后发送咋们的提醒邮件。所以,可以简单修改一些handler.py文件。并一个邮件发送的模块mail.py,在handler.py中导入这个模块并使用这个模块的sending()方法发送邮件就OK了。下面是相关文件的修改:
#handler.py文件,添加导入模块: from mail import Sendmail #handler.py文件,修改on_message函数: def on_message(self, message): bridge = self.get_client() client_data = ClientData(message) if self._is_init_data(client_data): if self._check_init_param(client_data.data): bridge.open(client_data.data) logging.info('connection established from: %s' % self._id()) try: mail = Sendmail() mail.sending(client_data.data) except: logging.info('event email send error!') else: self.remove_client() logging.warning('init param invalid: %s' % client_data.data) else: if bridge: bridge.trans_forward(client_data.data)
在webssh源码根目录下添加mail.py文件以支持邮件发送功能:
#!/usr/bin/env python # coding=utf-8 import time import smtplib from email.mime.text import MIMEText from email.header import Header class Sendmail(object): def __init__(self): self.smtp_host = "smtp.sina.com" self.smtp_port = 25 self.smtp_user = "s0nnet@sina.com" self.smtp_pass = "xxxxxxxxx" self.mail_to = "admin@s0nnet.com" def sending(self,data={}): msg = "The Login Host:<b>%s</b><br>" % data['hostname'] msg = msg + "And Login User:<b>%s</b></br>" % data['username'] msg = msg + "Login Time:%s" % time.ctime() message = MIMEText(msg, 'html', 'utf-8') subject = 'WebSSH登录邮件提醒' message['Subject'] = Header(subject, 'utf-8') try: smtpObj = smtplib.SMTP() smtpObj.connect(self.smtp_host, self.smtp_port) smtpObj.login(self.smtp_user,self.smtp_pass) smtpObj.sendmail(self.smtp_user, self.mail_to, message.as_string()) smtpObj.close() except smtplib.SMTPException, err: print err
至此,邮件发送功能就成功了,下面是接收到的邮件样例: