Bookmarks

You haven't yet saved any bookmarks. To bookmark a post, just click .

  • Docker Nextcloud 搭建

  • 前言

    毫无疑问,Docker是个实用的工具,关于Docker你可以找到无数技术文章,从告诉你什么是Docker到使用Docker搭建复杂的服务集群,应有尽有。

    但包括我在内的大多数人,既不具备足够的技术水平,也缺乏足够的应用场景,去应用Docker那些纷繁复杂的功能,也不会愿意去花费大量时间研读各种官方文档,对大多数人而言,使用Docker的原因无外乎几个原因:

    • 节约配置时间:可以直接使用别人已经预配置好的环境直接运行应用
    • 不影响原系统:同虚拟机近似的机制,不需要时直接删除即可

    目前网络上使用 Docker 搭建 Nextcloud 的文章挺多,但很难让人一步一步按步就班就能完成的, 特别是在SSL证书配置这一关键问题上,浪费了本人不少时间尝试诸如nginx-proxy+letsencrypt-nginx-proxy-companion这样的工具,但最终还是放弃,对于nginx这样的基础服务而言,太多黑箱实在不好,我们需要的大多数功能,使用手动配置并不困难。

    本文要实现的目标是快速搭建一个配置好SSL证书的Nextcloud服务器,且不占用主机443端口,非常适合建站的朋友在主站之外使用诸如cloud.domain.com的子域名为自己搭建云存储服务,用于小范围的快速文件分享或者个人文件存储。

    本文所使用的服务器环境为 Ubuntu 18.04 LTS,经测试在 Ubuntu 16.04 LTS上同样适用,CentOS 7.5环境待测试。

    搭建完成体验地址:点击访问
    用户名 guest 密码 Guest12345


    Docker 环境搭建

    在 Ubuntu 系统中安装 Docker

    推荐使用 snap 安装 docker, 只需要在命令行中输入 snap install docker, 稍等片刻即可完成安装。

    docker-nextcloud1.png

    当然也可以使用 apt-get 进行安装,如果是新安装的系统记得先 apt-get update 一下,安装命令如下:

    sudo apt-get install docker.io

    使用 Portainer 进行 Docker 可视化管理

    本文面向的是 Docker 的初级使用者,所以我非常推荐使用 Portainer 这样的图形化 Docker 管理器,在完成相关服务搭建后关闭即可,当然所有通过 Portainer完成的操作都可以通过命令行完成。

    安装方式如下:

    • 创建 Portainer数据卷
    docker volume create portainer_data
    
    • 运行 Portainer 容器
    docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data --name portainer portainer/portainer
    

    待服务器拉取镜像完成,Portainer就安装成功了,绑定的端口是9000,可以通过服务器IP:9000 进行访问:

    docker-nextcloud-portainer1.png

    首次访问需要创建初始用户,创建之后选择 Local 连接:

    docker-nextcloud-portainer2.png

    Portainer 的界面比较美观,对新手而言功能足够强大:

    docker-nextcloud-portainer3.png

    一些 Docker 的基本操作

    本部分内容主要针对下文所使用到的操作进行说明,并不打算详细说明,有兴趣的朋友可以查看文末的相关内容链接学习,以下是本文涉及到的全部命令。

    运行容器

    docker run

    我们常使用的参数主要包括以下几个:
    -d 后台运行容器
    -P 自动映射端口
    -p xxxx:xxxx 手动映射端口
    -v 绑定volume或者主机文件夹到容器
    --name abcd. 给容器命名,若省略则随机生成容器名

    查看容器状态

    docker ps

    直接运行时显示正在运行的容器,使用参数-a则显示所有容器

    启动停止重启容器

    docker start 容器名
    docker stop 容器名
    docker restart 容器名

    容器名可以使用 docker ps -a 获得。

    删除容器

    docker rm 容器名

    注意在删除容器之前,须先停止容器

    复制容器内文件

    docker cp 容器名:容器内路径 复制目标位置

    所有操作既可以使用命令行,也可以使用 Portainer 图形化操作,除 docker run和 docker cp之外,我强烈推荐刚开始时其他操作全部使用 Portainer,待熟练之后可以关闭该工具使用命令行管理。

    使用 Docker 镜像搭建服务的一般方法

    使用 Docker 搭建网络应用,最方便快捷的方式无疑是直接使用现成的 Docker 镜像了,一行 docker run命令,一个服务就开始运行,不需要时直接删除,干干净净。

    体验新应用的时候这样可以,但如果真的要长期使用这项服务,只 docker run 一下还是不够的,我们要考虑:

    • 需要将容器端口映射到主机端口,方便端口转发
    • 需要将用户数据和配置文件从容器暴露,方便应用升级和应用配置

    端口的问题容易解决,只需要将容器端口映射到某个外部端口,避免每次容器重启绑定的端口变化即可,所以最关键的问题便是搞清楚,容器运行时的用户数据和配置文件位置,然后通过 volume 存储或者直接 bind 主机文件。

    基于以上考虑,使用第三方构建的镜像时,一般步骤如下:

    • 从 Docker hub 或者其他类似服务找到所需的镜像文件
    • 使用 docker run 命令测试是否能够在我们的服务器环境上正常运行
    • 通过容器相关文档或容器运行生成的 volume 判断需要将哪些数据持久存储
    • 对需要持久存储的数据选择使用 volume 或者 bind 方式
    • 如果使用 bind 方式,从已经正常运行的容器中使用 docker cp 命令将初使内容复制到主机中或者在主机中新建相应空文件夹(如果是配置文件必须使用 docker cp 复制,否则很多服务无法正常运行)
    • 使用 docker run 命令的 -p 参数绑定端口 -v 绑定卷或文件夹,再次运行容器
    • 若服务无法正常运行,查看 Log 并针对报错内容进行修改

    我们以nginx为例进行说明:

    我们直接运行 Docker Hub 上的 nginx 官方镜像:

    docker run -d -P nginx
    

    然后使用 docker ps 查看到 nginx 已经运行了

    docker-nextcloud-example2.png

    Docker 自动分配将容器的80端口映射到了主机的32768端口,此时我们访问服务器IP:32768就能看到 nginx服务已经正常运行了

    docker-nextcloud-example3.png

    下面我们要做的主要工作就是找到需要持久存储的文件,最明显的就是网站主目录以及配置文件,通过查看 Docker Hub 的 nginx 官方页面,可以知道镜像内部 网站主目录为 /usr/share/nginx/html ,配置文件目录为 /etc/nginx ,我们需要将这两个文件夹绑定到主机。

    为方便管理,对 Docker 中容器的相关的配置文件建议统一存放

    由于本文使用的是root用户,下文所有~均指/root

    • 新建 Docker 相关文件的存储目录
    mkdir ~/docker
    
    • 从 Docker nginx 容器中复制初始配置文件:
    docker cp nginx-name:/etc/nginx ~/docker
    

    注意这里的 nginx-name 指的是 nginx 容器的名字,因为我们未使用 --name 来指定名称,因此容器的名字会是 Docker 随机生成的,我们通过 docker ps 获得。

    docker-nextcloud-example4.png

    • 新建网站主目录
    mkdir ~/wwwroot
    

    现在我们要做就是删除原容器,并再次运行,但这一次进行端口映射和目录绑定,使用命令行的话,内容如下,这次我们使用了--name来命名

    docker run -d --name nginx \
    -v /root/docker/nginx:/etc/nginx \
    -v /root/wwwroot:/usr/share/nginx/html \
    -p 80:80 \
    -p 443:443 \
    nginx
    

    容器顺利运行,由于我们直接将容器80端口映射到了主机80端口,此时直接访问http://服务器IP 即可

    不过由于目前我们的网站主目录是空的,打开 http://服务器IP 会出现403错误,我们在网站主目录下新建一个index.html文件,并输入 Hello World!

    touch ~/wwwroot/index.html
    echo 'Hello World!' > ~/wwwroot/index.html
    

    刷新一下页面,就可以看到正常显示 Hello World!

    至此,一个 nginx 服务就通过 Docker 正常运行了,我们可以修改 nignx配置,也可以修改网站内容,即使容器删除,再次新建容器后绑定文件夹后又一切照旧。

    我们可以根据我们的需要绑定更多目录,或者将容器内的某些文件使用 volume 进行存储,下文中我们就会需要增加一个 Letsencrypt 的证书目录的绑定。

    使用 Nextcloud 官方镜像搭建 Nextcloud服务

    Docker Hub上有很多Nextcloud的镜像,经过试用,最终我还是选择了官方镜像
    Nextcloud 的官方 Github 页面有着详细的使用说明,并提供了多样化的选择,可以查看这个页面并根据自己的需求选择使用。

    官方 Github 页面上提供的 docker-compose 文件很完善,基本无须任何修改,我们就可以在我们的服务器上搭建起 Nextcloud 服务

    本文中使用的是insecure/mariadb-cron-redis/fpm/目录下的docker-compose文件,地址在这里

    为什么选择 insecure, 是因为使用其他两个总是尝试多次才成功配置ssl,配置成功ssl后又发现,如果不把容器443端口直接映射到主机443端口的话,还是需要其他Web服务器进行端口转发,而进行转发的nginx服务器同样需要配置ssl,不如直接手动申请证书,手动设置,反倒不容易出错。

    具体步骤如下:

    将 官方提供的 docker-compose 文件下载到服务器

    由于git无法通过clone下载单个文件夹,我们通过wget结合文件原始地址逐一下载,具体方式是——在本地新建对应的文件夹,进入文件夹后,wget+对应文件夹中文件链接,具体步骤如下:

    mkdir -p ~/docker/docker-compose/nextcloud
    cd ~/docker/docker-compose/nextcloud
    
    mkdir app 
    cd app
    wget https://raw.githubusercontent.com/nextcloud/docker/master/.examples/docker-compose/insecure/mariadb-cron-redis/fpm/app/Dockerfile
    wget https://raw.githubusercontent.com/nextcloud/docker/master/.examples/docker-compose/insecure/mariadb-cron-redis/fpm/app/redis.config.php
    
    cd ..
    mkdir web
    cd web
    wget https://raw.githubusercontent.com/nextcloud/docker/master/.examples/docker-compose/insecure/mariadb-cron-redis/fpm/web/Dockerfile
    wget https://raw.githubusercontent.com/nextcloud/docker/master/.examples/docker-compose/insecure/mariadb-cron-redis/fpm/web/nginx.conf
    
    cd ..
    wget https://raw.githubusercontent.com/nextcloud/docker/master/.examples/docker-compose/insecure/mariadb-cron-redis/fpm/db.env
    wget https://raw.githubusercontent.com/nextcloud/docker/master/.examples/docker-compose/insecure/mariadb-cron-redis/fpm/docker-compose.yml
    

    其中具体文件的下载地址,可以通过在 Github 该文件页面,点击 Raw 之后获得。

    使用 docker-compose BUILD 镜像并运行

    完成上面的操作后,我们就已经将整个官方提供的 docker-compose 示例复制到了我们的服务器上,如果你不需要使用SSL,那么只需要将配置文件中留空的密码补全就可以了,如果你和我一样需要使用SSL,还需要:

    • 申请证书,并增加SSL证书的文件夹绑定,使容器能够使用主机中的证书
    • 修改nginx配置文件实现HTTPS访问

    首先我们只将配置文件中的密码补全,共有两处
    docker-nextcloud-build1.png
    docker-nextcloud-build2.png
    之后BUILD镜像并运行:

    docker-compose build --pull
    docker-compose up -d
    

    docker-nextcloud-build3ch.png

    所有容器正常运行,此时访问http://服务器IP:8080就可以进入Nextcloud界面,此时创建一个用户就可以进入Nextcloud文件管理界面。

    docker-nextcloud-success1.png
    docker-nextcloud-success2.png

    通过 Portainer 中的 Logs 可以看到容器运行正常,数据库连接正常,我们已经可以正常上传下载分享文件,但关键的工作还未完成,主要包括:

    • 申请SSL证书
    • 配置 nginx 进行端口转发及HTTPS访问

    申请 SSL 证书

    HTTPS 取代 HTTP 是大势所趋,随着 Let's Encrypt 等免费 SSL 证书的出现,越来越多的网站开始为自己加上一把小锁,安全之外还多一份美观,既然免费,我们怎么有理由拒绝,本部分将使用Cerbot来申请 Let's Encrypt 提供的免费通配符证书。

    获取 Certbot 客户端

    使用 wget 获取 Cerbot客户端:

    wget https://dl.eff.org/certbot-auto
    

    增加可执行权限:

    chmod a+x certbot-auto
    

    申请证书

    之后执行以下命令即可开始申请免费SSL证书:

    
    ./certbot-auto certonly -d "*.betas.me" --manual --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory
    

    注意将betas.me替换成你的域名。

    docker-nextcloud-ssl1.png

    根据提示填写即可,最后一步需要到你的域名管理页面添加一个TXT类的解析,Host名名是_acme-challege,值为下面一行所提供的:

    docker-nextcloud-ssl2.png

    去你的域名管理页面添加即可,添加后请稍等片刻待DNS生效即可,经测试一般几分钟就可以,之后点击回车确认即可,如果正确添加了 TXT 解析值,就会提示 SSL 证书申请成功。

    可以看到 SSL 证书保存在 /etc/letsencrypt/live下,但要注意的是live下保存的实际上是软连接,原文件位置是在/etc/letsencrypt/archive文件夹下,如果我们直接绑定/etc/letsencrypt/live到容器,容器将会因无法找到链接文件而报错,所以我直接将/etc/letsencrypt目录绑定到容器。

    配置 SSL

    在部署 Nextcloud 服务时,已经包含了一个 nginx 容器,完全可以通过将该 nginx 的配置文件绑定主机文件并进行修改来实现HTTPS访问,但这种情况下,一般需要将容器内的443端口直接映射到主机443端口,否则访问时必须以https://域名:端口号的形式,还是需要主机内其他Web服务器进行端口转发。

    所以,我推荐不通过 Nextcloud 中的 nginx 配置 HTTPS,而是直接通过在主机内再运行一个 nginx(当然你也可以选择其他Web服务器),并直接在该 nginx 内进行 HTTPS 配置以及端口转发。

    下面将两种方式分别描述。

    配置 Nextcloud 容器外 nginx 端口转发

    大部分读者在架设 Nextcloud 之前 已经部署过其他服务,一般也已经安装了 nginx 等 Web 服务器,443端口已经处于被占用状态,所以通过上一部分的做法时不得不通过增加端口号来访问,最后还是需要在容器外增加端口转发,所以我建议直接使用本部分的方法。

    Nextcloud 容器外既可以是非 Docker 环境的 nginx 也可以是 Docker 环境中的另一个 nginx ,这里我们同样采用容器,我们要实现的目标是将 http://服务器IP:8080 转发到https://cloud.betas.me。

    如果你已经搭建过 nginx 服务,请直接参考修改 nginx 配置文件即可。

    还记得我们在本文开始曾经将 nginx 作为示例进行了搭建,现在我们比之前需要增加证书目录的绑定,删除之前的nginx,用以下命令新建一个:

    docker run -d --name nginx \
    -v /root/docker/nginx:/etc/nginx \
    -v /root/wwwroot:/usr/share/nginx/html \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -p 80:80 \
    -p 443:443 \
    nginx
    

    之后我们在 /root/docker/nginx/conf.d 目录下新建一个cloud.域名.conf 文件,内容如下:

    server {
           listen 443 ssl http2;
           server_name cloud.betas.me;
           ssl_certificate /etc/letsencrypt/live/betas.me/fullchain.pem;
           ssl_certificate_key /etc/letsencrypt/live/betas.me/privkey.pem;
           ssl_trusted_certificate  /etc/letsencrypt/live/betas.me/chain.pem;
           ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
           ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
                    ssl_prefer_server_ciphers on;
                    ssl_session_cache shared:SSL:10m;
                    ssl_session_timeout 30m;
           add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://服务器IP:8080;
        }
    }
    
    

    之后重启 nginx 容器,即可实现通过https://cloud.betas.me 访问 Nextcloud服务:

    docker-nextcloud-finish2.png

    直接通过 Nextcloud 内的 nginx 配置 SSL

    重新部署 Nextcloud 服务

    如果直接通过 Nextcloud 内的 nginx 配置 SSL,我们需要将 nginx 配置文件绑定主机文件,并将 SSL 证书文件夹绑定到容器,这修改 docker-compose.yml 文件并重新部署 Nextcloud。

    我们先通过docker cp命令将 Nextcloud 容器内部的 nginx 初始配置文件复制出来

    docker cp nextcloud_web_1:/etc/nginx ~/docker/nextcloud
    

    之后修改 ~/docker/docker-compose/nextcloud 中的 docker-compose.yml文件,添加如下内容:

    docker-nextcloud-rebuild.png

    - /root/docker/nextcloud/nginx:/etc/nginx
    - /etc/letsencrypt:/etc/letsencrypt
    

    之后通过 Portainer 删除相关容器及 volume,重新BUILD镜像并运行:

    docker-compose build --pull
    docker-compose up -d
    

    现在我们就可以自由修改 Nextcloud Stack 包含的 nginx 的配置了。

    在 Nextcloud 容器内部配置 nginx

    我们在 Nextcloud 内部绑定nextcloud.yourdomain.com形式的子域名,配置完成后可以通过
    https://nextcloud.yourdomain.com:9090 进行访问。

    修改/root/docker/nextcloud/nginx/nginx.conf文件内容,将之前的listen 80替换为红框中的内容:

    docker-nextcloud-ssl3.png

        listen 443 http2 ssl;
            server_name nextcloud.betas.me;
            ssl_certificate /etc/letsencrypt/live/betas.me/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/betas.me/privkey.pem;
            ssl_trusted_certificate  /etc/letsencrypt/live/betas.me/chain.pem;
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
            ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
                    ssl_prefer_server_ciphers on;
                    ssl_session_cache shared:SSL:10m;
                    ssl_session_timeout 30m;                
    

    之后重启容器 nextcloud_web_1,现在我们就可以通过访问https://nextcloud.yourdomain.com:9090进入到 Nextcloud界面了,如果我们直接将容器的443端口映射到主机的443端口,此时就已经可以直接通过访问 https://nextcloud.yourdomains.com 进行访问,但因为我们使用了9090端口,所以如果你不想每次访问时都需要输入端口号的话,还需要在容器外进行端口转发,端口转发设置的方式参考上一部分内容。

    docker-nextcloud-finish1.png

    脱水正序版待更新