Wiki/Guides/Arch/02Server.md
2025-04-10 04:10:54 +02:00

32 KiB

title, description, published, date, tags, editor, dateCreated
title description published date tags editor dateCreated
02 Server true 2024-11-24T11:38:12.406Z markdown 2023-04-28T08:02:53.316Z

Getting back in with the installation USB

First we have to get back into the installation medium to install the network components

You just start from USB again, Check your network, Mount the needed drives and chroot into the system

You might think, Why did I make you go trough this trouble?

Well, This routine should be common knowledge for Arch users, If you ever break your system, you now know how to get back into it and hopefully fix your system.

So once again so you don't have to go back to the previous guide.

ping archlinux.org

OK? Ctrl + C

mount the needed drives

mount /dev/nvme0n1p1 /mnt

Also mount boot if you need it, mount the second partition to /mnt/boot

mount /dev/nvme0n1p2 /mnt/boot

And finally chroot into the system so you can change whatever you need to change

arch-chroot /mnt

You should be root inside your installed system

Installing DHCP

For network capabilities we need a DHCP client so install it

pacman -S dhcpcd

That's it

Reboot into your Installation

Run the following command to escape from the chroot

exit

Run the following command to restart

reboot

Remove the USB when your screen turns black and it should boot into a login prompt

Configure network

Configuring the network is easy with dhcpcd but first we need to know what device we want to enable

ip address

It should show you a bunch of devices, Ignore lo, there can be multiple, for me it is enp4s0.

so I run the following command to activate the network

sudo systemctl enable --now dhcpcd@enp4s0

You can then test with ping if it works, if it works you can go on, if not you can disable it again with sudo systemctl disable --now dhcpcd@enp4s0 and try other network devices listed by the previous command.

Point Domains to your server

If you have any domains, you first need to edit their DNS records to point to your Server.

First we need our public IP so run the following command

host myip.opendns.com resolver1.opendns.com 

Next up you go to your domain registrar, I can recommend Dynadot.com if you don't have one

You simply login go to domain settings, look for the DNS records and let it point to your IP It should look something like this

A    domain.tld      PublicIP
A    *.domain.tld    PublicIP

The A refers to IPv4, If you need IPv6 you just add both records again this time with AAAA

domain.tld should be replaced with your custom domain, the *.domain.tld is for all subdomains.

If you have a TTL setting, just put it on the lowest possible value and don't forget to save.

Set Static IP for Server

You need a Static IP on your internal network so you can open ports on that internal IP without the device switching internal IP randomly

For this you need to login into your router, This can be a pain, If you have no idea I recommend resetting it and use the default password to login.

In the router interface you have to look for Static IP or DHCP reservation or something like that.

run the following command and look at the hardware address or MAC/link/ether address for your network device it should look something like this ab:cd:f0:12:34:56

ip address

Now you need to combine the mac address of the server with a static IP given by you, It might be good to plan out your network create different vlans like 192.168.1.X for your servers 192.168.2.X for your trusted devices 192.168.3.X for your smarthome devices and 192.168.4.X for a free wifi guest network, This way you have a seperated network for your home and servers, you can block all smarthome devices from phoning home by just blocking the subnet with 1 rule and you can seperate guests from your own devices. we are going to assume you made a subnet 192.168.1.X for your servers, and this server is 192.168.1.10.

So Mac Adress ab:cd:f0:12:34:56 needs to be assigned the local IP of 192.168.1.10.

Make sure you save, Then reboot your server and it should move over to the assigned local IP.

Open two ports to your server

For now we are only going to open the ports 80 and 443 for http and https respectively

Still in your router interface you have to look for "port forward", Don't worry about clicking trough the menus, as long as you don't press save anywhere you should be fine :)

If you found the port forwarding screen you need to open ports 80 and 443 over TCP to the local static IP of your server. So in this example case

192.168.1.10 TCP 80 192.168.1.10 TCP 443

Make sure you save and you don't need to reboot anything for this.

Be careful with opening ports here, I would recommend against opening the SSH or the FTP ports, Keep it local which keeps it somewhat safe :)

Also remember that you don't need to open ports for local services, like mysql or any of the proxy ports, You also don't have to open ports for outgoing connections, It is just for incoming connections.

