Skip to content

Instantly share code, notes, and snippets.

@jakzal
Last active December 13, 2023 21:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakzal/2b571ba0eef65c58e603acf1d4b2fce0 to your computer and use it in GitHub Desktop.
Save jakzal/2b571ba0eef65c58e603acf1d4b2fce0 to your computer and use it in GitHub Desktop.
Nextcloud behind Cloudflare on a Raspberry PI

Nextcloud behind Cloudflare on a Raspberry PI

Prerequisites

Install Raspberry Pi OS

Install the Raspberry Pi OS on the SSD drive with the Raspberry Pi Imager.

Boot the Pi and ssh to it.

Create directories

mkdir nextcloud
cd nextcloud
mkdir -p app/config app/custom_apps app_data caddy_data db_data cloudflared

Setup permissions

In order for www-data and pi users to read and write nextcloud directories. New files will inherit these permissions.

sudo setfacl -R -m u:pi:rwx app app_data 
sudo setfacl -R -d -m u:pi:rwx app app_data
sudo setfacl -R -m u:www-data:rwx app app_data
sudo setfacl -R -d -m u:www-data:rwx app app_data
sudo setfacl -R -m mask:rwx app app_data
sudo setfacl -R -d -m mask:rwx app app_data

Copy configuration files

  • nextcloud/docker-compose.yml
  • nextcloud/Caddyfile
  • nextcloud/nextcloud-docker/Dockerfile

Build the nextcloud image

cd nextcloud-docker && docker build -t jakzal/nextcloud:latest && cd -

Configure the Cloudflare tunnel

Create a group and user for uid/gid 65532 that the cloudflared uses.

sudo groupadd -g 65532 -U pi nonroot
sudo useradd -g 65532 -M -u 65532 nonroot

It might also be good to add the pi user to the www-data group in /etc/group.

Create the volume for cloudflared certs and configuration.

docker compose run --no-deps cloudflared tunnel login
docker compose run --no-deps cloudflared tunnel create nextcloud
docker compose run --no-deps cloudflared tunnel route dns nextcloud next.example.com

Make a note of the tunnel ID.

Create cloudflared/config.yml.

tunnel: <TUNNEL-ID>
credentials-file: /home/nonroot/.cloudflared/<TUNNEL-ID>.json
ingress:
  - hostname: "next.example.com"
    service: http://web
    originRequest:
      originServerName: "next.example.com"
  - service: http_status:404

Start everything

docker compose up -d

Configure nextcloud

Go to https://next.example.com and complete the installation.

Update app/config/config.php with your configuration.

Mv data and fix app_data permissions.

