oing9179 的笔记本儿

用 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

  1. 执行命令来安装 Nginx apt-get install nginx,配置 Nginx 需要在安装 Nextcloud 后进行。
  2. 执行命令打开防火墙的 80 端口 ufw allow 80/tcp

安装 / 配置 MariaDB

  1. 执行命令来安装 MariaDB apt-get install mariadb-server mariadb-client
  2. 执行命令来初步配置 MariaDB mysql_secure_installation,然后按照提示进行操作
  3. root 登录 mysql,执行下面的 SQL 语句,为 Nextcloud 的数据库做准备
    1
    2
    3
    4
    5
    6
    -- 创建 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
2
3
4
5
6
7
8
9
10
# 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 证书

  1. 安装 letsencrypt apt-get install letsencrypt
  2. 创建静态网站的目录 mkdir --parents /var/www/yun.example.com,稍后 Let’s Encrypt 会用到它
  3. 创建文件 /etc/nginx/sites-available/yun.example.com 并编辑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # "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;
    }
    }
  4. 创建软链接,因为 Nginx 载入所有 /etc/nginx/sites-enabled/ 下的配置文件

    1
    ln -s /etc/nginx/sites-available/yun.example.com /etc/nginx/sites-enabled/yun.example.com
  5. 重启 Nginx systemctl restart nginx

  6. 执行命令来生成 SSL 证书
    1
    letsencrypt certonly --webroot -w /var/www/yun.example.com --domain "yun.example.com"

至此,SSL 证书已经生成好了,接下来将配置 Nginx。

配置 Nginx

  1. 编辑配置文件 /etc/nginx/sites-available/yun.example.com

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # "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;
    }
    }
  2. 验证配置文件语法 并 重启 Nginx:

    1
    2
    nginx -t
    systemctl restart nginx
  3. 用网页浏览器打开地址 https://yun.example.com 查看效果

配置 Nextcloud

首先定位目录到上面 docker create-v 后面的 路径 下的 config 文件夹,编辑 config.php 文件。

配置 trusted_domains

找到 trusted_domains,在下面按照格式添加自己的域名,比如像这样:

1
2
3
4
'trusted_domains' =>
array (
0 => 'yun.example.com',
)

配置 overwritehost

官方文档 提到,有时候 Nextcloud 自己重定向时候会重定向到错误的地址,加上下面这行就好了:

1
'overwritehost' => 'yun.example.com',

配置缓存

按照 官方文档 的说明,个人使用的话只需要添加下面这行就行了:

1
'memcache.local' => '\OC\Memcache\APCu',

最后需要重启 Nextcloud/Docker容器 使配置生效。

1
docker restart nextcloud

主机的防火墙配置

因为容器内的 Docker 需要访问主机的 MariaDB,因此需要知道 Docker 容器的网关和 IP 地址。

  1. 进入并运行容器内的 bash

    1
    docker exec -i nextcloud /bin/bash -il
  2. 获取容器 IP 和网关(Gateway)

    1
    ip route show default

    输出大概是这样:

    1
    2
    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.

  3. 添加防火墙白名单,允许来自容器(172.17.0.2)的所有 IP 包
    1
    ufw allow from 172.17.0.2

初始设置

  1. 用浏览器打开 https://yun.example.com
  2. 填写管理员的用户名和密码,以后将使用这个帐号来管理 Nextcloud
  3. 数据库设定里,数据库选择 MySQL / MariaDB,其余的参考下面的配置

    | 名称 | 注释 |
    |:———|:————————————————————-|
    | 用户名 | nextcloud |
    | 密码 | nextcloud 用户的密码 |
    | 地址 | 比如 172.17.0.1, 也可以加上端口号 像这样 172.17.0.2:3306 |
    | 数据库名 | nextcloud |

部署完成

至此,Nextcloud 的安装与配置就全部结束了。移动端 app 可以到这里下载:

更新 Nextcloud

  1. git pull
  2. docker-compose build
  3. docker start --attach nextcloud-app then <CTRL+C> and wait it exits.
  4. docker exec -it --user www-data nextcloud-app /bin/bash -il
  5. php occ maintenance:mode --off
  6. php occ upgrade then exit
  7. 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)之类的问题。