用 Docker 和 Nginx 搭建自己的云服务器(Nextcloud)
Preface
前些阵子瓷国各种网盘纷纷倒下,我也越来越担心自己的数据安全,没准哪天我的网盘帐号就被"无缘无故"的删掉什么的,于是我就琢磨着搭建个自己的私人网盘。现在这个时代最不缺的就是轮子,随便一搜就有好几个符合要求的自搭建(Self-Hosted)网盘软件:
- Owncloud
不错的候选,不过一些高级特性(比如 Android/iOS app, 团队协作功能, etc.)需要购买订阅,而且还挺贵。 - Cozy
同样是不错的候选,但是试用了一会儿发现制作得比较粗糙,大部分功能只是存在而已,不够用。 - Nextcloud
Owncloud 的 fork,所有高级特性/企业团队协同功能全免费,还可以自己选择一些 Nextcloud 仓库内的 app 进行安装,Android app 也是免费使用(对应的 iOS app 售价是 $0.99)。
综上,我选择 Nextcloud。
接下来的问题是,我以后必定会在同一台主机内搭建多个网站,但 80 端口只能被一个进程监听。解决这个问题就是使用 Nginx 做反向代理,把入站连接根据域名/路径来转发到主机内的不同端口上。
还有一个问题就是通信安全问题。用 HTTP 这种明文通信协议的话,在通过某些恶意防火墙的时候 很可能会把通信内容给镜像下来 然后拿去分析。解决这个问题也不难,弄个免费 SSL 证书即可,比如 “Let’s Encrypt"。
注意: 本文使用 Ubuntu 作为服务器系统,部分特性(比如 ufw
)不存在于其他 Linux 发行版里 或 需要代替方案(比如用 iptables
代替 ufw
)。
安装 Nginx
- 执行命令来安装 Nginx
apt-get install nginx
,配置 Nginx 需要在安装 Nextcloud 后进行。 - 执行命令打开防火墙的 80 端口
ufw allow 80/tcp
安装 / 配置 MariaDB
- 执行命令来安装 MariaDB
apt-get install mariadb-server mariadb-client
- 执行命令来初步配置 MariaDB
mysql_secure_installation
,然后按照提示进行操作 - root 登录 mysql,执行下面的 SQL 语句,为 Nextcloud 的数据库做准备
-- 创建 nextcloud 数据库 CREATE DATABASE nextcloud CHARACTER SET = utf8 COLLATE = utf8_general_ci; -- 创建 nextcloud 用户 CREATE USER nextcloud IDENTIFIED BY 'Passw0rd'; -- 让用户 nextcloud 拥有 nextcloud 数据库的完整权限 GRANT ALL ON nextcloud.* TO nextcloud;
安装 Nextcloud
我选择用 Docker 安装/部署 Nextcloud 因为用起来傻瓜化,并且还能与现有的网站隔离开来,而且 Dockerfile
里都把依赖什么的都配置好了,直接拿来用就行了,省得我再自己解决环境/依赖之类的问题。参考如下命令:
# 1. 从 GitHub 仓库拉取 Dockerfile
git clone https://github.com/nextcloud/docker.git nextcloud_docker
cd ./nextcloud_docker/11.0/apache/
# 2. 构建 Docker image.
docker build --tag nextcloud/server:11.0.2-apache .
# 3. 从 docker image "nextcloud/server:11.0.2-apache" 创建一个 docker container, docker create 的参数说明请参考后面的表格.
docker create -v /<路径>/apps/:/var/www/html/apps -v /<路径>/config/:/var/www/html/config -v /<路径>/data/:/var/www/html/data -p 127.0.0.1:8081:80/tcp --name nextcloud nextcloud/server:11.0.2-apache
# 4. 启动容器并测试
docker start nextcloud
curl http://127.0.0.1:8081 # 如果能看到有 HTML 输出的话,应该就是启动成功了.
docker create
参数说明:
基本格式:docker create [OPTIONS] <IMAGE> [COMMAND] [ARG...]
参数名 | 值的格式 | 注释 |
---|---|---|
-v , --volume |
主机路径:容器内路径 |
将 容器内目录 映射到 主机目录 , 这样既可以把数据存在主机上而不是容器里了 |
-p , --publish |
主机IP:主机端口:容器内端口[/通信协议] |
将容器里公开的端口映射到主机端口上,然后就能被 Nginx 转发了 |
--name |
容器名称 |
给新的容器起个名 |
<IMAGE> | Image 名称 | 指定使用哪个 image 来创建容器 |
注1: 如需更新 Nextcloud 的话,修改 Dockerfile
内的 ENV NEXTCLOUD_VERSION
右面的值即可。
配置 SSL 证书 & Nginx & 子域名
创建子域名
直接在域名提供商的域名管理页面创建 CNAME
到自己的域名即可,下文将以 yun.example.com
为例。
配置 SSL 证书
- 安装 letsencrypt
apt-get install letsencrypt
- 创建静态网站的目录
mkdir --parents /var/www/yun.example.com
,稍后 Let’s Encrypt 会用到它 - 创建文件
/etc/nginx/sites-available/yun.example.com
并编辑# "yun.example.com" server { # 监听 IPv4/6 80 端口 listen 80; listen [::]:80; # 域名 server_name yun.example.com; # 静态网站根目录 root /var/www/yun.example.com; # 提供静态文件服务 location / { proxy_set_header X-Forwarded-Proto $scheme; try_files $uri $uri/ =404; } }
- 创建软链接,因为 Nginx 载入所有
/etc/nginx/sites-enabled/
下的配置文件ln -s /etc/nginx/sites-available/yun.example.com /etc/nginx/sites-enabled/yun.example.com
- 重启 Nginx
systemctl restart nginx
- 执行命令来生成 SSL 证书
letsencrypt certonly --webroot -w /var/www/yun.example.com --domain "yun.example.com"
至此,SSL 证书已经生成好了,接下来将配置 Nginx。
配置 Nginx
- 编辑配置文件
/etc/nginx/sites-available/yun.example.com
# "yun.example.com" server { # 指定服务器名称,这里改成你自己的域名 server_name yun.example.com; # 监听 IPv4/6 上的 443 端口 # 不配置 80 重定向到 443 是为了让用户在浏览器地址栏里手动输入 "https://",最大限度避免被劫持. listen 443; listen [::]:443; # 配置 SSL 证书,把下面的证书路径改成自己的证书. ssl on; ssl_certificate /etc/letsencrypt/live/yun.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yun.example.com/privkey.pem; access_log /var/log/nginx/${server_name}_access.log; location / { proxy_redirect off; # 将请求转发到本机的 8081 端口 proxy_pass http://127.0.0.1:8081; proxy_set_header Host $http_host; # According to "https://docs.nextcloud.com/server/11/admin_manual/configuration_server/harden_server.html#enable-http-strict-transport-security" add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always; # 指定 HTTP Request Body 的最大大小 client_max_body_size 128M; } # 禁止访问 /.htaccess 文件 location = /.htaccess { return 404; } }
- 验证配置文件语法 并 重启 Nginx:
nginx -t systemctl restart nginx
- 用网页浏览器打开地址
https://yun.example.com
查看效果
配置 Nextcloud
首先定位目录到上面 docker create
里 -v
后面的 路径
下的 config
文件夹,编辑 config.php
文件。
配置 trusted_domains
找到 trusted_domains
,在下面按照格式添加自己的域名,比如像这样:
'trusted_domains' =>
array (
0 => 'yun.example.com',
)
配置 overwritehost
官方文档 提到,有时候 Nextcloud 自己重定向时候会重定向到错误的地址,加上下面这行就好了:
'overwritehost' => 'yun.example.com',
配置缓存
按照 官方文档 的说明,个人使用的话只需要添加下面这行就行了:
'memcache.local' => '\OC\Memcache\APCu',
最后需要重启 Nextcloud/Docker容器 使配置生效。
docker restart nextcloud
主机的防火墙配置
因为容器内的 Docker 需要访问主机的 MariaDB,因此需要知道 Docker 容器的网关和 IP 地址。
- 进入并运行容器内的
bash
docker exec -i nextcloud /bin/bash -il
- 获取容器 IP 和网关(Gateway)
输出大概是这样:
ip route show default
执行命令default via 172.17.0.1 dev eth0 # via 后面的是网关 IP 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2 # src 后面的是容器的 IP 地址
exit
回到主机的 bash. - 添加防火墙白名单,允许来自容器(
172.17.0.2
)的所有 IP 包ufw allow from 172.17.0.2
初始设置
- 用浏览器打开
https://yun.example.com
- 填写管理员的用户名和密码,以后将使用这个帐号来管理 Nextcloud
- 数据库设定里,数据库选择
MySQL / MariaDB
,其余的参考下面的配置名称 注释 用户名 nextcloud
密码 nextcloud 用户的密码 地址 比如 172.17.0.1
, 也可以加上端口号 像这样172.17.0.2:3306
数据库名 nextcloud
部署完成
至此,Nextcloud 的安装与配置就全部结束了。移动端 app 可以到这里下载:
更新 Nextcloud
git pull
docker-compose build
docker start --attach nextcloud-app
then<CTRL+C>
and wait it exits.docker exec -it --user www-data nextcloud-app /bin/bash -il
php occ maintenance:mode --off
php occ upgrade
thenexit
- Check it out in web broser.
更新历史
15 Mar 2017: 首次发布 16 Mar 2017:
- 补上 Docker 容器内访问主机提供的 MariaDB
- 详细描述 Android app 和 iOS app 的价格区别.
- 详细描述 Nextcloud 初始配置里数据库的设定
18 Apr 2017:
- 修正:在 “配置 SSL 证书” 一节里 生成证书前需要先重启 Nginx
- 修正:文中使用
systemctl reload nginx
的地方都改为systemctl restart nginx
,否则会有一些奇怪的小毛病,比如循环重定向(net::ERR_TOO_MANY_REDIRECTS
)之类的问题。