sudo mv app/data/* app_data/
sudo mv app/data/.ocdata app_data/
sudo mv app/data/.htaccess app_data/
sudo chown -R www-data:www-data app_data/

Rescan the files.

docker compose exec -u www-data app php occ files:scan --all

Go to the admin overview to check the installation. In case of problems with missing .ocdata file, go to Basic Settings -> Webcron -> back to Ajax.

Run it as a service

Create /lib/systemd/system/nextcloud.service.

Enable the nextcloud.service and start it.

sudo systemctl enable nextcloud.service
sudo systemctl start nextcloud.service

Configure cron

https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/background_jobs_configuration.html#systemd

version: '3'
services:
cloudflared:
image: 'cloudflare/cloudflared:latest'
restart: always
volumes:
- cloudflared_certs:/home/nonroot/.cloudflared
environment:
- PUID=1000
- PGID=1000
links:
- web
command: tunnel run nextcloud
db:
image: 'postgres:16.1'
restart: always
volumes:
- db_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=2035e48e
- POSTGRES_USER=a1cfa51b806b
- POSTGRES_PASSWORD=e8ff2758-579c-449a-8a0d-f4b0c8311db0
redis:
image: redis:7.2-alpine
restart: always
app:
image: 'jakzal/nextcloud:latest'
restart: always
volumes:
- ./app/config/config.php:/var/www/html/config/config.php:rw
- app_custom_apps:/var/www/html/custom_apps
- app_data:/nextcloud-data
environment:
- POSTGRES_HOST=db
- POSTGRES_DB=2035e48e
- POSTGRES_USER=a1cfa51b806b
- POSTGRES_PASSWORD=e8ff2758-579c-449a-8a0d-f4b0c8311db0
links:
- db
- redis
web:
image: 'caddy:2.7.5-alpine'
restart: always
ports:
- 80:80
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
volumes_from:
- app
links:
- app
volumes:
cloudflared_certs:
driver: local
driver_opts:
type: none
o: bind
device: ./cloudflared
app_custom_apps:
driver: local
driver_opts:
type: none
o: bind
device: ./app/custom_apps
app_data:
driver: local
driver_opts:
type: none
o: bind
device: ./app_data
db_data:
driver: local
driver_opts:
type: none
o: bind
device: ./db_data
caddy_data:
driver: local
driver_opts:
type: none
o: bind
device: ./caddy_data
{
auto_https off
}
next.example.com:80 {
encode zstd gzip
root * /var/www/html
redir /.well-known/carddav /remote.php/dav 301
redir /.well-known/caldav /remote.php/dav 301
header {
Strict-Transport-Security max-age=31536000;
}
file_server
@forbidden {
path /data/* /config/* /README /3rdparty/* /lib/* /templates/* /core
path /.htaccess /console.php /composer.* /.xml /occ /db_structure
}
try_files {path} {path}/index.php
respond @forbidden 404
php_fastcgi app:9000
}
<?php
$CONFIG = array (
'memcache.local' => '\\OC\\Memcache\\APCu',
'apps_paths' =>
array (
0 =>
array (
'path' => '/var/www/html/apps',
'url' => '/apps',
'writable' => false,
),
1 =>
array (
'path' => '/var/www/html/custom_apps',
'url' => '/custom_apps',
'writable' => true,
),
),
'instanceid' => 'asdfasdf',
'passwordsalt' => 'asdfasdf',
'secret' => 'asdfasdfsad',
'trusted_domains' =>
array (
0 => 'next.example.com',
),
'datadirectory' => '/nextcloud-data',
'dbtype' => 'pgsql',
'version' => '27.1.3.2',
'overwrite.cli.url' => 'https://next.example.com',
'dbname' => 'nextcloud',
'dbhost' => 'db',
'dbport' => '',
'dbtableprefix' => 'asdf',
'dbuser' => 'asdf',
'dbpassword' => 'asdf',
'filelocking.enabled' => true,
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
'host' => 'redis',
'port' => 6379,
'timeout' => 0.0,
],
'installed' => true,
'htaccess.IgnoreFrontController' => true,
'overwriteprotocol' => 'https',
'overwritehost' => 'next.example.com',
'trusted_proxies' => [
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'104.16.0.0/13',
'104.24.0.0/14',
'108.162.192.0/18',
'131.0.72.0/22',
'141.101.64.0/18',
'162.158.0.0/15',
'172.64.0.0/13',
'173.245.48.0/20',
'188.114.96.0/20',
'190.93.240.0/20',
'197.234.240.0/22',
'198.41.128.0/17',
],
'default_phone_region' => 'GB',
'enable_previews' => true,
'preview_max_x' => 1000,
'preview_max_y' => 1000,
'enabledPreviewProviders' => [
'OC\\Preview\\TXT',
'OC\\Preview\\MarkDown',
'OC\\Preview\\PDF',
'OC\\Preview\\MSOfficeDoc',
'OC\\Preview\\JPEG',
'OC\\Preview\\PNG',
'OC\\Preview\\GIF',
'OC\\Preview\\BMP',
'OC\\Preview\\XBitmap',
'OC\\Preview\\MP3',
'OC\\Preview\\HEIC',
'OC\\Preview\\Movie',
'OC\\Preview\\MKV',
'OC\\Preview\\MP4',
'OC\\Preview\\AVI',
],
);
FROM nextcloud:stable-fpm
RUN apt update && apt install -y ffmpeg imagemagick exif && rm -rf /var/lib/apt/lists/*
RUN echo 'pm.max_children = 100' >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
echo 'pm.max_requests = 500' >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
echo 'pm.start_servers = 4' >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
echo 'pm.max_spare_servers = 8' >> /usr/local/etc/php-fpm.d/zz-docker.conf
[Unit]
Description=NextCloud
Requires=docker.service
After=network.target docker.service
[Service]
User=pi
Restart=always
RestartSec=5s
WorkingDirectory=/home/pi/nextcloud
ExecStart=/usr/bin/docker compose up
ExecStop=-/usr/bin/docker compose stop
[Install]
WantedBy=multi-user.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment