曾经我们在 Ubuntu 18.04 上面搭建过 Nextcloud 服务器,当时采用的 Web 服务器是 Caddy 和 Apache2。这次,我们把系统升级到 Ubuntu 20.04,顺便把 Web 服务器更改为 Nginx,同样利用 Nextcloud 重新搭建私人云盘。下面介绍一下部署的流程。
1 安装 Nginx
逐行运行以下代码,安装、启动 Nginx Web 服务器,并将其设为随系统启动:
sudo apt update
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
(非必需)检查是否正常运行:
sudo systemctl status nginx
(非必需)更新 Nginx 至最新版本:
# 添加源
echo "deb http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
curl -o /tmp/nginx_signing.key https://nginx.org/keys/nginx_signing.key
sudo mv /tmp/nginx_signing.key /etc/apt/trusted.gpg.d/nginx_signing.asc
# 更新
sudo apt update
sudo apt install nginx -y
# 如果在配置 php 过程中出现问题,需要检查用户是否检查“/etc/nginx/nginx.conf”配置中的用户是否在更新过程中出现了变更。
user www-data;
2 安装 PHP
安装 PHP 及 Nextcloud 依赖的 PHP-FPM 软件包, Ubuntu 20.04 默认支持的 PHP 版本是 v7.4:
sudo apt install php-fpm php-curl php-cli php-mysql php-gd php-common php-xml php-json php-intl php-pear php-imagick php-dev php-common php-mbstring php-zip php-soap php-bz2 php-bcmath php-gmp -y
修改 /etc/php/7.4/fpm/php.ini,取消“date.timezone =”行的注释,并添加自己的时区代码,以上海为例:
date.timezone = Asia/Shanghai
修改 /etc/php/7.4/cli/php.ini,取消“cgi.fix_pathinfo=1”行的注释,并将值改成“0”:
cgi.fix_pathinfo=0
修改 /etc/php/7.4/fpm/pool.d/www.conf,取消下列五行代码的注释:
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
逐行运行以下代码,重启 PHP,并将其设为随系统启动:
sudo systemctl restart php7.4-fpm
sudo systemctl enable php7.4-fpm
(非必需)检查PHP-FPM服务:
sudo ss -xa | grep php
sudo systemctl status php7.4-fpm
3 安装MariaDB
逐行运行以下代码,安装 MariaDB,并将其设为随系统启动:
sudo apt install mariadb-server mariadb-client -y
sudo systemctl enable mariadb
(非必需)检查 MariaDB 是否正常运行:
sudo systemctl status mariadb
配置 MariaDB:
sudo mysql_secure_installation
在配置界面,按提示进行配置:除第一步为 root 用户设置登录密码外,一路按“Enter”进行配置即可。
逐行运行以下代码,创建 Nextcloud 所需的数据库信息(其中,代码中的“nextcloud”是数据库名称,“nextclouduser”为数据库用户名,“your-password”为数据库用户的密码,请自行修改替换):
sudo mysql
create database nextcloud;
create user nextclouduser@localhost identified by 'your-password';
grant all privileges on nextcloud.* to nextclouduser@localhost identified by 'your-password';
flush privileges;
exit
4 下载Nextcloud文件
(非必需)创建 Nextcloud 安装路径 /var/www,假如该路径已经存在,可以忽略;如果需要自定义其他的路径亦可自行修改:
sudo mkdir /var/www
创建私人云盘的文件保存路径:
sudo mkdir /var/www/data
逐行运行以下代码,将 Nextcloud 安装文件压缩包下载并解压到安装路径下:
cd /var/www
sudo wget https://download.nextcloud.com/server/releases/latest.zip
sudo unzip latest.zip
cd
(非必需)如果安装过程中,系统提示缺少 unzip 组件,需要先行安装,再运行上述的下载、解压缩相关代码:
sudo apt install unzip
为 nextcloud、data 文件夹分配正确的用户及用户组,系统默认的用户及用户组无法正常启动 Nextcloud:
sudo chown -R www-data:www-data /var/www/nextcloud
sudo chown -R www-data:www-data /var/www/data
修改 /etc/php/7.4/fpm/php.ini,找到 “memory_limit = 128M” 行,修改为:
memory_limit = 512M
重启 PHP 服务:
sudo systemctl restart php7.4-fpm
5 为 Nextcloud 配置 Nginx
在 /etc/nginx/conf.d/ 路径下,新建文件“nextcloud.conf”,写入以下内容(需要修改第四行的“example.com”为个人网站域名,假如你所设的安装路径与本文推荐路径不一致,还需要修改第十五行“root /var/www/nextcloud/;”):
upstream php-handler {
server 127.0.0.1:9000;
#server unix:/var/run/php/php7.4-fpm.sock;
}
server {
listen 80;
listen [::]:80;
server_name example.com;
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15768000;preload;";
#I found this header is needed on Ubuntu, but not on Arch Linux.
add_header X-Frame-Options "SAMEORIGIN";
# Path to the root of your installation
root /var/www/nextcloud/;
access_log /var/log/nginx/nextcloud.access;
error_log /var/log/nginx/nextcloud.error;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
# last;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
location ~ /.well-known/acme-challenge {
allow all;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Disable gzip to avoid the removal of the ETag header
gzip off;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
location / {
rewrite ^ /index.php;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
try_files $fastcgi_script_name =404;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
#Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
# Make sure it is BELOW the PHP block
location ~* \.(?:css|js)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
# Optional: Don't log access to assets
access_log off;
}
location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
# Optional: Don't log access to other assets
access_log off;
}
}
测试 Nginx 配置是否正确,并重新加载 Nginx 使其生效:
sudo nginx -t
sudo systemctl reload nginx
6 安装 Nextcloud
在浏览器地址栏输入个人的网站域名,按提示输入:
- 设置管理员帐户(新建)
- 设置管理员密码(新建)
- 填写数据目录:/var/www/data
- 数据库用户:nextclouduser(此前设置好的)
- 数据库密码:your-password(此前设置好的)
设置好后,开始安装,等待时间的洗礼。
如果无法正常打开网页,请在防火墙开放 80 端口,顺便也可将 443 端口一并开放,假如你希望进一步申请 SSL 证书的话:
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 443 -j ACCEPT
7 申请 SSL 证书
7.1 方法一:利用 Certbot 申请 RSA 证书
安装 Certbot 及其 Nginx 插件“Python3-certbot-nginx”:
sudo apt install certbot python3-certbot-nginx -y
申请 Let’s Encrypt 证书(替换 “myemail@gmail.com” 为个人电子邮件地址,替换 “example.com” 为个人网站域名):
sudo certbot --nginx --agree-tos --redirect --staple-ocsp --email myemail@gmail.com -d example.com
根据 Certbot 的简单询问,轻松完成证书申请。证书路径一般位于:
/etc/letsencrypt/live/example.com/
fullchain.pem # 完整的证书链
privkey.pem # 私钥
查询 Certbot 计时器状态(非必要):
sudo systemctl status certbot.timer
测试 Certbot 是否已经能够自动续订 SSL 证书(非必要):
sudo certbot renew --dry-run
更新 Nginx 配置:
upstream php-handler {
server 127.0.0.1:9000;
#server unix:/var/run/php/php7.4-fpm.sock;
}
server {
listen 80;
listen [::]:80;
server_name example.com;
# enforce https
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
# SSL/TLS settings
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.crt;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15768000;preload;";
#I found this header is needed on Ubuntu, but not on Arch Linux.
add_header X-Frame-Options "SAMEORIGIN";
# Path to the root of your installation
root /var/www/nextcloud/;
access_log /var/log/nginx/nextcloud.access;
error_log /var/log/nginx/nextcloud.error;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
# last;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
location ~ /.well-known/acme-challenge {
allow all;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Disable gzip to avoid the removal of the ETag header
gzip off;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
location / {
rewrite ^ /index.php;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
try_files $fastcgi_script_name =404;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
#Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
# Make sure it is BELOW the PHP block
location ~* \.(?:css|js)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
# Optional: Don't log access to assets
access_log off;
}
location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
# Optional: Don't log access to other assets
access_log off;
}
}
测试 Nginx 配置是否正确,并重新加载 Nginx 使其生效:
sudo nginx -t
sudo systemctl reload nginx
7.2 方法二:利用 acme.sh 申请 ECC 证书
acme.sh 的项目地址:https://github.com/acmesh-official/acme.sh
(一)安装 acme.sh:
sudo curl https://get.acme.sh | sh
(二)创建 一个 bash 的 alias:
alias acme.sh=~/.acme.sh/acme.sh
(三)开启 acme.sh 的自动更新功能:
acme.sh --upgrade --auto-upgrade
(四)申请证书,请自行替换代码中的个人邮箱地址“myemail@gmail.com”及个人网站域名 “example.com”:
acme.sh --set-default-ca --server zerossl
acme.sh --register-account -m myemail@gmail.com
acme.sh --issue -d example.com --nginx --keylength ec-256
(五)复制/安装证书:
此前步骤生成的 SSL 证书无法直接使用,需要将其复制到自定义路径下,才可正常使用:
新建 SSL 证书的转移路径 /var/www/ssl/ :
sudo mkdir /var/www/ssl
复制 fullchain.crt 及 example.com.key 到 /var/www/ssl/ 路径下进行安装:
acme.sh --install-cert -d example.com --ecc --key-file /var/www/ssl/example.com.key --fullchain-file /var/www/ssl/fullchain.crt --reloadcmd "service nginx force-reload"
设置权限,无脑赋权 777 :
sudo chmod -R 777 /var/www/ssl
(六)更新 nextcloud.conf 配置:
修改 /etc/nginx/conf.d/nextcloud.conf 内容:
upstream php-handler {
server 127.0.0.1:9000;
#server unix:/var/run/php/php7.4-fpm.sock;
}
server {
listen 80;
listen [::]:80;
server_name example.com;
# enforce https
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
# SSL/TLS settings
ssl_certificate /var/www/ssl/fullchain.crt;
ssl_certificate_key /var/www/ssl/example.com.key;
# Add headers to serve security related headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15768000;preload;";
#I found this header is needed on Ubuntu, but not on Arch Linux.
add_header X-Frame-Options "SAMEORIGIN";
# Path to the root of your installation
root /var/www/nextcloud/;
access_log /var/log/nginx/nextcloud.access;
error_log /var/log/nginx/nextcloud.error;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
# last;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
location ~ /.well-known/acme-challenge {
allow all;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Disable gzip to avoid the removal of the ETag header
gzip off;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
location / {
rewrite ^ /index.php;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
try_files $fastcgi_script_name =404;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
#Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js and css files
# Make sure it is BELOW the PHP block
location ~* \.(?:css|js)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control "public, max-age=7200";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
# Optional: Don't log access to assets
access_log off;
}
location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
# Optional: Don't log access to other assets
access_log off;
}
}
测试 Nginx 配置是否正确,并重新加载 Nginx 使其生效:
sudo nginx -t
sudo systemctl reload nginx
终于部署完成,赶紧去SSL Server Test验收成果吧。
8 参考文献
本文有描述不尽之处,可以参考以下文献:
- How to Install LEMP Stack on Ubuntu 20.04 Server/Desktop
- Install NextCloud on Ubuntu 20.04 with Nginx (LEMP Stack)
- How To Secure Nginx with Let’s Encrypt on Ubuntu 20.04
9 拓展
9.1 安装fail2ban及相关配置
安装fail2ban:
sudo apt update
sudo apt install fail2ban -y
配置fail2ban:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
打开jail.local文件,转到[DEFAULT]部分,按需修改bantime:
# "bantime" is the number of seconds that a host is banned.
bantime = 6000m
重启fail2ban服务:
sudo systemctl restart fail2ban
查看小黑屋:
sudo fail2ban-client status
sudo fail2ban-client status sshd
了解 环评五四三 的更多信息
Subscribe to get the latest posts sent to your email.