2020/07/04

[Docker] Nextcloud自有雲建置


Nextcloud是一套用於建立網路空間的Client-Server軟體,換言之就是私人免空

我的blogger日瀏覧量約1000人次,其中1/4是來自大陸牆內,因為眾所周知的原因,他們看不到blogger上google伺服器的圖片 (過牆請見附註)
我想所有站長都知道圖片的重要,一但失去圖片,文章看起來就是垃圾。
不要誤會,我不是針對你
說起圖片站,常見到的像是imgur、upload.cc、Flickr
前兩個確定牆了,Flickr Pro據說能過,但樹大招風(ry

這裡就是私有主機出場的地方了! ⁽⁽٩(๑˃̶͈̀ ᗨ ˂̶͈́)۶⁾⁾

圖片鏈結放在與blogger同一網域下,若整個站被牆那就是另一層面的問題了 ┐(´д`)┌
且我的Nextcloud同時做為檔案主機和圖片主機
所以不只圖片,分享檔案再也不用和該死的百毒網盤大眼瞪小眼wwww
而效果,試試看這條網址: https://cloud.maki0419.com/index.php/s/qw3QEDcaN657bBn

這是我花一週做出的專案,docker真心好玩 (ㆆᴗㆆ)

本機客戶端設定自動同步後,只要在電腦裡把檔案放進資料夾就會自動上傳Nextcloud,接著直接輸入網址就能訪問
有沒有看到文首的圖片? 對,他就在一個blog\nextcloud\login.jpg的路徑下

寫blog時上傳圖片唯一要做的一件事,就是把它拖進去
上傳是機器的事,我就按資料夾名拼網址用就好

本專案核心目標:

  • 最少的步驟建立整個server
  • 定時備份功能
  • 同時做為檔案分享站圖片站,圖片站需要縮址和直鏈訪問

本專案特徵:

  • 使用nextcloud官方image,將來升級就是 docker-compose pull 解決
  • 重寫了docker-compose file將需要填入的部份獨立出來,並降到最少
  • 分開nginx reverse proxy和Nextcloud的compose file,實現擴充彈性
  • 用Cloudflare Worker將img網域做縮址,以產生漂亮的圖片直鏈

本文適合對象:

  • 初級以上的linux操作基礎
  • 有自己的主機或NAS,沒有可以現在租 (不然你檔案想放哪裡?)
  • 會在意中國大陸看不到圖片的blog站長

流程簡述

  1. 起一台新的Linux
  2. 裝docker
  3. git clone下來docker-compose建置檔案和config檔案
  4. 密碼類的個別設定
  5. docker-compose up -d
  6. (選)Restore既有資料和config

硬體架構

機器有兩台,放在我家的NAS做備份伺服器;Digital Ocean租的VPS做主要Server
┌ Synology NAS (Rsync Server)
WWW
└ Digital Ocean Droplet (Main Server)

Main Server系統架構

WWW

nginx Server (Reverse Proxy) (SSL證書申請、Renew)
│  ┌ MariaDB資料庫 (網路只對Nextcloud)
└ Nextcloud
  └ Jobber (Cron) (定時Backup Docker volume,Backup完送至rsync server)

DNS設定和Cache設定

我使用Cloudflare做DNS和Cache
若用其它DNS商請略過Cache設定

SSL相關設定如此是為了讓Let's Encrypt能成功訪問,請留意

DNS Record有三條,一條A指向SERVER_IP,另倆CNAME指向A Record
nextcloud網域DNS Only用做日常操作,以免Cache造成回應錯誤
Cache只設定於cloud和img倆網域上,分享時使用這倆網域以節省主機流量,Cloudflare能夠抓住近99%
  • DNS
    • A: nextcloud.domain.com → SERVER_IP (DNS Only)
    • CNAME: cloud.domain.comnextcloud.domain.com (Proxied)
    • CNAME: img.domain.comnextcloud.domain.com (Proxied)
  • SSL/TLS
    • Always Use HTTPS: Off
    • HTTP Strict Transport Security (HSTS): Disabled
    • Automatic HTTPS Rewrites: (Can enable if needed)
  • Caching
    • Caching Level: Standard
  • Page Rule
    1. *domain.com/.well-known/acme-challenge*
      • Disable Everything
      • Cache Level: Bypass
    2. nextcloud.domain.com/index.php/apps/sharingpath/<NEXTCLOUDUSERNAME>/Public/*
      • Disable Security
      • Browser Integrity Check: Off
      • SSL: Full
      • Browser Cache TTL: a year
      • Cache Level: Cache Everything
      • Edge Cache TTL: a month
      • Automatic HTTPS Rewrites: On
      • Disable Performance
    3. https://cloud.domain.com/*
      • SSL: Full
      • Rocket Loader: Off
      • Cache Level: Cache Everything
      • Automatic HTTPS Rewrites: On
      • Disable Apps

架設

  • 起一台Linux做Main Server,理論上任何能裝Docker的arm64 linux都行
    我推薦使用Digital Ocean,最便宜的方案每個月只要5美元
    這是老牌的主機商,在業界有信譽有口碑,比國內的主機商都穩定得多
    現在的優惠,透過上方推廣鏈結註冊,兩個月內會有100鎂的試用額度
    這足夠玩遍所有功能了,事實上我自己也是會開小號來測功能
    用上方的推廣鏈結,你消費25鎂時我也能拿到25鎂,超難賺的哈哈..
    這裡我選一台Unbuntu x64 LTS
  •   由後台從Consle連入,把SSH port改為自設的port
    vi /etc/ssh/sshd_config
    service ssh restart
  • 注意UFW是否有擋port
    ufw status
    如果它是inactive以外的狀態,請上網找Ubuntu UFW相關文章做調整
    需開放80、443和自設的SSH port
  • 若是租用VPS,建議關了UFW,用VPS後台的Firewall功能即可
  • SSH Client,以root連入,推薦用MobaXterm
    ※提醒
    請用root連入或是su
    docker所有操作都需要root權限,且我建議這些檔案都放在root家目錄下

  • 安裝docker和docker-compose ,參閱官方文件
    1. (選)全面更新
      sudo apt-get update && apt-get upgrade -y
    2. 安裝必要組件
      sudo apt-get install \
          apt-transport-https \
          ca-certificates \
          curl \
          gnupg-agent \
          software-properties-common
    3. 加入gpg key
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    4. 加入repo庫
      sudo add-apt-repository \
         "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
         $(lsb_release -cs) \
         stable"
    5. 安裝Docker和Docker-compose
      sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose
    6. 測試
      docker --version
      安裝成功,印出docker版本號
  • cd到root家目錄
    cd
  • git clone專案
    git clone https://github.com/jim60105/docker-ReverseProxy.git &&\
    git clone https://github.com/jim60105/docker-Nextcloud.git
  • 啟動nginx reverse proxy
    docker-compose -f ./docker-ReverseProxy/docker-compose.yml up -d
  • 進入docker-Nextcloud資料夾
    cd docker-Nextcloud
  • 填入.env檔案
    cp .env_sample .env && vim .env
    • LETSENCRYPT_TEST: 此為設定申請測試SSL證書,現在給true,最後上線前才改false
    • LETSENCRYPT_EMAIL: Let's Encrypt在證書到期時通知你用的email,不會透過這個做驗證。但這也是你對網域的申報,建議正確填入。
    • LETSENCRYPT_HOST: SSL證書網域名稱和別名。以半型逗點「,」分隔,不能用wildcard
    • NEXTCLOUD_TRUSTED_DOMAINS: Nextcloud的信任網域,這是一個安全性設定,以其它的網域訪問Nextcloud時會被擋住
      建議和LETSENCRYPT_HOST填入相同內容但以空白分隔,或可用「*」wildcard字符
      需注意,填入後若要消除,必須到nextcloud container下的/var/www/html/config/config.php中做消除
      此處設定只寫不消,且只在第一次建立Nextcloud設定檔時會讀取
  • 填入db.env檔案
    cp db.env_sample db.env && vim db.env
    • MYSQL_PASSWORD: Nextcloud程式專用帳號的Database密碼
    • MYSQL_ROOT_PASSWORD: Database的root密碼

    下面這兩條可不使用,只有同時設定了才會生效
    設定了上機時會跳過創建主帳號程序,直接開始Nextcloud初使化
    • NEXTCLOUD_ADMIN_USER: 創建你要用的Nextcloud帳號
    • NEXTCLOUD_ADMIN_PASSWORD:創建你要用的Nextcloud密碼
  • 修改jobber部份:
    • 你有Rsync Server,且會按照本文設定
      →建立~/ssh.pas檔案過build,密碼我們後面再填入
      touch ~/ssh.pas
    • 你沒有Rsync Server,定時備份後留在Main Server就好
      →編輯docker-compose.yml,刪除JOB_COMMAND1的後半段、secrets相關內容
    • 你完全不想執行備份
      →編輯docker-compose.yml,刪除secrets相關內容和整個jobber
  • 起機囉~~
    docker-compose up -d
  • 檢查Container是否都有起來
    docker ps -a
  • 檢查SSL是否成功
    docker logs proxy_le -f
    注意紅框處,這樣就是成功
  • 將SSL申請改為正式申請
    vim .env
    第一行LETSENCRYPT_TEST改為false
    ※注意
    因為Let's Encrypt針對網域正式申請有次數限制,不論成功與否,做太多次就會鎖住
    發布前一定要測試成功再轉正,並於申請成功後備份cert
    重做compose
    docker-compose down -v && docker compose up -d
    檢查是否有成功要到正式證書
    注意紅框處,已沒有_test_字樣

Rsync Server設定

  • Synology rsync server設定
    • Rsync是DSM內建功能,開啟「控制台→檔案服務→rsync」
      啟動rsync服務,port可改(或者由上層的router,外自訂轉內22)
    • 「使用者帳號→新增使用者」
      使用者名必須為rsync,密碼記起來
    • 設定NetBackup為可讀寫,其餘禁止
      (這rsync專用的共用資料夾必須名為NetBackup)
    • 使用者建立後,選中rsync使用者「編輯」→「應用程式」頁籤
      全選禁止,再選中「rsync服務→針對IP設定」
      「允許清單→新增IP位址→單一主機」,填入Main Server的IP
  • 回到Main Server,修改upload.sh的設定
    cp shellScript/upload.sh_sample shellScript/upload.sh && vim shellScript/upload.sh
    最後兩行修改如下,填入你的RSYNC_SERVER_IP和PORT
    su - root -c "ssh-keyscan -p 你的PORT 你的RSYNC_SERVER_IP >> ~/.ssh/known_hosts"
    su - root -c "sshpass -f /run/secrets/rsyncpass rsync -e 'ssh -p 你的PORT' -avz --no-p --no-g /backup/ [email protected]你的RSYNC_SERVER_IP::NetBackup/docker_backup/"
    
  • 將shellScript下的檔案權限都改為可執行
    chmod 744 shellScript/* && ls -al shellScript/
    root權限應為rwx
  • 設定rsync server的ssh密碼,填入Rsync Server上rsync使用者的密碼
    echo "你的密碼" > ~/ssh.pas
  • 修改密碼檔權限為-rw-------
    chmod 600 ~/ssh.pas
  • 測試定時備份功能,下面這段的意思是
    「在名為docker-nextcloud_jobber_1的container中,執行jobber test指令,測試名為Backup的定時工作」
    docker exec -it docker-nextcloud_jobber_1 jobber test Backup
    Stderr會報說下載了docker image和加入SSH-Key, 但只要有輸出rsync資訊就是成功
    也別忘了到Rsync Server確認檔案是否存在
    爆了 (´゚д゚`)
    ※提醒
    upload.sh不能在host直接執行,因為密碼檔是以docker secrets的方式處理
    此路徑在host不存在

  • 我做了簡易的log,記錄下執行時間和IP

還原

伺服器都正常運行後,接下來是還原
  • 把備份檔案放回Main Server的/backup資料夾下
    這部份沒有特別建立管道,我是以區網Samba連到NAS,再拖曳進MobaXterm的SFTP傳輸
    因為安全性考量,我不希望建立能自動從我家NAS輸出資料的管道

    假若前面有申請了新的正式SSL證書想要保留,留下reverseproxy字樣的備份不覆蓋
  • 執行Restore
    ./shellScript/restore.sh && ./shellScript/startContainer.sh
    若restore後不希望自啟動,去掉&&後那一段
    ※提醒
    restore邏輯
    1. 由tag為nextcloud和proxy的現存volume中取得清單
    2. 去/backup資料夾找檔案做複原
    故運行前要先有volume存在,意即必須得先docker-compose up一次建立volume,後做restore
     
    ※提醒
    renameVolume.sh的用法如下
    renameVolume.sh oldVolumeName newVolumeName
    rename邏輯
      1. 如果新volume不存在就建立,否則清空延用volume
      2. 將舊volume的檔案傳到新的volume
      3. 砍掉舊的volume
        在建立的過程中不會帶有backup.sh需要的label,所以要由docker-compose up來建立

      img圖片縮址

      img網域的縮址如下:

      https://img.domain.com/OOXX
      =
      https://nextcloud.domain.com/index.php/apps/sharingpath/<NEXTCLOUDUSERNAME>/Public/OOXX

      在Cloudflare操作

      • 先確定是否有按照前面的小節做Cloudflare設定
      • 建一個Worker,內容把這些Code複製進去
      • 修改前三行的內容
        • NextCloudUserName = 你在nextcloud的username
        • SourceHost = 你的img網域
        • TargetHost = 你的nextcloud網域
      • Route img.domain.com/* 到這個Worker

      在Nextcloud操作

      1. 安裝Nextcloud應用程式: Sharing Path
        右上角「應用程式→Files分類」,裝上Sharing path
        注意:
        Sharing Path會開啟「以路徑直鏈訪問公開檔案」功能
        這雖然方便,但會導致路徑可猜的資安問題
        建議此Nextcloud只存放低敏感度資料
      2. 右上角「設定→個人-分享→Sharing Path」,勾上Enable sharing path
      3. 「設定→管理-分享」,勾選以下項目
        • 允許 apps 使用分享 API
        • 允許使用者透過連結分享
          • 允許公開上傳
        • 允許使用者名稱自動補齊在分享對話框
        • 允許這台伺服器上的使用者發送分享給其他伺服器
        • Search global and public address book for users
      4. 在Nextcloud根目錄新增Public資料夾,此資料夾開啟外部唯讀分享,做為分享的根目錄
      5. Public資料夾下放做為img網域的favicon.ico,即Public/favicon.ico

        客戶端

        最後,你會需要一個Nextcloud客戶端,做自動同步
        >>官網<< ლ( • ̀ω•́ )っ
        在這裡可以取得,而且安裝非常簡單
        安裝時請填入沒有過proxy的nextcloud網域

        附註: Nextcloud升級

        因為用了docker,內建的升級功能會有問題,必須在docker image層面升級
        參考官方指南
        docker-compose pull
        docker-compose up -d
        注意,一次只能升級一版
        意即如果要從17升19,要17升18;18再升19
        sed -i -e 's/nextcloud:[0-9.]*-apache/nextcloud:18-apache/g' docker-compose.yml
        docker-compose up -d
        進入網頁確認升級完成,然後
        sed -i -e 's/nextcloud:[0-9.]*-apache/nextcloud:19-apache/g' docker-compose.yml
        docker-compose up -d
        這裡有所有可用的版號

        附註: Content-Security-Policy問題

        我不確定什麼情況會讓Nextcloud觸發Content-Security-Policy Error
        這個問題的解法是在Nextcloud目錄下之.htaccess file加上設定
        這個檔案會在升級時被重置
        docker exec -it docker-nextcloud_app_1 bash
        apt-get update && apt-get install vim -y
        vim .htaccess
        在最後面加上以下幾行,記得把*.domain.com換成你的域名
        <IfModule mod_headers.c>
          Header set Content-Security-Policy " \
              img-src 'self' *.domain.com www.google-analytics.com *.nextcloud.com data: blob:; \
          "
          </IfModule>

        附註: 讓Blogger過牆

        Blogger是放在Google的伺服器,預設狀態牆內無法瀏覧,但我們能用一些方式讓它過牆
        這裡有兩個要素要更動: 域名IP,只要這倆個都不是掛在Google就能通過
        • 購買一個自己的網域,並在Blogger後台設定一個子網域給blogger使用。
          像本站是 blog.maki0419.com
        • 將此網域通過Cloudflare DNS Proxy,這會改變出站IP
          隱藏伺服器的真實IP也有一定的資安保護做用
        這張以內建功能上傳的圖片,網址在哪裡呢?
        以上簡單的操作可讓Blogger本站過牆,但Blogger內建的圖片上傳功能並不會套用自訂網域在圖片網址
        這始得我們只能使用外鏈圖片,不能用Google內建的圖片上傳
        而架設這個「外鏈圖片站」,就是本專案的核心目標 (・`ω´・)

        附註:常用docker指令

        這是寫給自己看的
        不然下次維護我就忘光了 (・ε・)

        列出所有cotainer,-a: 列出包含未啟動的container
        docker ps -a
        列出所有volume
        docker volume ls
        清除所有未被container使用的volume
        docker volume prune
        建立compose,同時用來做驗證
        docker-compose build
        compose狀態,可以用來檢查變數是否有正確代入,環境變數的讀入順序十分麻煩
        docker-compose config
        啟動compose,-d: 以deamon背景服務執行
        docker-compose up -d
        compose操作都可以用-f 給定docker-compose.yml的位置,但需注意有些相對路徑可能會有問題
        docker-compose -f <路徑> up -d
        stop&remove compose的所有container,-v: 同時刪除volume
        docker-compose down
        列出此compose的logs,-f: 持續監聽
        docker-compose logs
        列出指定cotainer的log,-f: 持續監聽
        docker logs <container name>
        重啟compose下的container
        docker-compose restart
        在container內執行指令,常會執行bash來做進入
        docker exec -it <container name> <指令>

        留言版

        留言我一般不會看到,急事請用右側社群網站聯繫我