Firewall

IPtables is present in the kernel and installed by default We use IPtables because docker networks don't play nice with nftables.

The default settings are fine we are leaving 80 and 443 closed, because the services we are going to host will be running from their own network. It is recomended to read up on iptables. Have a look at them and see what docker and fail2ban is changing over time. Do not change things other than steps in this guide unless you know what you are doing. See page 02 Server Iptables

Enable auto login

To make sure everything is getting started automatically after a reboot you can use autologin

edit the getty service file with the following command

sudo vim /etc/systemd/system/getty.target.wants/getty@tty1.service

Look for the following line

ExecStart=./sbin/agetty -o '-p -- \\u' --noclear - $TERM

And change it into this

ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear --autologin USERNAME - $TERM

Save and exit

You can restart to ensure you are automatically logged in, It will still ask you for a password, but it should say Automatic Login after boot. If you want to log in with another user simply press enter (wrong password) and you can type another user when needed. press enter for your other user password and you are in!

Install and Configure SSH

SSH or Secure SHell is a tool to access your server remotely, In our example we will only use it locally by simply not opening any ports in the router.

Simply install OpenSSH

sudo pacman -S openssh

We need to configure it properly so open the following file

sudo vim /etc/ssh/sshd_config

Uncomment LogLevel and change it to VERBOSE so we can use it with fail2ban

LogLevel VERBOSE

Now start and enable the service

sudo systemctl enable --now sshd

Install Docker

Docker is the containerization software we are going to use, Every service will get its own container and network.

Install it with the following command

sudo pacman -S docker

now we just need to enable it with systemctl

sudo systemctl enable --now docker

Docker should be up and running.

Install Docker Compose

Docker Compose is a front end for Docker, It allows us to set up containers and networks in an easy way.

Install it with the following command

sudo pacman -S docker-compose

Docker Compose parses yaml files, which are designed to be simple configuration files, spaces are everything here, so make sure you get the spacing right. It does allow us to set up containers quick and easy.

We configure 3 main things container details, volumes and networks

container or service details contain the name of the container, which image it should pull, when it should restart, etc.

volumes are like mounting points for persistant storage, For stuff like Configuration files, Databases, File storage, Stuff that must remain intact if you ever remove the container and rebuild it.

Networks are like virtual networks on the local network, they seperate the different services that don't need to talk to eachother. Services can be in multiple networks tho.

I hope the configuration files will make everything more clear, but this is everything you need to know for now.

Shutdown your server

Aside from fail2ban, certbot, banner/motd and updating and the docker services themself your server is done. It is the perfect time to make some changes. mainly becuase the next sections require a lot of typing and the ability to copy/paste will be very welcome.

So shutdown your machine

sudo shutdown now

Remove the power cable and press the power button this will drain any power left in the machine. Now you can remove any GPU you needed for a video output, remove any peripherals like keyboard, monitors, and give your server a nice place in your house, Just connect the ethernet and power cable and simply press the power button once to start your server again.

Wait a minute and you should be able to login to your server from a different machine over your local network in our example the Local IP was 192.168.1.10 so our command will be the following

ssh username@192.168.1.10

Fill in your password associated with your username and press enter. If you run into problems here, double check the Firewall, SSH and static IP steps. Also make sure your home vlan has access to your server vlan if you chose to use different vlans.

Banner and motd

Next up we are going to adjust the banner it will display on SSH password request

sudo vim /etc/issue

Add in the following content (you might need to \ the \ ones)

  _________
 /         \
|  Whatsup? |
 \_______  /
         \/
        .--.
       |o_o |
       |:_/ |
      //   \ \
     (|     | )
    /'\_   _/`\
    \___)=(___/

Then we have the motd which will display after login

for this we will write a little script so it has up to date information

mkdir ~/Scripts 
vim ~/Scripts/updatemotd.sh

Add in the following content

#!/bin/bash

printf "        \e[34m/#\\                     \e[0;0m_        \e[34m_ _
       \e[34m/###\\   \e[0;0m   __ _ _ __ ___| |__    \e[34m| (_)_ __  _   ___  __
      \e[34m/#####\\    \e[0;0m/ _' | '__/ __| '_ \\   \e[34m| | | '_ \\| | | \\ \\/ /
     \e[34m/##.-.##\\  \e[0;0m| (_| | | | (__| | | |  \e[34m| | | | | | |_| |>  <
    \e[34m/##(   )##\\  \e[0;0m\\__,_|_|  \\___|_| |_|  \e[34m|_|_|_| |_|\\__,_/_/\\_\\
   \e[34m/#.--   --.#\\
  \e[34m/'           '\\
" > /etc/motd
printf "\e[34mMemory Usage: \e[0;0m" >> /etc/motd && free -m | grep Mem | awk '{ printf("%dMB/%dMB ", $3, $2) }' >> /etc/motd && free | grep Mem | awk '{ printf("%.2f%% used\n", $3*100/$2) }' >> /etc/motd
printf "\e[34mDisk Free: \e[0;0m" >> /etc/motd && df -h | awk '$NF=="/"{printf "root %s ", $4}' >> /etc/motd
printf "" && df -h | awk '$NF=="/data"{printf "data %s ", $4}' >> /etc/motd
printf "" && df -h | awk '$NF=="/music"{printf "data %s ", $4}' >> /etc/motd
printf "" && df -h | awk '$NF=="/video"{printf "data %s ", $4}' >> /etc/motd
printf "\n\e[34mLast Boot: \e[0;0m$(uptime)\n" >> /etc/motd
exit

Now we are going to create a Systemtimer which will run the script

sudo vim /etc/systemd/system/updatemotd.service

Add in the following (replace USSERNAME with your username!)

[Unit]
Description=Update the motd
Wants=updatemotd.timer

[Service]
Type=oneshot
ExecStart=/bin/bash /home/USERNAME/Scripts/updatemotd.sh

[Install]
WantedBy=multi-user.target

Now we need a timer file

sudo vim /etc/systemd/system/updatemotd.timer

Add in the following content

[Unit]
Description=Runs the update motd service every minute
Requires=updatemotd.service

[Timer]
Unit=updatemotd.service
OnBootSec=1min
OnUnitActiveSec=1min

[Install]
WantedBy=timers.target

And now we finally start the timer

sudo systemctl enable --now updatemotd.timer

You can exit the ssh and log back in to see the results

Install and Configure Certbot

Certbot will create signed SSL certificates for you (For HTTPS websites)

We simply install it with the following command

sudo pacman -S certbot

First we need to open port 80 temporarily so that certbot can verify you own the domain.

sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT

Next we are going to request a certificate for every domain you pointed to this server.

sudo certbot certonly -d example.com

Just answer the questions and repeat the process for every other domain. Pick 1 if it asks for the authentication method.

Now we can restore the firewall settings again by running the following command

sudo iptables -D INPUT -p tcp -m tcp --dport 80 -j ACCEPT

Your certificates are only valid for 90 days, so we need to update them every once in a while, personally I just run a script every week that makes sure all certificates are valid

Create the script

vim ~/Scripts/renewcerts.sh

Add in the following content (replace USSERNAME with your username!)

#!/bin/bash

docker-compose -f /home/USERNAME/Docker/nginx/docker-compose.yml down
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
certbot renew
iptables -D INPUT -p tcp -m tcp --dport 80 -j ACCEPT
docker-compose -f /home/USERNAME/Docker/nginx/docker-compose.yml up -d

Next we need a service which actually executes the script so create the service file

sudo vim /etc/systemd/system/renewcerts.service

Add in the following content (replace USSERNAME with your username!)

[Unit]
Description=Updates all expiring certificates
Wants=renewcerts.timer

[Service]
Type=oneshot
ExecStart=/bin/bash /home/USERNAME/Scripts/renewcerts.sh

[Install]
WantedBy=multi-user.target

Next we need a timer which actually calls the service so create the timer file

sudo vim /etc/systemd/system/renewcerts.timer

Add in the following content

[Unit]
Description=Runs the update certificates service every week
Requires=renewcerts.service

[Timer]
OnCalendar=Tue 04:00
Persistent=true

[Install]
WantedBy=timers.target

Finally start and enable the timer so it will actually run

sudo systemctl enable --now renewcerts.timer

Install and Configure Fail2Ban

Fail2Ban will read your logs for failed login attempts or other fishy things, when it crosses a certain amount of attempts it will block the IP using the firewall.

So first we are going to install fail2ban

sudo pacman -S fail2ban

Next enable and start the service

sudo systemctl enable --now fail2ban

Create a file where we will store all of our configuration

sudo vim /etc/fail2ban/jail.local

Replace the whole contents with the following

[INCLUDES]

before = paths-arch.conf

[DEFAULT]

## Settings
ignoreip = 127.0.0.1/8 ::1 192.168.1.1/16 172.20.0.0/16
findtime = 1h
maxretry = 3
bantime = 1h
bantime.increment = true
bantime.rndtime = 3600
bantime.multipliers = 1 3 5 12 24 168 4200 999999999 
bantime.overalljails = true
banaction = action

## SSH Jail
[sshd]
enabled = true

For now we only set some default settings you can always overwrite them later on

ignoreip is pretty self explanitory, You can add your own IPs findtime is the period in which these attempts are are allowed maxretry is the number of attempts to trigger a ban bantime is pretty self explanitory bantime.increment this increments the bantime bantime.rndtime adds a random time to the bantime to fool scripts bantime.multipliers sets a custom ban time for repeated offenders bantime.overalljails makes fail2ban check accross all jails so 1 attempt at 3 services is a ban banaction is which action to perform, we will write a custom action in the next section Finally under [sshd] we enabled sshd, we have to enable every service we add. We will add more later depending on the services you want to activate

Save and exit the file

Now we need to create a banaction so fail2ban knows what to do when it needs to ban someone.

sudo vim /etc/fail2ban/action.d/action.conf

Add in the following lines

[Definition]
actionban = iptables -I INPUT -s <ip> -j REJECT
            iptables -I FORWARD -s <ip> -j REJECT
            iptables -I DOCKER-USER -s <ip> -j REJECT
	          echo "<matches>" >> /var/log/fail2ban.log

actionunban = iptables -D INPUT -s <ip> -j REJECT
              iptables -D FORWARD -s <ip> -j REJECT
              iptables -D DOCKER-USER -s <ip> -j REJECT

Here you can see that everytime it needs to ban someone it will simply execute some iptables commands that reject requests for docker and the host system.

I also put in the echo so it prints the why in the fail2ban log it can be handy for debugging but you can remove it.

Don't forget to restart the service to make the changes take effect

sudo systemctl restart fail2ban

You can use fail2ban-client to unban people or view some statistics

sudo fail2ban-client

Lets add some Aliases so viewing the banned list and unbanning people gets easier

WIP!

Install and Configure Nginx

eNGINe X is a very powerful webserver, It can do many things and is highly configurable.

We will use it as a reverse proxy to forward requests to the correct container.

Create some folders in your home directory

mkdir -p ~/Docker/nginx

Now create a docker compose file in that directory

vim ~/Docker/nginx/docker-compose.yml

Add in the following text

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    restart: always
    volumes:
      - /data/nginx/config:/etc/nginx
      - /data/nginx/log/error.log:/var/log/error.log
      - /data/nginx/log/access.log:/var/log/access.log
      - /etc/letsencrypt/:/etc/letsencrypt/
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 80:80
      - 443:443

First we need to create a folder for the configuration

sudo mkdir -p /data/nginx/config

We need to add the nginx configuration file

sudo vim /data/nginx/config/nginx.conf

Add in the following text

# Global Settings
user                 nginx;
pid                  /var/run/nginx.pid;
worker_processes     auto;
worker_rlimit_nofile 65535;

events {
    multi_accept       on;
    worker_connections 1024;
}


# Web Traffic
http {
  charset utf-8;
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  server_tokens off;
  error_log /var/log/error.log warn;
  access_log /var/log/access.log;
  proxy_cache_path /etc/nginx/cache keys_zone=one:500m max_size=1000m;
  types_hash_max_size 2048;
  types_hash_bucket_size 64;
  client_max_body_size 16M;
  client_body_buffer_size 16M;
  client_header_buffer_size 16M;
  large_client_header_buffers 2 16M;

  # MIME
  default_type           application/octet-stream;

  # Limits
  limit_req_log_level    warn;
  limit_req_zone         $binary_remote_addr zone=login:10m rate=10r/m;

  # SSL
  ssl_session_timeout    1d;
  ssl_session_cache      shared:SSL:10m;
  ssl_session_tickets    off;
  ssl_protocols          TLSv1.2 TLSv1.3;
  ssl_stapling           on;
  ssl_stapling_verify    on;

  # Services
  include /etc/nginx/services/*.active;
}

We need to create the 2 log files so docker compose won't create directories

sudo touch /data/nginx/log/access.log /data/nginx/log/error.log

We also nened to create 2 directories which will house our auth

sudo mkdir -p /data/nginx/config/auth /data/nginx/config/services

Nginx should be good now, lets start the container

sudo docker-compose -f ~/Docker/nginx/docker-compose.yml up -d 

Now we only need to setup fail2ban for Nginx, so create the following file

sudo vim /etc/fail2ban/filter.d/nginxx.local

add in the following content

[INCLUDES]
before = common.conf

[Definition]
failregex = ^<HOST>.*"(GET|POST).*" (400|401|403|404|405|406|407|423|429) .*$

This will ban everyone getting any of the error codes in the failregex line.

Now we need to activate the filter in our main fail2ban configuration file

sudo vim /etc/fail2ban/jail.local

Add the following to the bottom

## Nginx
[nginxx]
enabled = true
logpath = /data/nginx/log/access.log

Restart fail2ban to make the changes take effect

sudo systemctl restart fail2ban

Install and Configure MariaDB

MariaDB is a drop in replacement for MySQL, which is a database used by many services.

First we create some folders

mkdir -p ~/Docker/mariadb

First we will create a docker compose file

vim ~/Docker/mariadb/docker-compose.yml

Add in the following text

version: '3'

services:
  mariadb:
    image: mariadb:latest
    container_name: mariadb
    restart: always
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --skip-innodb-read-only-compressed
    volumes:
      - /data/mariadb/data:/var/lib/mysql
      - /data/mariadb/config:/etc/mysql/conf.d
      - /data/mariadb/logs:/var/log/mysql
      - /etc/localtime:/etc/localtime:ro

    environment:
      - MYSQL_ROOT_PASSWORD=SETAMYSQLROOTPASSWORDHERE

Be sure to set your mysql root password

Lets start the container

sudo docker-compose -f ~/Docker/mariadb/docker-compose.yml up -d 

Now we only need to initialize the database

sudo docker exec -it mariadb mariadb-secure-installation

Answer the first 3 questions with No and the rest with Yes

Install and Configure Nextcloud

Nextcloud is a great application, It is great for storing and syncing data, storing your contacts, bookmarks, passwords, calendar, tasks. It also has a great RSS reader, full office suite and many many more. I truly can't live without it. And neither should you which is why I picked it as the example for this guide

First we need to create a network for the service.

sudo docker network create --subnet=172.20.30.0/24 nextcloud

Next we are going to create some folders

mkdir -p ~/Docker/nextcloud

Now we will create a docker compose file

vim ~/Docker/nextcloud/docker-compose.yml

Add in the following text

version: '3'

services:
  nextcloud:
    image: nextcloud
    container_name: nextcloud
    restart: always
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /data/nextcloud:/var/www/html
    networks:
      nextcloud:
        ipv4_address: 172.20.30.10

networks:
  nextcloud:
    external: true
    name: nextcloud
    ipam:
      config:
        - subnet: 172.20.30.0/24

Now we need to add a server block for nextcloud to the Nginx config file so create a file that will be included by the main nginx config file

And create the file

sudo vim /data/nginx/config/services/nextcloud.active

add in the following text

server {
  server_name example.com;
  listen      443 ssl;

# Settings
  autoindex off;
  client_max_body_size 5000M;

# Locations
  location / {
    proxy_pass http://nextcloud:80;
    proxy_http_version                 1.1;
    proxy_cache_bypass                 $http_upgrade;
    proxy_ssl_server_name              on;
    proxy_set_header Upgrade           $http_upgrade;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Port  $server_port;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_connect_timeout              600m;
    proxy_send_timeout                 600m;
    proxy_read_timeout                 600m;
  }

  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) {
    deny all;
  }

  location = /favicon.ico {
    log_not_found off;
  }

  location = /robots.txt {
    log_not_found off;
  }

# GZip
  gzip            on;
  gzip_vary       on;
  gzip_proxied    any;
  gzip_comp_level 6;
  gzip_types      text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;

# Headers
  add_header X-XSS-Protection          "1; mode=block" always;
  add_header X-Content-Type-Options    "nosniff" always;
  add_header X-Frame-Options "SAMEORIGIN";
  add_header Referrer-Policy           "no-referrer-when-downgrade" always;
  add_header Content-Security-Policy   "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;
  add_header Permissions-Policy        "interest-cohort=()" always;
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# SSL
  ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
}

# Redirect
server {
  listen 80;
  server_name example.com;
  return 301 https://example.com$request_uri;
}

Be sure to replace example.com 6 times

Now we need to add nextcloud to the mariadb and nginx networks, because it needs a database and a proxy.

open the nginx compose file

vim ~/Docker/nginx/docker-compose.yml

add the nextcloud network so it looks like this

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    restart: always
    volumes:
      - /data/nginx/config:/etc/nginx
      - /data/nginx/log/error.log:/var/log/error.log
      - /data/nginx/log/access.log:/var/log/access.log
      - /etc/letsencrypt/:/etc/letsencrypt/
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 80:80
      - 443:443
      - 8448:8448
    networks:
      nextcloud:
        ipv4_address: 172.20.30.20

networks:
  nextcloud:
    external: true
    name: nextcloud

open the mariadb compose file

vim ~/Docker/mariadb/docker-compose.yml

add the nextcloud network so it looks like this

version: '3'

services:
  mariadb:
    image: mariadb:latest
    container_name: mariadb
    restart: always
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --skip-innodb-read-only-compressed
    volumes:
      - /data/mariadb/data:/var/lib/mysql
      - /data/mariadb/config:/etc/mysql/conf.d
      - /data/mariadb/logs:/var/log/mysql
      - /etc/localtime:/etc/localtime:ro

    environment:
      - MYSQL_ROOT_PASSWORD=SETAMYSQLROOTPASSWORDHERE
    networks:
      nextcloud:
        ipv4_address: 172.20.30.30

networks:
  nextcloud:
    external: true
    name: nextcloud

Now we are going to start the nextcloud container and restart the nginx and mariadb containers.

sudo docker-compose -f ~/Docker/nextcloud/docker-compose.yml up -d
sudo docker-compose -f ~/Docker/nginx/docker-compose.yml down && sudo docker-compose -f ~/Docker/nginx/docker-compose.yml up -d
sudo docker-compose -f ~/Docker/mariadb/docker-compose.yml down && sudo docker-compose -f ~/Docker/mariadb/docker-compose.yml up -d

Nextcloud should be accessable from your browser using the domain you chose. If you have not setup your dns records but only adjusted your .active file for nginx you need to do 2 things first before you go on.

  • make sure you have chosen a domain (nextcloud.example.com) and used it in your .active file for nginx.
  • make sure you have valid certificates for this domain. if not go back to the certbot part so you can repeat those instructions for your nextcloud domain.

But first we need to create a database, a user and set the permissions.

You can get into the database with the following command (only if mariadb is running)

sudo docker exec -it mariadb mariadb -p

Enter the Mysql root password you provided during the creation of the mariadb container and you should be in.

Now run the following commands to create a database, create a user with privileges, and make them take effect.

create database nextcloud;
create user nextcloud@'172.20.30.10' identified by 'NEXTCLOUDDATABASEPASSWORD';
grant all privileges on nextcloud.* to nextcloud@'172.20.30.10';
flush privileges;

You can exit the mysql prompt with exit; and then pressing enter.

Now we just need to go to example.com and follow the steps

The Database is nextcloud, the user is nextcloud, The IP is 172.20.30.30:3306 and the password is what you gave it.

We also need to force HTTPS, else it will give problems since we are running from behind a proxy

sudo vim /data/nextcloud/config/config.php

Add in the following line preferrrably under the overwrite.cli.url line.

'overwriteprotocol' => 'https',

Nextcloud requires some tasks to be executed every 5 minutes, for that we are going to use systemd timers, like we did for certbot

Create a little script

vim ~/Scripts/nextcloudcron.sh

add in the following content

#!/bin/bash

docker exec -u 33 -t nextcloud php -f /var/www/html/cron.php
exit

Create a systemd service

sudo vim /etc/systemd/system/nextcloudcron.service

Add in the following content

[Unit]
Description=Runs Nextcloud Cron
Wants=nextcloudcron.timer

[Service]
Type=oneshot
ExecStart=/bin/bash /home/USERNAME/Scripts/nextcloudcron.sh

[Install]
WantedBy=multi-user.target

Create a timer file

sudo vim /etc/systemd/system/nextcloudcron.timer

and add in the following content

[Unit]
Description=Runs Nextcloud Cron
Requires=nextcloudcron.service

[Timer]
Unit=nextcloudcron.service
OnBootSec=5min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target

Finally start the timer

sudo systemctl enable --now nextcloudcron.timer

Nextcloud should be all good and ready to go, You can check the persistance by completely deleting all containers and all volumes, When you start it again all your stuff should still be there :)

Nextcloud has its own Brute force protection, but we still are going to add a fail2ban filter because we want attackers to be banned from all services and not just nextcloud.

So lets create a new nextcloud filter

sudo vim /etc/fail2ban/filter.d/nextcloud.local

add in the following content

[Definition]
failregex=^{"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)","level":2,"time":".*"}$
          ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user":".*","app":".*","method":".*","url":".*","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)".*}$
          ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user":".*","app":".*","method":".*","url":".*","message":"Login failed: .* \(Remote IP: <HOST>\).*}$

Now add the filter to your main fail2ban config file

sudo vim /etc/fail2ban/jail.local

Add the following to the end of the file

## Nextcloud
[nextcloud]
filter = nextcloud
enabled = true
logpath = /data/nextcloud/data/nextcloud.log

restart fail2ban to make it take effect

sudo systemctl restart fail2ban

Updating the Server

To maintain the system we simply need to update it by running the following command

sudo pacman -Syu

To update the docker containers we need to pull every container and then restart it, it would be a lot of work every time you want to upgrade. It is easier to create a script instead of manually typing all the commands every time.

So create a file

vim ~/Scripts/update-docker.sh

put in the following text

#!/bin/bash

# Update Nginx
docker-compose -f /home/USERNAME/Docker/nginx/docker-compose.yml pull
docker-compose -f /home/USERNAME/Docker/nginx/docker-compose.yml down
docker-compose -f /home/USERNAME/Docker/nginx/docker-compose.yml up -d --remove-orphans

# Update MariaDB
docker-compose -f /home/USERNAME/Docker/mariadb/docker-compose.yml pull
docker-compose -f /home/USERNAME/Docker/mariadb/docker-compose.yml down
docker-compose -f /home/USERNAME/Docker/mariadb/docker-compose.yml up -d --remove-orphans

# Update Nextcloud
docker-compose -f /home/USERNAME/Docker/nextcloud/docker-compose.yml pull
docker-compose -f /home/USERNAME/Docker/nextcloud/docker-compose.yml down
docker-compose -f /home/USERNAME/Docker/nextcloud/docker-compose.yml up -d --remove-orphans

You should add any services you add to this simple script so all containers get updated

Save, exit and then make it executable with the following command

sudo chmod u+x update-docker.sh

You can now run the script to update all docker containers

Let the script run with pacman

Why mess around with 2 commands, when you can simply force the docker-update.sh script to run when you update your system using pacman. We can do this very easy with pacman hooks

create a file in the hooks directory for docker

sudo vim /usr/share/libalpm/hooks/docker.hook

Add in the following text

[Trigger]
Operation = Upgrade
Type = Package
Target = *
[Action]
Description = Update Docker Containers
When = PostTransaction
Exec = /bin/bash /home/USERNAME/Scripts/update-docker.sh

Save and exit and try to update your system, if you are lucky you have an update and you can see the script in action after the update.

Next

For now I would continue the guide Terminal and Programming are quite useful for a server, I would also recommend reading the maintenance part of the guide. But you can skip basic programs, office, gaming, etc

When you are done you can go to my Docker guide, and install any service your heart desires :)