Install Nextcloud on Arch Linux: Difference between revisions
(Add the Nextcloud installation part) |
(Change source tags to pre) |
||
Line 1: | Line 1: | ||
= Introduction = | = Introduction = | ||
Line 13: | Line 9: | ||
Since the system comes preinstalled with Arch Linux on it, the first thing to do is to update the system: | Since the system comes preinstalled with Arch Linux on it, the first thing to do is to update the system: | ||
< | <pre lang="bash">pacman -Syu | ||
reboot | reboot | ||
pacman -S base base-devel | pacman -S base base-devel | ||
</ | </pre> | ||
== Add an administration user == | == Add an administration user == | ||
We add a day-to-day administrator account: | We add a day-to-day administrator account: | ||
< | <pre lang="bash">useradd -m -g users -s /bin/bash admin | ||
passwd admin | passwd admin | ||
</ | </pre> | ||
Make sure that <code>pacman</code> can be executed as user <code>admin</code>: | Make sure that <code>pacman</code> can be executed as user <code>admin</code>: | ||
< | <pre lang="bash">visudo | ||
</ | </pre> | ||
And add the following: | And add the following: | ||
< | <pre lang="bash">admin ALL=(ALL) NOPASSWD: /usr/bin/pacman | ||
</ | </pre> | ||
== Create a swap partition == | == Create a swap partition == | ||
Line 42: | Line 38: | ||
In file <code>/etc/locale.gen</code>: | In file <code>/etc/locale.gen</code>: | ||
< | <pre lang="bash">en_US.UTF-8 UTF-8 | ||
</ | </pre> | ||
Then execute: | Then execute: | ||
< | <pre lang="bash">locale-gen | ||
echo LANG=en_US.UTF-8 > /etc/locale.conf | echo LANG=en_US.UTF-8 > /etc/locale.conf | ||
export LANG=en_US.UTF-8 | export LANG=en_US.UTF-8 | ||
</ | </pre> | ||
Add the correct time zone, for example: | Add the correct time zone, for example: | ||
Line 63: | Line 59: | ||
Random number generation is important for security, so we install the following tools: | Random number generation is important for security, so we install the following tools: | ||
< | <pre lang="bash">pacman -S rng-tools | ||
systemctl start rngd | systemctl start rngd | ||
systemctl enable rngd | systemctl enable rngd | ||
</ | </pre> | ||
To check the level of entropy we can do: | To check the level of entropy we can do: | ||
< | <pre lang="bash">cat /proc/sys/kernel/random/entropy_available | ||
</ | </pre> | ||
Since it runs on a virtual machine, we are not really sure how representative the entropy is. | Since it runs on a virtual machine, we are not really sure how representative the entropy is. | ||
We can also run the following tests which should have very few failures: | We can also run the following tests which should have very few failures: | ||
< | <pre lang="bash">cat /dev/random | rngtest -c 1000 | ||
cat /dev/urandom | rngtest -c 1000 | cat /dev/urandom | rngtest -c 1000 | ||
</ | </pre> | ||
The <code>rng-tools</code> service is preferred over <code>haveged</code>. | The <code>rng-tools</code> service is preferred over <code>haveged</code>. | ||
Line 87: | Line 83: | ||
In <code>/etc/hostname</code>: | In <code>/etc/hostname</code>: | ||
< | <pre lang="bash">cloud.mydomainname.net | ||
</ | </pre> | ||
In <code>/etc/hosts</code>: | In <code>/etc/hosts</code>: | ||
< | <pre lang="bash">127.0.1.1 cloud.mydomainname.net | ||
</ | </pre> | ||
After a reboot, we can check whether everything is set with the command <code>hostname -f</code>. | After a reboot, we can check whether everything is set with the command <code>hostname -f</code>. | ||
Line 105: | Line 101: | ||
First we set the policy for chain INPUT to target ACCEPT: | First we set the policy for chain INPUT to target ACCEPT: | ||
< | <pre lang="bash">iptables -P INPUT ACCEPT | ||
ip6tables -P INPUT ACCEPT | ip6tables -P INPUT ACCEPT | ||
</ | </pre> | ||
We then flush all the chains: | We then flush all the chains: | ||
< | <pre lang="bash">iptables -F | ||
ip6tables -F | ip6tables -F | ||
</ | </pre> | ||
A table in this context is a packet matching table. There are five predefined tables. The default table ''filter'', the tables ''nat'', ''mangle'', ''raw'', and ''security''. We flush the table ''nat'': | A table in this context is a packet matching table. There are five predefined tables. The default table ''filter'', the tables ''nat'', ''mangle'', ''raw'', and ''security''. We flush the table ''nat'': | ||
< | <pre lang="bash">iptables -t nat -F | ||
ip6tables -t nat -F | ip6tables -t nat -F | ||
</ | </pre> | ||
We then delete all the user-defined chains: | We then delete all the user-defined chains: | ||
< | <pre lang="bash">iptables -X | ||
ip6tables -X | ip6tables -X | ||
</ | </pre> | ||
We then set the policy to drop every packet that enters the system (make sure you are logged in via a video display and not SSH): | We then set the policy to drop every packet that enters the system (make sure you are logged in via a video display and not SSH): | ||
< | <pre lang="bash">iptables -P INPUT DROP | ||
ip6tables -P INPUT DROP | ip6tables -P INPUT DROP | ||
</ | </pre> | ||
We append to chain INPUT on the loopback interface <code>lo</code> to jump to target ACCEPT. This is important for applications that use local servers. | We append to chain INPUT on the loopback interface <code>lo</code> to jump to target ACCEPT. This is important for applications that use local servers. | ||
< | <pre lang="bash">iptables -A INPUT -i lo -j ACCEPT | ||
ip6tables -A INPUT -i lo -j ACCEPT | ip6tables -A INPUT -i lo -j ACCEPT | ||
</ | </pre> | ||
We then append to chain INPUT on interface <code>ens3</code> a rule to accept connections with states ESTABLISHED and RELATED: | We then append to chain INPUT on interface <code>ens3</code> a rule to accept connections with states ESTABLISHED and RELATED: | ||
< | <pre lang="bash">iptables -A INPUT -i ens3 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | ||
ip6tables -A INPUT -i ens3 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | ip6tables -A INPUT -i ens3 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | ||
</ | </pre> | ||
We then make sure that incomming TCP connections are SYN packets to prevent SYN flooding: | We then make sure that incomming TCP connections are SYN packets to prevent SYN flooding: | ||
< | <pre lang="bash">iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP | ||
ip6tables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP | ip6tables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP | ||
</ | </pre> | ||
We also drop packets with incoming fragments. This is only for IPv4: | We also drop packets with incoming fragments. This is only for IPv4: | ||
< | <pre lang="bash">iptables -A INPUT -f -j DROP | ||
</ | </pre> | ||
We also drop bogons: | We also drop bogons: | ||
< | <pre lang="bash">iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP | ||
iptables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP | iptables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP | ||
iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP | iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP | ||
Line 155: | Line 151: | ||
ip6tables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP | ip6tables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP | ||
ip6tables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP | ip6tables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP | ||
</ | </pre> | ||
We also reject malformed NULL packets: | We also reject malformed NULL packets: | ||
< | <pre lang="bash">iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP | ||
ip6tables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP | ip6tables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP | ||
</ | </pre> | ||
We can then store the firewall rules with the following commands: | We can then store the firewall rules with the following commands: | ||
< | <pre lang="bash">iptables-save > /etc/iptables/iptables.rules | ||
ip6tables-save > /etc/iptables/ip6tables.rules | ip6tables-save > /etc/iptables/ip6tables.rules | ||
</ | </pre> | ||
To make the changes permanent, we can enable and start the Systemd service: | To make the changes permanent, we can enable and start the Systemd service: | ||
< | <pre lang="bash">systemctl start iptables.service | ||
systemctl enable iptables.service | systemctl enable iptables.service | ||
systemctl status iptables.service | systemctl status iptables.service | ||
Line 175: | Line 171: | ||
systemctl enable ip6tables.service | systemctl enable ip6tables.service | ||
systemctl status ip6tables.service | systemctl status ip6tables.service | ||
</ | </pre> | ||
== Fail2ban == | == Fail2ban == | ||
Line 182: | Line 178: | ||
We install it with: | We install it with: | ||
< | <pre lang="bash">pacman -S fail2ban | ||
</ | </pre> | ||
Using <code>systemd</code> we can sandbox the fail2ban service with capabilities. To do so, we create a new file <code>/etc/systemd/system/fail2ban.service.d/capabilities.conf</code> with the following contents: | Using <code>systemd</code> we can sandbox the fail2ban service with capabilities. To do so, we create a new file <code>/etc/systemd/system/fail2ban.service.d/capabilities.conf</code> with the following contents: | ||
< | <pre lang="bash">[Service] | ||
PrivateDevices=yes | PrivateDevices=yes | ||
PrivateTmp=yes | PrivateTmp=yes | ||
Line 198: | Line 194: | ||
ReadWritePaths=-/run/xtables.lock | ReadWritePaths=-/run/xtables.lock | ||
CapabilityBoundingSet=CAP_AUDIT_READ CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW | CapabilityBoundingSet=CAP_AUDIT_READ CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW | ||
</ | </pre> | ||
Create configuration file <code>/etc/fail2ban/fail2ban.local</code> with the correct logtarget path: | Create configuration file <code>/etc/fail2ban/fail2ban.local</code> with the correct logtarget path: | ||
< | <pre lang="bash">[Definition] | ||
logtarget = /var/log/fail2ban/fail2ban.log | logtarget = /var/log/fail2ban/fail2ban.log | ||
</ | </pre> | ||
Create the <code>/var/log/fail2ban/</code> directory as root. | Create the <code>/var/log/fail2ban/</code> directory as root. | ||
We have to set up paths for Arch Linux in a <code>jail.local</code> file: | We have to set up paths for Arch Linux in a <code>jail.local</code> file: | ||
< | <pre lang="bash">[INCLUDES] | ||
before = paths-arch.conf | before = paths-arch.conf | ||
</ | </pre> | ||
== Yay == | == Yay == | ||
With yay, we can keep also the AUR packages up to date. | With yay, we can keep also the AUR packages up to date. | ||
< | <pre lang="bash">git clone https://aur.archlinux.org/yay.git | ||
tar xvzf yay.tar.gz | tar xvzf yay.tar.gz | ||
cd yay | cd yay | ||
makepkg -s | makepkg -s | ||
pacman -U yay*.pkg.tar.xz | pacman -U yay*.pkg.tar.xz | ||
</ | </pre> | ||
= SSH access = | = SSH access = | ||
Line 227: | Line 223: | ||
The first service we would like to set up is SSH. We first configure the SSH daemon itself in file <code>/etc/ssh/sshd_config</code>: | The first service we would like to set up is SSH. We first configure the SSH daemon itself in file <code>/etc/ssh/sshd_config</code>: | ||
< | <pre lang="bash">PermitRootLogin no | ||
TCPKeepAlive no | TCPKeepAlive no | ||
ClientAliveInterval 60 | ClientAliveInterval 60 | ||
Line 233: | Line 229: | ||
MACs hmac-sha2-512,hmac-sha2-256 | MACs hmac-sha2-512,hmac-sha2-256 | ||
KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1 | KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1 | ||
</ | </pre> | ||
We then restart the daemon: | We then restart the daemon: | ||
< | <pre lang="bash">systemctl restart sshd | ||
</ | </pre> | ||
== The firewall == | == The firewall == | ||
We have to open port 22 for SSH in our firewall: | We have to open port 22 for SSH in our firewall: | ||
< | <pre lang="bash">iptables -A INPUT -i ens3 -p tcp --dport 22 -j ACCEPT | ||
</ | </pre> | ||
< | <pre lang="bash">iptables-save > /etc/iptables/iptables.rules | ||
ip6tables-save > /etc/iptables/ip6tables.rules | ip6tables-save > /etc/iptables/ip6tables.rules | ||
</ | </pre> | ||
== Fail2ban == | == Fail2ban == | ||
Line 253: | Line 249: | ||
In <code>sshd.conf</code>: | In <code>sshd.conf</code>: | ||
< | <pre lang="bash">[sshd] | ||
enabled = true | enabled = true | ||
</ | </pre> | ||
= Installing Nextcloud = | = Installing Nextcloud = | ||
Line 265: | Line 261: | ||
As a first step, we are going to install MariaDB with package <code>mariadb</code>. Before we start the service, we run: | As a first step, we are going to install MariaDB with package <code>mariadb</code>. Before we start the service, we run: | ||
< | <pre lang="bash">mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql | ||
systemctl start mariadb</ | systemctl start mariadb</pre> | ||
Then add the database (substitute the password with a proper one): | Then add the database (substitute the password with a proper one): | ||
< | <pre lang="sql">CREATE DATABASE nextcloud DEFAULT CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci'; | ||
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost' IDENTIFIED BY 'password'; | GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost' IDENTIFIED BY 'password'; | ||
FLUSH PRIVILEGES;</ | FLUSH PRIVILEGES;</pre> | ||
== PHP == | == PHP == | ||
Install PHP with package <code>php</code>. We need to do additional configuration, in <code>/etc/php/php.ini</code>: | Install PHP with package <code>php</code>. We need to do additional configuration, in <code>/etc/php/php.ini</code>: | ||
< | <pre lang="bash">date.timezone = Europe/Amsterdam | ||
memory_limit = 512M</ | memory_limit = 512M</pre> | ||
For PHP we need to install the following modules: | For PHP we need to install the following modules: | ||
Line 384: | Line 380: | ||
For further support for <code>imagick</code>, it is wise to install the following packages: | For further support for <code>imagick</code>, it is wise to install the following packages: | ||
< | <pre lang="bash">pacman -S ghostscript librsvg libwmf ocl-icd openexr openjpeg2 pango</pre> | ||
We enable OPCache in <code>php.ini</code>: | We enable OPCache in <code>php.ini</code>: | ||
< | <pre lang="bash">zend_extension=opcache</pre> | ||
And we set the following options: | And we set the following options: | ||
< | <pre lang="bash">opcache.enable=1 | ||
opcache.interned_strings_buffer=8 | opcache.interned_strings_buffer=8 | ||
opcache.max_accelerated_files=10000 | opcache.max_accelerated_files=10000 | ||
opcache.memory_consumption=128 | opcache.memory_consumption=128 | ||
opcache.save_comments=1 | opcache.save_comments=1 | ||
opcache.revalidate_freq=1</ | opcache.revalidate_freq=1</pre> | ||
We enable APCu by installing <code>php-apcu</code> and enabling it in <code>/etc/php/conf.d/apcu.ini</code>: | We enable APCu by installing <code>php-apcu</code> and enabling it in <code>/etc/php/conf.d/apcu.ini</code>: | ||
< | <pre lang="bash">extension=apcu.so</pre> | ||
== Nginx == | == Nginx == | ||
We install <code>nginx</code> and set it up to obtain certificates by enabling the service, and open port 80: | We install <code>nginx</code> and set it up to obtain certificates by enabling the service, and open port 80: | ||
< | <pre lang="bash">iptables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT | ||
systemctl enable nginx | systemctl enable nginx | ||
systemctl start nginx</ | systemctl start nginx</pre> | ||
We get a message that the <code>max_types_hash_size</code> is not enough. In <code>/etc/nginx/nginx.conf</code> add in the <code>http</code> block: | We get a message that the <code>max_types_hash_size</code> is not enough. In <code>/etc/nginx/nginx.conf</code> add in the <code>http</code> block: | ||
< | <pre lang="bash">types_hash_max_size 4096;</pre> | ||
We are now ready to install certificates. | We are now ready to install certificates. | ||
Line 417: | Line 413: | ||
Then run: | Then run: | ||
< | <pre lang="bash">certbot --nginx</pre> | ||
We fill in: | We fill in: | ||
Line 442: | Line 438: | ||
We also set the following values in <code>/etc/php/php-fpm.d/www.conf</code>, taken from the documentation and all values divided by 2. | We also set the following values in <code>/etc/php/php-fpm.d/www.conf</code>, taken from the documentation and all values divided by 2. | ||
< | <pre lang="bash">pm.max_children = 60; | ||
pm.start_servers = 6; | pm.start_servers = 6; | ||
pm.min_spare_servers = 3; | pm.min_spare_servers = 3; | ||
pm.max_spare_servers = 9;</ | pm.max_spare_servers = 9;</pre> | ||
< | <pre lang="bash">systemctl start php-fpm | ||
systemctl enable php-fpm</ | systemctl enable php-fpm</pre> | ||
== Nextcloud == | == Nextcloud == | ||
< | <pre lang="bash">pacman -S nextcloud</pre> | ||
We install the following pacman hook in <code>/etc/pacman.d/hooks/nextcloud.hook</code>: | We install the following pacman hook in <code>/etc/pacman.d/hooks/nextcloud.hook</code>: | ||
< | <pre lang="bash">[Trigger] | ||
Operation = Install | Operation = Install | ||
Operation = Upgrade | Operation = Upgrade | ||
Line 463: | Line 459: | ||
Description = Update Nextcloud installation | Description = Update Nextcloud installation | ||
When = PostTransaction | When = PostTransaction | ||
Exec = /usr/bin/runuser -u http -- /usr/bin/php /usr/share/webapps/nextcloud/occ upgrade</ | Exec = /usr/bin/runuser -u http -- /usr/bin/php /usr/share/webapps/nextcloud/occ upgrade</pre> | ||
Create a server block in the <code>nginx.conf</code>: | Create a server block in the <code>nginx.conf</code>: | ||
< | <pre lang="bash">upstream php-handler { | ||
#server 127.0.0.1:9000; | #server 127.0.0.1:9000; | ||
server unix:/run/php-fpm/php-fpm.sock; | server unix:/run/php-fpm/php-fpm.sock; | ||
Line 617: | Line 613: | ||
access_log off; | access_log off; | ||
} | } | ||
}</ | }</pre> | ||
We have to create a data directory for Nextcloud: | We have to create a data directory for Nextcloud: | ||
< | <pre lang="bash">mkdir /var/nextcloud | ||
chown http:http /var/nextcloud | chown http:http /var/nextcloud | ||
chmod 750 /var/nextcloud</ | chmod 750 /var/nextcloud</pre> | ||
We also have to change permissions for the apps directories: | We also have to change permissions for the apps directories: | ||
< | <pre lang="bash">mkdir -p /usr/share/webapps/nextcloud/data | ||
chown -R http:http /usr/share/webapps/nextcloud/{apps,data} | chown -R http:http /usr/share/webapps/nextcloud/{apps,data} | ||
chmod 750 /usr/share/webapps/nextcloud/{apps,data}</ | chmod 750 /usr/share/webapps/nextcloud/{apps,data}</pre> | ||
We have to give <code>php-fpm</code> permissions. We do this with the following command: | We have to give <code>php-fpm</code> permissions. We do this with the following command: | ||
< | <pre lang="bash">systemctl edit php-fpm.service</pre> | ||
This will save the contents in <code>/etc/systemd/system/php-fpm.service.d/override.conf</code>. | This will save the contents in <code>/etc/systemd/system/php-fpm.service.d/override.conf</code>. | ||
The contents: | The contents: | ||
< | <pre lang="bash">[Service] | ||
ReadWritePaths = /usr/share/webapps/nextcloud/apps | ReadWritePaths = /usr/share/webapps/nextcloud/apps | ||
ReadWritePaths = /usr/share/webapps/nextcloud/data | ReadWritePaths = /usr/share/webapps/nextcloud/data | ||
Line 641: | Line 637: | ||
# Replace the following path with the Nextcloud data directory | # Replace the following path with the Nextcloud data directory | ||
ReadWritePaths = /var/nextcloud</ | ReadWritePaths = /var/nextcloud</pre> | ||
We then do: | We then do: | ||
< | <pre lang="bash">systemctl restart php-fpm</pre> | ||
We can then open the firewall on port 80 and 443: | We can then open the firewall on port 80 and 443: | ||
< | <pre lang="bash">systemctl stop fail2ban | ||
iptables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT | iptables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT | ||
ip6tables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT | ip6tables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT | ||
Line 654: | Line 650: | ||
iptables-save > /etc/iptables/iptables.rules | iptables-save > /etc/iptables/iptables.rules | ||
ip6tables-save > /etc/iptables/ip6tables.rules | ip6tables-save > /etc/iptables/ip6tables.rules | ||
systemctl start fail2ban</ | systemctl start fail2ban</pre> | ||
== Postinstall == | == Postinstall == | ||
It turns out that the cache was not enabled. We do that by adding the following key to <code>/etc/webapps/nextcloud/config/config.php</code>: | It turns out that the cache was not enabled. We do that by adding the following key to <code>/etc/webapps/nextcloud/config/config.php</code>: | ||
< | <pre lang="php">'memcache.local' => '\OC\Memcache\APCu',</pre> | ||
Install the following apps: | Install the following apps: | ||
Revision as of 20:21, 23 June 2020
Introduction
This document describes how to set up Nextcloud on a virtual private server (VPS) hosted by a cloud service provider that provides images for Arch Linux. We assume there is a DNS record in place that points the address cloud.mydomain.net
to the IP address provided by the cloud service provider.
Basic setup Arch Linux
Initial setup
Since the system comes preinstalled with Arch Linux on it, the first thing to do is to update the system:
pacman -Syu
reboot
pacman -S base base-devel
Add an administration user
We add a day-to-day administrator account:
useradd -m -g users -s /bin/bash admin
passwd admin
Make sure that pacman
can be executed as user admin
:
visudo
And add the following:
admin ALL=(ALL) NOPASSWD: /usr/bin/pacman
Create a swap partition
The swap partition has already been activated, so there is nothing to do.
Configure the language and locales
In file /etc/locale.gen
:
en_US.UTF-8 UTF-8
Then execute:
locale-gen
echo LANG=en_US.UTF-8 > /etc/locale.conf
export LANG=en_US.UTF-8
Add the correct time zone, for example:
ln -s /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime
Time configuration
Since Arch sits in a virtual machine, we assume that the time is always correct.
Random number generation
Random number generation is important for security, so we install the following tools:
pacman -S rng-tools
systemctl start rngd
systemctl enable rngd
To check the level of entropy we can do:
cat /proc/sys/kernel/random/entropy_available
Since it runs on a virtual machine, we are not really sure how representative the entropy is.
We can also run the following tests which should have very few failures:
cat /dev/random | rngtest -c 1000
cat /dev/urandom | rngtest -c 1000
The rng-tools
service is preferred over haveged
.
Setting the hostname
Assuming we have a hostname mydomainname.net
that points to our server's IP address:
In /etc/hostname
:
cloud.mydomainname.net
In /etc/hosts
:
127.0.1.1 cloud.mydomainname.net
After a reboot, we can check whether everything is set with the command hostname -f
.
Setting up the network
The network has been set up fine by the cloud provider.
Setting up the firewall
We use iptables
to set up the firewall. A chain is a set of rules. The chain INPUT is predefined for packets that enter the system.
First we set the policy for chain INPUT to target ACCEPT:
iptables -P INPUT ACCEPT
ip6tables -P INPUT ACCEPT
We then flush all the chains:
iptables -F
ip6tables -F
A table in this context is a packet matching table. There are five predefined tables. The default table filter, the tables nat, mangle, raw, and security. We flush the table nat:
iptables -t nat -F
ip6tables -t nat -F
We then delete all the user-defined chains:
iptables -X
ip6tables -X
We then set the policy to drop every packet that enters the system (make sure you are logged in via a video display and not SSH):
iptables -P INPUT DROP
ip6tables -P INPUT DROP
We append to chain INPUT on the loopback interface lo
to jump to target ACCEPT. This is important for applications that use local servers.
iptables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT
We then append to chain INPUT on interface ens3
a rule to accept connections with states ESTABLISHED and RELATED:
iptables -A INPUT -i ens3 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -i ens3 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
We then make sure that incomming TCP connections are SYN packets to prevent SYN flooding:
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
ip6tables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
We also drop packets with incoming fragments. This is only for IPv4:
iptables -A INPUT -f -j DROP
We also drop bogons:
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
ip6tables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
ip6tables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
ip6tables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
We also reject malformed NULL packets:
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
ip6tables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
We can then store the firewall rules with the following commands:
iptables-save > /etc/iptables/iptables.rules
ip6tables-save > /etc/iptables/ip6tables.rules
To make the changes permanent, we can enable and start the Systemd service:
systemctl start iptables.service
systemctl enable iptables.service
systemctl status iptables.service
systemctl start ip6tables.service
systemctl enable ip6tables.service
systemctl status ip6tables.service
Fail2ban
The service fail2ban is a service for detecting login attempts and blocking it.
We install it with:
pacman -S fail2ban
Using systemd
we can sandbox the fail2ban service with capabilities. To do so, we create a new file /etc/systemd/system/fail2ban.service.d/capabilities.conf
with the following contents:
[Service]
PrivateDevices=yes
PrivateTmp=yes
ProtectHome=read-only
ProtectSystem=strict
NoNewPrivileges=yes
ReadWritePaths=-/var/run/fail2ban
ReadWritePaths=-/var/lib/fail2ban
ReadWritePaths=-/var/log/fail2ban
ReadWritePaths=-/var/spool/postfix/maildrop
ReadWritePaths=-/run/xtables.lock
CapabilityBoundingSet=CAP_AUDIT_READ CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW
Create configuration file /etc/fail2ban/fail2ban.local
with the correct logtarget path:
[Definition]
logtarget = /var/log/fail2ban/fail2ban.log
Create the /var/log/fail2ban/
directory as root.
We have to set up paths for Arch Linux in a jail.local
file:
[INCLUDES]
before = paths-arch.conf
Yay
With yay, we can keep also the AUR packages up to date.
git clone https://aur.archlinux.org/yay.git
tar xvzf yay.tar.gz
cd yay
makepkg -s
pacman -U yay*.pkg.tar.xz
SSH access
Configuration
The first service we would like to set up is SSH. We first configure the SSH daemon itself in file /etc/ssh/sshd_config
:
PermitRootLogin no
TCPKeepAlive no
ClientAliveInterval 60
Ciphers aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512,hmac-sha2-256
KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1
We then restart the daemon:
systemctl restart sshd
The firewall
We have to open port 22 for SSH in our firewall:
iptables -A INPUT -i ens3 -p tcp --dport 22 -j ACCEPT
iptables-save > /etc/iptables/iptables.rules
ip6tables-save > /etc/iptables/ip6tables.rules
Fail2ban
We add the following jails in /etc/fail2ban/jail.d/
:
In sshd.conf
:
[sshd]
enabled = true
Installing Nextcloud
The version to install is 19.0.0. We are going to install it on top of nginx
and MariaDB
.
MariaDB
As a first step, we are going to install MariaDB with package mariadb
. Before we start the service, we run:
mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
systemctl start mariadb
Then add the database (substitute the password with a proper one):
CREATE DATABASE nextcloud DEFAULT CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
PHP
Install PHP with package php
. We need to do additional configuration, in /etc/php/php.ini
:
date.timezone = Europe/Amsterdam
memory_limit = 512M
For PHP we need to install the following modules:
module | package | comments |
---|---|---|
ctype | php | |
curl | php | |
dom | php | |
GD | php-gd | enable in php.ini |
iconv | php | enable in php.ini |
json | php | |
libxml | php | |
mbstring | php | |
openssl | php | |
posix | php | |
session | php | |
SimpleXML | php | |
xmlreader | php | |
xmlwriter | php | |
zip | php | |
zlib | php | |
pdomysql | php | enable in php.ini |
mysqli | php | enable in php.ini |
fileinfo | php | |
bz2 | php | enable in php.ini |
intl | php-intl | enable in php.ini |
bcmath | php | enable in php.ini |
gmp | php | enable in php.ini |
imagick | php-imagick | enable in conf.d/imagick.ini |
For further support for imagick
, it is wise to install the following packages:
pacman -S ghostscript librsvg libwmf ocl-icd openexr openjpeg2 pango
We enable OPCache in php.ini
:
zend_extension=opcache
And we set the following options:
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
We enable APCu by installing php-apcu
and enabling it in /etc/php/conf.d/apcu.ini
:
extension=apcu.so
Nginx
We install nginx
and set it up to obtain certificates by enabling the service, and open port 80:
iptables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT
systemctl enable nginx
systemctl start nginx
We get a message that the max_types_hash_size
is not enough. In /etc/nginx/nginx.conf
add in the http
block:
types_hash_max_size 4096;
We are now ready to install certificates.
Let's Encrypt certificates
Install the following packages to acquire certificates: certbot
, certbot-nginx
.
Then run:
certbot --nginx
We fill in:
email address | <your email address> |
terms | agree |
share info | no |
domain | cloud.mydomain.net |
It aquires the certificates but cannot find the server block for this domain.
PHP CGI
Install package php-fpm
and in the configuration file /etc/php/php-fpm.d/www.conf
uncomment env[PATH]
. Also set up env[TMP]
in /etc/php/php-fpm.d/www.conf
and make sure the directory is writable for the Nginx user.
We also set the following values in /etc/php/php-fpm.d/www.conf
, taken from the documentation and all values divided by 2.
pm.max_children = 60;
pm.start_servers = 6;
pm.min_spare_servers = 3;
pm.max_spare_servers = 9;
systemctl start php-fpm
systemctl enable php-fpm
Nextcloud
pacman -S nextcloud
We install the following pacman hook in /etc/pacman.d/hooks/nextcloud.hook
:
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = nextcloud
Target = nextcloud-app-*
[Action]
Description = Update Nextcloud installation
When = PostTransaction
Exec = /usr/bin/runuser -u http -- /usr/bin/php /usr/share/webapps/nextcloud/occ upgrade
Create a server block in the nginx.conf
:
upstream php-handler {
#server 127.0.0.1:9000;
server unix:/run/php-fpm/php-fpm.sock;
}
server {
listen 80;
listen [::]:80;
server_name cloud.mydomain.net;
# enforce https
return 301 https://$server_name:443$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cloud.mydomain.net;
ssl_certificate /etc/letsencrypt/live/cloud.mydomain.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cloud.mydomain.net/privkey.pem;
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
# add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
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 /usr/share/webapps/nextcloud;
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;
# The following rule is only needed for the Social app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
location = /.well-known/carddav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
# 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;
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
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\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy)\.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;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
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;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
}
We have to create a data directory for Nextcloud:
mkdir /var/nextcloud
chown http:http /var/nextcloud
chmod 750 /var/nextcloud
We also have to change permissions for the apps directories:
mkdir -p /usr/share/webapps/nextcloud/data
chown -R http:http /usr/share/webapps/nextcloud/{apps,data}
chmod 750 /usr/share/webapps/nextcloud/{apps,data}
We have to give php-fpm
permissions. We do this with the following command:
systemctl edit php-fpm.service
This will save the contents in /etc/systemd/system/php-fpm.service.d/override.conf
.
The contents:
[Service]
ReadWritePaths = /usr/share/webapps/nextcloud/apps
ReadWritePaths = /usr/share/webapps/nextcloud/data
ReadWritePaths = /etc/webapps/nextcloud/config
# Replace the following path with the Nextcloud data directory
ReadWritePaths = /var/nextcloud
We then do:
systemctl restart php-fpm
We can then open the firewall on port 80 and 443:
systemctl stop fail2ban
iptables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -i ens3 -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -i ens3 -p tcp --dport 443 -j ACCEPT
ip6tables -A INPUT -i ens3 -p tcp --dport 443 -j ACCEPT
iptables-save > /etc/iptables/iptables.rules
ip6tables-save > /etc/iptables/ip6tables.rules
systemctl start fail2ban
Postinstall
It turns out that the cache was not enabled. We do that by adding the following key to /etc/webapps/nextcloud/config/config.php
:
'memcache.local' => '\OC\Memcache\APCu',
Install the following apps:
- talk
- deck
- notes
Maintenance
The services that are run are:
- mariadb
- nginx
- php-fpm