Установка Nextcloud + Nginx + PHP-FPM на Ubuntu
Nextcloud - открытый проект приватного облака для хранения и обработки файлов.
Можно установить на локальном домашнем сервере или на арендованом сервере. В этой инструкции рассматривается пример установки на виртуальный выделенный сервер с системой Ubuntu 24.04.
Подготовка системы
Обновляем и устанавливаем необходимые пакеты:
apt update && \
apt -y upgrade && \
apt -y dist-upgrade && \
apt -y autoremove && \
apt -y install unzip && \ ## Утилита распаковки zip архивов
apt -y install redis-server && \ ## Устанавливаем Redis Server
apt -y install postgresql-16 && \ ## Сервер баз данных
apt -y install nginx && \ ## Веб сервер
apt -y install certbot ## Утилита выпуска SSL сетификатов LetsEncrypt
Выполним предварительную настройку, прежде чем начать развертывание Nextcloud.
Выставляем нужный часовой пояс:
timedatectl set-timezone Europe/Moscow
Установка и настройка PHP-FPM
Перед установкой php, проверить системные требования Nextcloud. Для корректной работы нужно установить рекомендуемую версию PHP.
На момент обновления инструкции, рекомендуется установить PHP версии 8.3. Для дальнейшего удобства работы, мы сохраним ее в переменную:
export PHP_VERSION=8.3
Устанавливаем пакеты, которые будут необходимы для работы Nextcloud:
apt -y install php${PHP_VERSION}-fpm php${PHP_VERSION}-common php${PHP_VERSION}-zip php${PHP_VERSION}-xml php${PHP_VERSION}-intl php${PHP_VERSION}-gd php${PHP_VERSION}-pgsql php${PHP_VERSION}-apcu php${PHP_VERSION}-redis php${PHP_VERSION}-mbstring php${PHP_VERSION}-curl php${PHP_VERSION}-imagick php${PHP_VERSION}-gmp php${PHP_VERSION}-bcmath libmagickcore-6.q16-6-extra
После установки, открываем конфигурационный файл php-fpm:
nano /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf
путь к данной папке зависит от установленной версии php. В данном примере через переменную PHP_VERSION задана 8.3.
В редакторе nano используй сочетания клавиш:
Ctrl+W- поискCtrl+O- сохранить файлCtrl+X- закрыть редактор
Раскомментируем строку с параметром удалив ;
env[PATH] = /usr/local/bin:/usr/bin:/bin
Настраиваем php.ini:
nano /etc/php/${PHP_VERSION}/fpm/php.ini
Снимаем комментарии со следующей строки:
opcache.enable_cli = 1
opcache.interned_strings_buffer = 32
opcache.revalidate_freq = 1
memory_limit = 1024M
Включаем локальное кэширование в файле:
nano /etc/php/${PHP_VERSION}/mods-available/apcu.ini
Добавляем строку:
apc.enable_cli=1
Разрешаем автозапуск php-fpm и перезапускаем его:
systemctl enable php${PHP_VERSION}-fpm
systemctl restart php${PHP_VERSION}-fpm
Выпускаем LetsEncrypt сертификат
Для безопасной работы с облаком нам необходим SSL сертификат. Воспользуемся бесплатным сервисом LetsEncrypt.
Выпускаем сертификат:
systemctl stop nginx ## Для получения сертификата останавливаем сервер nginx
certbot certonly -d nextcloud.domain.tld -m mymail@mail.ru ## Выпускаем SSL сертификат утилитой Certbot
Команда создаст сертификат на 3 месяца для домена nextcloud.domain.tld.
Для того, что бы сертификат выпускался регулярно и не приходилось делать это вручную, создадим systemd таймер и сервис.
nano /etc/systemd/system/certbot-renewal.service
Содержимое файла certbot-renewal.service:
[Unit]
Description=Certbot Renewal
[Service]
ExecStart=/usr/bin/certbot renew --force-renewal --post-hook "systemctl reload nginx.service"
Создадим новый файл certbot-renewal.timer в той же директории, где находится certbot-renewal.service. Настройки ниже будут запускать обновление SSL-сертификата раз в неделю, не раньше чем через 300 секунд с момента включения сервера:
nano /etc/systemd/system/certbot-renewal.timer
Содержимое файла certbot-renewal.timer:
[Unit]
Description=Timer for Certbot Renewal
[Timer]
OnBootSec=300
OnUnitActiveSec=1w
[Install]
WantedBy=multi-user.target
Включим таймер, чтобы он начал свой отсчёт:
systemctl start certbot-renewal.timer
Настроим автостарт таймера на случай перезапуска сервера:
systemctl enable certbot-renewal.timer
Заглянем в статус таймера, чтобы узнать когда было последнее обновление SSL-сертификата и когда планируется следующее:
systemctl status certbot-renewal.timer
● certbot-renewal.timer - Timer for Certbot Renewal
Loaded: loaded (/etc/systemd/system/certbot-renewal.timer; enabled; preset: enabled)
Active: active (waiting) since Thu 2024-07-25 13:40:36 UTC; 19h ago
Trigger: Thu 2024-08-01 13:40:36 UTC; 6 days left
Triggers: ● certbot-renewal.service
Установка и настройка NGINX
Создаем конфиг nextcloud для веб сервера nginx:
nano /etc/nginx/sites-available/nextcloud.conf
upstream php-handler {
server unix:/run/php/php8.3-fpm.sock; # Путь до файла сокета зависит от версии PHP
}
map $arg_v $asset_immutable {
"" "";
default ", immutable";
}
server {
listen 80;
listen [::]:80;
server_name nextcloud.domain.tld; # доменное имя для nextcloud
server_tokens off;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name nextcloud.domain.tld;
root /opt/nextcloud; # каталог файлов nextcloud
ssl_certificate /etc/letsencrypt/live/nextcloud.domain.tld/fullchain.pem; # каталог для сертификатов LetsEncript;
ssl_certificate_key /etc/letsencrypt/live/nextcloud.domain.tld/privkey.pem;
server_tokens off;
client_max_body_size 10G;
client_body_timeout 300s;
fastcgi_buffers 64 4K;
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 text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm 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;
client_body_buffer_size 512k;
add_header Strict-Transport-Security "max-age=31536000;includeSubDomains" always;
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
fastcgi_hide_header X-Powered-By;
include mime.types;
types {
text/javascript js mjs;
}
index index.php index.html /index.php$request_uri;
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;
}
location ^~ /.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; }
return 301 /index.php$request_uri;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
location ~ \.php(?:$|/) {
# Required for legacy support
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /index.php$request_uri;
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;
fastcgi_max_temp_file_size 0;
}
location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|tflite|map|ogg|flac)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463$asset_immutable";
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
access_log off;
}
location ~ \.woff2?$ {
try_files $uri /index.php$request_uri;
expires 7d;
access_log off;
}
location /remote {
return 301 /remote.php$request_uri;
}
location / {
try_files $uri $uri/ /index.php$request_uri;
}
}
Поменяте nextcloud.domain.tld в конфигурации на свой домен.
Включаем запуск конфига сайта с помощью добавления символьной ссылки:
ln -s /etc/nginx/sites-available/nextcloud.conf /etc/nginx/sites-enabled/nextcloud.conf
Проверяем конфигурацию nginx:
nginx -t
Перезагружаем конфигурацию и включаем автозапуск сервиса nginx:
systemctl restart nginx
systemctl enable nginx
Настройка сервера баз данных
В качестве СУБД будем использовать Postgresql, который установили ранее.
Разрешаем автозапуск и стартуем сервис:
systemctl enable postgresql
systemctl start postgresql
Переключаемся на пользователя от которого запускается сервер баз данных Postgres:
sudo su postgres
Запускаем интерактивныую утилиту запросов к базе данных
psql
Создаем пользователя и базу данных:
CREATE ROLE nextcloud_database_user WITH LOGIN;
ALTER USER nextcloud_database_user WITH PASSWORD 'password';
CREATE DATABASE nextcloud OWNER nextcloud_database_user;
quit;
Записываем имя пользователя, пароль и название базы данных в файл. Они потребуются для дальнейшей установки.
Установка Nextcloud
Переходим в папку где у нас будет установлен Nextcloud и скачиваем архив с последним релизом:
cd /opt
wget https://download.nextcloud.com/server/releases/latest.zip
Распаковываем скачанный архив:
unzip latest.zip
Удаляем архив:
rm /opt/latest.zip
Задаем права доступа для пользователя:
chown -R www-data:www-data /opt/nextcloud
Открываем браузер и переходим по адресу https://nextcloud.domain.tld, где расположен наш портал.
Вводим логин, пароль и название базы данных, которые указали при создании и записали в файл.

