我以前寫過一篇 Nextcloud 安裝教學,最近設定了一台新的 Pi,記錄下從無到有的完整設定過程,包含基本設定、路由器、防火牆等。安裝過程若遇問題,可搭配各段落 References 服用。本文使用 Raspberry Pi 作為硬體,其中大部分設定用在 Debian / Ubuntu 也沒有問題。
本文會用兩顆外接硬碟組磁碟陣列,設定 DDNS、Nginx,並安裝 Nextcloud,以及後續的 PHP 調校與 Redis 快取。
準備工作
- Raspberry Pi,我使用 4B
- 記憶卡
- 外接硬碟或硬碟外接盒,如果要組磁碟陣列需要兩顆。
- 路由器
- 能取得公網 IP 之網路
- 一個域名
首先讓路由器接上網路,下載 Raspberry Pi Imager,將記憶卡寫入 Raspberry Pi OS LITE。
接著將記憶卡插上 Pi,接上螢幕後開機,帳號是 pi,密碼是 raspberry。
靜態 IP 設定
路由器預設是 DHCP 自動分配 IP,可能會浮動,對穩定性不太好,所以我們會幫 Pi 設定一個 static LAN IP,如 192.168.0.2。
Ref: Raspberry Doc
編輯 /etc/dhcpcd.conf
sudo cp /etc/dhcpcd.conf /etc/dhcpcd.backup # 備份
sudo vim /etc/dhcpcd.conf # Feel free to use Nano or something else :)
找到以下幾行,拿掉註解
interface eth0
static ip_address=192.168.0.2/24 # Pi 的 IP 位址, /24 為 netmask,要記得加
static ip6_address=fd51:42f8:caae:d92e::ff/64 # IPv6,随意
static routers=192.168.0.1 # 路由器位址
static domain_name_servers=1.1.1.1 8.8.8.8 fd51:42f8:caae:d92e::1 # DNS Server IP
若不確定 router ip,可使用 ip a
指今查詢。
完成後重開機,用 ip a
檢查有無更新。
基本設定
我們做一些 Pi 的設定
sudo raspi-config
首先改密碼:
System Options -> Password
啟用 SSH:
Interface Options -> SSH -> Yes
然後跑下更新
sudo apt update
sudo apt upgrade
SSH 換 Port
為了安全性考量,我們將 SSH 換一個 Port。編輯 SSH 設定檔:
sudo vim /etc/ssh/sshd_config
找到以下行,將預設的 22 換成你要的 port,以 22222 為例:
Port 22222
接著重啟 SSH
sudo systemctl restart sshd
接下來可以從你的電腦連上 Pi
ssh -p 22222 [email protected]
設定 RAID 磁碟陣列
為了避免因硬碟壞掉導致資料遺失,我們設定 RAID 1 來鏡像兩顆硬碟:
Refs:
- https://www.ricmedia.com/build-raspberry-pi3-raid-nas-server/
- https://jlamoure.net/blog/raspberry-pi-raid-1/
安裝 mdadm
sudo apt install mdadm -y
RAID 需要重開機才能讓核心載入需要的檔案:
sudo reboot
接著插入兩顆硬碟,待會需要格式化,裡面不要存放資料。檢查硬碟編號:
lsblk
假設兩顆分別是 /dev/sda
和 /dev/sdb
,先建立 GPT 和分割區:
sudo fdisk /dev/sda
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help):
g # 建立 GPT 分割表
n # 建立分割區,ENTER 到底
w # 寫入變更,無法復原資料
q
重復 /dev/sdb
。
再跑一次 lsblk
,應該能看到出現 /dev/sda1
和 /dev/sdb1
,接著建立 RAID 1:
# mint 可以換你喜歡的名字
sudo mdadm --create --verbose /dev/md/mint --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1
lsblk
就會看到 sda1 和 sdb1 下面出現了 /dev/md/mint
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 3.7T 0 disk
`-sda1 8:1 0 3.7T 0 part
`-md127 9:127 0 3.7T 0 raid1
sdb 8:16 0 3.7T 0 disk
`-sdb1 8:17 0 3.7T 0 part
`-md127 9:127 0 3.7T 0 raid1
檢視 RAID 資訊:
sudo mdadm --detail /dev/md/mint
接著寫入變更:
sudo -i
mdadm --detail --scan >> /etc/mdadm/mdadm.conf
格式化 RAID 分割區:
sudo mkfs.ext4 -v -m .1 -b 4096 -E stride=32,stripe-width=64 /dev/md/mint
掛載分割區:
sudo mkdir /mnt/data
blkid # copy the uuid of /dev/md127 or /dev/md/mint
sudo vim /etc/fstab
# Add this line
UUID=your-uuid /mnt/data ext4 defaults,nofail 0 2 # 把 your-uuid 換成你的 UUID
接著重開機,如果開不起來可以再試一次。
Cloudflare DDNS
由於我使用的是浮動 IP,需要設定 DDNS,我使用 Cloudflare 做 DNS 託管,之前寫過一篇 Cloudflare 設定 DDNS 教學,但我使用的程式已經停止維護,這次找到一個更好用的 NewFuture/DDNS。
首先安裝 git
sudo apt install git
Clone 程式下來:
sudo git clone https://github.com/NewFuture/DDNS.git /usr/share/
建立設定檔:
sudo mkdir /etc/DDNS
sudo python /usr/share/DDNS/run.py -c /etc/DDNS/config.json
sudo vim /etc/DDNS/config.json
到 Cloudflare 申請一支 token,設定其有編輯區域 DNS 的權限:https://dash.cloudflare.com/profile/api-tokens
編輯設定檔:
{
"$schema": "https://ddns.newfuture.cc/schema/v2.8.json",
"debug": false,
"dns": "cloudflare",
"id": "", # 使用 Token 故留空
"index4": "public",
"index6": "default",
"ipv4": [
"cloud.example.com" # 你的 domain
],
"ipv6": [
],
"proxy": null,
"token": "the-token", # 填入你的 token
"ttl": null
}
測試執行:
sudo python /usr/share/DDNS/run.py -c /etc/DDNS/config.json
檢查是否能成功更新 Cloudflare 上的 IP
安裝 systemd service:
sudo /usr/share/DDNS/systemd.sh install
檢查有無執行:
sudo systemctl status ddns.timer
重開 router,故意換 IP,看會不會五分鐘自動更新。
journalctl -u ddns.service
防火牆設定
防火牆我使用最簡單好用的 ufw,首先是安裝:
sudo apt install ufw
sudo ufw allow 22222 # 你前面設定的 SSH port
sudo ufw allow http
sudo ufw allow https
sudo ufw default deny # 預設擋掉
sudo ufw enable # 開啟防火牆
開啟前要確定有開到 SSH 用的 port。
Nginx Setup
接下來設定 Web Server,有別於以往都用 Caddy,我這次改用傳統的 Nginx,後續裝 Nextcloud 比較輕鬆。
Ref: LandChad Nginx
sudo apt install nginx
瀏覽口打開 192.168.0.2,看看有沒有 Nginx 安裝成功的頁面。
接下來要在路由器設定 DMZ,允許外網連線到 Pi。方法有分 Port Forwarding 和 DMZ 兩種,Port Forwarding 只導向指定的幾個 Port,DMZ 則是將所有外網連線交給一個 IP。Port Forwarding 會由路由器做防火牆,DMZ 則是由 Pi 自己做,由於路由器的硬體一般都比較差,用 DMZ 應該會有比較好的效能(但要確定有設定好 ufw),當服務需要用大量的 port 時,DMZ 設定起來也比較輕鬆。本文以 DMZ 做示範。
登入你的路由器 http://192.168.0.1 ,找到 DMZ 設定,將其設為 Pi 的 IP(192.168.0.2),然後重開路由器。完成後,打開你的網址 http://cloud.example.com ,看看有沒有出現 Nginx 預設頁面。
安裝 Certbot
Certbot 可以免費取得 HTTPS 所需的憑證,且自動安裝至系統中並配置 Nginx。
Ref: LandChad Certbot
安裝 Certbot:
sudo apt install python3-certbot-nginx
執行:
sudo certbot --nginx
輸入你用來接收 renew 通知的 email、輸入域名(cloud.example.com)、視需求選擇 Redirect(沒特別原因就選吧!)
再打開一次網頁,看看有沒有換成 https 了。
Nextcloud
Ref:
- Nextcloud Doc
- LandChad Nextcloud 註:此文章是安裝在子路徑(example.com/cloud)而非子網域(cloud.example.com),故其 Nginx 設定檔不適用。
接著要來安裝 Nextcloud 了,先安裝依賴,我使用的是相容於 MySQL 的 MariaDB:
sudo apt install mariadb-server php php-mysql php-gd php-mbstring php-curl php-zip php-xml php-fpm php-intl php-gmp php-bcmath php-exif php-imagick php-bz2
MySQL
sudo mysql
CREATE DATABASE nextcloud;
GRANT ALL ON nextcloud.* TO 'ncadmin'@'localhost' IDENTIFIED BY 'supersecretpassword';
FLUSH PRIVILEGES;
EXIT;
Download Nextcloud
到 https://nextcloud.com/install/#instructions-server 去,複製 .tar.bz2 檔案連結(Details and download options 中),接著用 wget 下載:
wget https://download.nextcloud.com/server/releases/nextcloud-22.1.0.tar.bz2
解壓縮到 /var/www
sudo tar -jxvf nextcloud-22.1.0.tar.bz2 -C /var/www
改變權限:
sudo chown -R www-data:www-data /var/www/nextcloud
sudo chmod -R 755 /var/www/nextcloud
建立我們存放檔案的資料來:
sudo mkdir /mnt/data/nextcloud
sudo chown www-data:www-data /mnt/data/nextcloud
啟動 PHP 和 MariaDB:
systemctl enable php-fpm
systemctl start php-fpm
systemctl enable mariadb
systemctl start mariadb
Nginx
接下來設定 Nginx,先確認 Nginx 使用者是以 www-data 執行。檢查 /etc/nginx/nginx.conf 應該出現
user www-data;
再來我們在新增 /etc/nginx/site-available/nextcloud 這個檔案,填入以下內容:
請將 ssl_certificate 的地方換成 /etc/nginx/site-available/default 裡面的路徑,cloud.example.com 也記得換成自己的域名。若你的 PHP 版本為 7.4,修改第二行的路徑成 7.4。
upstream php-handler {
server unix:/run/php/php-fpm.sock;
server 127.0.0.1:9000;
}
server {
listen 80;
listen [::]:80;
server_name cloud.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cloud.example.com;
ssl_certificate /etc/letsencrypt/live/cloud.example.com/fullchain.pem ; # 重點區塊!
ssl_certificate_key /etc/letsencrypt/live/cloud.example.com/privkey.pem ;
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
# Pagespeed is not supported by Nextcloud, so if your server is built
# with the `ngx_pagespeed` module, uncomment this line to disable it.
#pagespeed off;
# HTTP response headers borrowed from Nextcloud `.htaccess`
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
# Path to the root of your installation
root /var/www/nextcloud;
# Specify how to handle directories -- specifying `/index.php$request_uri`
# here as the fallback means that Nginx always exhibits the desired behaviour
# when a client requests a path that corresponds to a directory that exists
# on the server. In particular, if that directory contains an index.php file,
# that file is correctly served; if it doesn't, then the request is passed to
# the front-end controller. This consistent behaviour means that we don't need
# to specify custom rules for certain paths (e.g. images and other assets,
# `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
# `try_files $uri $uri/ /index.php$request_uri`
# always provides the desired behaviour.
index index.php index.html /index.php$request_uri;
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
location = / {
if ( $http_user_agent ~ ^DavClnt ) {
return 302 /remote.php/webdav/$is_args$args;
}
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Make a regex exception for `/.well-known` so that clients can still
# access it despite the existence of the regex rule
# `location ~ /(\.|autotest|...)` which would otherwise handle requests
# for `/.well-known`.
location ^~ /.well-known {
# The rules in this block are an adaptation of the rules
# in `.htaccess` that concern `/.well-known`.
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
location /.well-known/pki-validation { try_files $uri $uri/ =404; }
# Let Nextcloud's API for `/.well-known` URIs handle all other
# requests by passing them to the front-end controller.
return 301 /index.php$request_uri;
}
# Rules borrowed from `.htaccess` to hide certain paths from clients
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
# Ensure this block, which passes PHP files to the PHP process, is above the blocks
# which handle static assets (as seen below). If this block is not declared first,
# then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
# to the URI, resulting in a HTTP 500 error response.
location ~ \.php(?:$|/) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
fastcgi_param front_controller_active true; # Enable pretty urls
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ \.(?:css|js|svg|gif|png|jpg|ico)$ {
try_files $uri /index.php$request_uri;
expires 6M; # Cache-Control policy borrowed from `.htaccess`
access_log off; # Optional: Don't log access to assets
}
location ~ \.woff2?$ {
try_files $uri /index.php$request_uri;
expires 7d; # Cache-Control policy borrowed from `.htaccess`
access_log off; # Optional: Don't log access to assets
}
# Rule borrowed from `.htaccess`
location /remote {
return 301 /remote.php$request_uri;
}
location / {
try_files $uri $uri/ /index.php$request_uri;
}
}
儲存後重啟 Nginx:
sudo systemctl reload nginx
打開 https://cloud.example.com ,就可以填入剛設定的資料庫密碼,以及選擇 /mnt/data/nextcloud 做為目標資料夾,完成安裝程式。
Redis
Nextcloud 可以透過安裝 Redis 做快取來優化效能:
Ref: Nextcloud Manual: Memory Caching
sudo apt install redis-server php8.0-redis
sudo vim /var/www/nextcloud/config/config.php
加入以下內容:
'memcache.local' => '\\OC\\Memcache\\APCu',
'memcache.distributed' => '\\OC\\Memcache\\Redis',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'redis' => [
'host' => 'localhost',
'port' => 6379,
],
重啟 PHP:
sudo systemctl restart php8.0-fpm.service
PHP 設定
Ref: Nextcloud Manual: php-fpm configuration notes
找到以下設定並修改:
sudo vim /etc/php/7.4/fpm/php.ini
memory_limit = 512M # PHP 記憶體上限
upload_max_filesize = 2000M # 最大上傳大小
opcache.enable = 1
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.memory_consumption = 128
opcache.save_comments = 1
opcache.revalidate_freq = 1
sudo vim /etc/php/7.4/cli/php.ini
# 加入這行
apc.enable_cli = 1
sudo systemctl restart php7.4-fpm.service
設定 Cron
Ref: Nextcloud Manual: Background jobs Nextcloud 需要定時跑一些程序來更新快取,我們使用效能最好的 cron:
sudo crontab -u www-data -e
# 加入以下這行
*/5 * * * * php -f /var/www/nextcloud/cron.php
到這邊 Nextcloud 的基本設定就告一段落了,Nextcloud 有非常多的 App 可以安裝,讓你的 Nextcloud 成為一個強大的辦公平台。希望你有愉快的使用體驗!