手头上原本是一个apache
基础的wordpress
网站,想着直接配置https
,一顿操作之后出了各种问题。后面又想搭一个CTFd
平台,绑定到域名下的子域名上,这就不能直接配置https
了,因为443
端口只有一个。后面发现了可以利用nginx
进行统一管理,零零散散折腾了很多天才搞完,在这里记录一下过程。
0x00 给wordpress配置https
wordpress
是基于apache
的,所以事先需要准备好SSL
证书,证书的获得方式有很多,在这里不赘述。我是通过腾讯云官方的下载的,下文也以此为基本。
首先对于单一容器,配置https
需要追加443端口,我将下载的证书存储在/data/cert/apache/
目录下,并在开启时配置挂载。创建好容器后,我们在容器内部操作如下
-
加载Apache2的SSL模块
a2enmod ssl
第一次加载会提示你重启,此处重启或稍后重启均可 -
重启指令
service apache2 restart
重启之后容器会退出,重进即可 -
修改配置文件
加载之后,在
/etc/apache2/sites-available/
下修改配置文件default-ssl.conf
和000-default.conf
default-ssl.conf
SSLCertificateFile /data/cert/ephemerally.top.crt SSLCertificateKeyFile /data/cert/ephemerally.top.key
修改上述两行,后面为你容器中挂载的证书路径,此处作用为绑定你的证书
000-default.conf
在
<VirtualHost *:80> </VirtualHost>
标签中增加下面的配置RewriteEngine on RewriteBase / # FORCE HTTPS RewriteCond %{HTTPS} !=on RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] 修改效果
# The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html RewriteEngine on RewriteBase / # FORCE HTTPS RewriteCond %{HTTPS} !=on RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] 此处效果为
http
请求跳转到https
-
文件链接
从 apache 的配置文件
apache2.conf
可以看到,apache 只会读取/etc/apache2/sites-enabled
目录的配置文件,所以需要把/etc/apache2/sites-available
下的default-ssl.conf
文件链接到/etc/apache2/sites-enabled
目录下。ln -s /etc/apache2/sites-available/default-ssl.conf \ /etc/apache2/sites-enabled/default-ssl.conf
-
修改
wordpress
后台到此的效果应该是,
https
和http
均能正常访问网站,但是在访问网站的时候,会提示你页面存在http
元素,所以在后台的仪表盘里,修改对应的地址,http
改成https
即可。如果前面有操作失误导致无法访问后台,可以在数据库中进行修改
mysql> use wordpress; mysql> desc wp_options; +--------------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+---------------------+------+-----+---------+----------------+ | option_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | option_name | varchar(191) | NO | UNI | | | | option_value | longtext | NO | | NULL | | | autoload | varchar(20) | NO | MUL | yes | | +--------------+---------------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) mysql> select option_id , option_value from wp_options where option_id = 1 or option_id = 2; +-----------+-------------------------+ | option_id | option_value | +-----------+-------------------------+ | 1 | https://ephemerally.top | | 2 | https://ephemerally.top | +-----------+-------------------------+ 2 rows in set (0.00 sec) mysql> update wp_options set option_value = 'https://ephemerally.top' where option_id = 1; mysql> update wp_options set option_value = 'https://ephemerally.top' where option_id = 2;
如上操作即可。
-
修改成功之后,如果遇到访问
http
未跳转到https
的,可以修改/var/www/html
下的.htaccess
文件RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] RewriteCond %{SERVER_PORT} !^443$ RewriteRule (.*) https://%{SERVER_NAME}/$1 [R=301,L] 参考如上
-
为了方便维护,我是利用
docker-compose
写的启动,但是正常启动之后,上述的操作如果不设置挂载,会需要重复操作,因此可参考restart.sh
容器名称:
wordpress
#! /bin/bash docker exec -it wordpress bash -c 'a2enmod ssl' docker cp ./conf/default-ssl.conf wordpress:/etc/apache2/sites-available/default-ssl.conf docker cp ./conf/000-default.conf wordpress:/etc/apache2/sites-available/000-default.conf docker exec -it wordpress bash -c 'ln -s /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf && service apache2 restart'
0x01 用nginx接管端口
在只有一个服务的情况下,如上方法部署会比较方便。但是当服务器上有多个服务的时候,就可以通过nginx
将请求转发到各个服务。
原来的情况下,我的80和443端口要跑我的网站,这个时候我要让nginx
接管80和443端口,一种做法就是比如让我的网站跑在8080端口,然后nginx
将8080端口的流量通过443端口转发到外网,在这个过程中用网站内部用http
协议,nginx
与外网传输用https
协议。同样,CTFd
如果跑在8001端口,同样用nginx
进行转发。
但是,如果我不想对外显示端口,因为我想将端口绑定到域名上,通过端口无法访问服务,那么我可以建立一个docker
网络,让nginx
与我的网站在同一个docker
网络下,在nginx
中通过容器名称访问服务。
在docker-compose.yml
中添加
nginx:
container_name: proxy_nginx
image: nginx:latest
volumes:
- /root/nginx/log/:/var/log/nginx
- /root/nginx/nginx.conf:/etc/nginx/nginx.conf
- /root/nginx/dist/:/usr/share/nginx/html
- /data/cert/nginx/:/data/cert/
ports:
- "443:443"
- "80:80"
restart: always
我用同一个yml
启动,就可以让他们在同一个网络中。
同样,在nginx中配置https
的步骤会更加好理解
server {
listen 80;
server_name ephemerally.top;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name ephemerally.top;
ssl_certificate /data/cert/ephemerally.top_bundle.crt;
ssl_certificate_key /data/cert/ephemerally.top.key;
location / {
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_pass https://wordpress:443;
}
}
第一个server
的作用是配置接收到80端口HTTP
请求转发至HTTPS
而第二个server
的作用是利用SSL
证书配置HTTPS
访问,wordpress
是我内部容器的名称,这样就将对443端口的请求转发到了内部容器的443端口,跟直接容器 -p 443:443
等效。
这里其实还有一种解决方式,就是我不需要配置wordpress
的https
,直接内部利用http
通信,只需要nginx
和外网https
通信。我开始是这样配置的,但是因为wordpress
内部的关系,配置的过程中出了很多问题,因此我在wordpress
内部配置https
之后直接将https
流量转出。
0x02 添加CTFd进入nginx管理
关于CTFd
的配置参见《SSSCTF平台部署指南》
因为CTFd
本身是一个多容器的庞大网络,并不方便和我的nginx
共属一个网络,但是我只需要将CTFd
的流量转发即可,比如说我CTFd
部署在内网的8001
端口,那我只要在内部写内网的8001
端口
server {
listen 80;
server_name ctf.ephemerally.top;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name ctf.ephemerally.top;
ssl_certificate /data/cert/ctf.ephemerally.top_bundle.crt;
ssl_certificate_key /data/cert/ctf.ephemerally.top.key;
location / {
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_pass http://x.x.x.x:8001;
}
}
proxy_pass
处填写内网地址即可
第一个server
的作用是配置接收到80端口HTTP
请求转发至HTTPS
第二个server
直接将内网8001端口的流量转发到443https
这里有一点需要注意,nginx
配置完并不是实时生效的,可以通过docker restart proxy_nginx
或在容器内部nginx -s reload
重载配置。
至此,完成配置。正如你所见,通过ephemerally.top
访问我的博客,通过ctf.ephemerally.top
访问CTFd
平台
0x03 参考链接
配置过程中参考了不少零零碎碎的资料,如下。nginx
的功能远远不止于此,这里只介绍了它的反向代理功能
https://www.cnblogs.com/zhenhunfan2/p/14031224.html
https://www.jianshu.com/p/3378d2eacb3d
https://www.jianshu.com/p/3e25b24d7247
Very good post! We will be linking to this great article on our website. Keep up the good writing.