Нажимаем Установить и ждем. После установки откроется панель управления порталом.
Оптимизируем работу базы данных:
sudo -u www-data php /opt/nextcloud/occ db:convert-filecache-bigint
sudo -u www-data php /opt/nextcloud/occ db:add-missing-indices
Настройка Nextcloud
После установки Nexcloud необходимо настроить его для работы. Нужно залогиниться под данными администратора системы, которые мы указывали при установке. Открываем меню и переходим в Параметры сервера

Затем переходим в раздел Основные сведения. В разделе Проверка безопасности и параметров увидим рекомендации по настройке:
В разделе «Проверка безопасности и параметров» мы можем увидеть список проблем:

Настройка выполнения фоновых задач
Отключаем параметр выставления окна времени технического обслуживания:
sudo -u www-data php /opt/nextcloud/occ config:system:set maintenance_window_start --type=integer --value=100
Далее нам надо создать повторяющийся таймер запуска cron.php для выполнения задач.
В качестве альтернативы cronjob будем использовать таймер systemd, так как он надежнее.
Этот подход требует наличия двух файлов: nextcloudcron.service и nextcloudcron.timer. Создайте эти два файла в каталоге /etc/systemd/system/
nano /etc/systemd/system/nextcloudcron.service
nextcloudcron.service должен выглядеть следующим образом:
[Unit]
Description=Nextcloud cron.php job
[Service]
User=www-data
ExecCondition=/usr/bin/php -f /opt/nextcloud/occ status -e
ExecStart=/usr/bin/php -f /opt/nextcloud/cron.php
KillMode=process
ExecCondition перед запуском фонового задания проверяет, что nextcloud работает нормально и пропускает его в противном случае.
Параметр KillMode=process необходим для того, чтобы внешние программы, запускаемые заданием cron, продолжали работать после завершения задания cron.
nano /etc/systemd/system/nextcloudcron.timer
nextcloudcron.timer должен выглядеть следующим образом:
[Unit]
Description=Запуск Nextcloud cron.php каждые 30 минут
[Timer]
OnBootSec=30min
OnUnitActiveSec=30min
Unit=nextcloudcron.service
[Install]
WantedBy=timers.target
OnBootSec запускает таймер через 30 минут после загрузки, иначе пришлось запускать его вручную. OnUnitActiveSec 30 минутный таймер между запусками.
Теперь осталось только запустить systemd unit и включить таймер, выполнив эту команду:
systemctl enable --now nextcloudcron.timer
Настройка системы кеширования Redis
Открываем конфигурационный файл для nextcloud:
nano /opt/nextcloud/config/config.php
И добавим:
'memcache.local' => '\OC\Memcache\APCu',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => array(
'host' => 'localhost',
'port' => 6379,
'timeout' => 0.0,
),
Готово.
Настраиваем регион по умолчанию
Для решения проблемы с форматом телефонного номера необходимо добавить параметр в конфиг:
nano /opt/nextcloud/config/config.php
Добавляем:
...
'default_phone_region' => 'RU',
Защита от перебора паролей
Данная возможность позволяет блокировать подключения от IP-адресов, с которых было много неудачных попыток войти в систему. Рассмотрим возможность изменения числа неудачных попыток или отключения возможности.
Текущее значение для числа попыток ввода пароля можно посмотреть командой:
sudo -u www-data php /opt/nextcloud/occ config:system:get brute-force-attempts
Если она вернет пустое значение, значит используется значение по умолчанию — 10.
Чтобы его изменить, запускаем команду, где 5 новое значение:
sudo -u www-data php /opt/nextcloud/occ config:system:set brute-force-attempts --type=integer --value=5