Hotaru's Notebook

用 Docker 和 Nginx 搭建自己的云服务器(Nextcloud)

Preface

前些阵子瓷国各种网盘纷纷倒下,我也越来越担心自己的数据安全,没准哪天我的网盘帐号就被"无缘无故"的删掉什么的,于是我就琢磨着搭建个自己的私人网盘。现在这个时代最不缺的就是轮子,随便一搜就有好几个符合要求的自搭建(Self-Hosted)网盘软件:

综上,我选择 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 的数据库做准备
    -- 创建 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 证书

  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 并编辑
    # "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/ 下的配置文件
    ln -s /etc/nginx/sites-available/yun.example.com /etc/nginx/sites-enabled/yun.example.com
    
  5. 重启 Nginx systemctl restart nginx
  6. 执行命令来生成 SSL 证书
    letsencrypt certonly --webroot -w /var/www/yun.example.com --domain "yun.example.com"
    

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

配置 Nginx

  1. 编辑配置文件 /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;
        }
    }
    
  2. 验证配置文件语法 并 重启 Nginx:
    nginx -t
    systemctl restart nginx
    
  3. 用网页浏览器打开地址 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 地址。

  1. 进入并运行容器内的 bash
    docker exec -i nextcloud /bin/bash -il
    
  2. 获取容器 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.
  3. 添加防火墙白名单,允许来自容器(172.17.0.2)的所有 IP 包
    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:

18 Apr 2017:

#Linux #Nextcloud #Docker #Nginx #cloud #reverse proxy