├── README.md ├── UNLICENSE └── images └── Puffy.png /README.md: -------------------------------------------------------------------------------- 1 | # Nextcloud on OpenBSD 2 | 3 | Summary 4 | --- 5 | 6 | ![puffy.png](images/Puffy.png) 7 | 8 | The most secure cloud server on the most secure operating system. 9 | 10 | ### Goal 11 | 12 | * OpenBSD 6.6 with full disk encryption 13 | * Nextcloud 18.0.4 14 | * PostgreSQL 15 | * PHP 7.3 and PHP-FPM 16 | * OpenBSD httpd 17 | * Caching and file-locking through Redis 18 | 19 | Preparation 20 | --- 21 | 22 | 1. Assemble your hardware 23 | 24 | I used an [APU2E4](https://www.varia-store.com/en/produkt/36818-pc-engines-apu2e4-system-board-3x-lan-4-gb-ram.html) with 500 GB 860 EVO SATA III mSATA SSD. Don't forget to setup cooling on the [APU2E4](https://www.pcengines.ch/apucool.htm), otherwise it will randomly shut down every couple minutes when it overheats. You will also need a USB to Serial (9-Pin) Converter Cable and Modem Serial RS232 Cable to connect over serial port for OS installation. 25 | 26 | 2. Connect over serial 27 | 28 | 29 | The APU serial connection uses 115200 baud rate, 8N1 (8 data bits, no parity, 1 stop bit). 30 | 31 | On OpenBSD, use [cu](https://man.openbsd.org/cu): 32 | 33 | ```console 34 | $ doas cu -r -s 115200 -l cuaU0 35 | ``` 36 | 37 | On Linux, use [screen](https://www.gnu.org/software/screen/manual/screen.html): 38 | 39 | ```console 40 | $ screen /dev/ttyUSB0 115200 8N1 41 | ``` 42 | 43 | Or use [minicom](https://linux.die.net/man/1/minicom): 44 | 45 | ```console 46 | $ sudo minicom -D /dev/ttyUSB0 47 | ``` 48 | 49 | Power on the APU and make note of the firmware version displayed briefly during boot. 50 | 51 | 3. Update firmware 52 | 53 | Follow [this section](https://github.com/drduh/PC-Engines-APU-Router-Guide#updating-firmware) of the excellent drduh guide. 54 | 55 | Note that the APU2E4 takes files with the `apu2` prefix, not the `apu4` prefix drduh uses. 56 | 57 | 4. Prepare OpenBSD installer 58 | 59 | Use another computer to prepare an installer for OpenBSD 6.6. This example uses Debian 10. 60 | 61 | Download the installation image - [`amd64/install66.fs`](https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs) and [`SHA256.sig`](https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/SHA256.sig) files. 62 | 63 | Verify the signatures file and hash of the installation image from Debian 10 (you might have to manually add openbsd-66-base.pub): 64 | 65 | ```console 66 | $ sudo apt-get install signify-openbsd signify-openbsd-keys 67 | 68 | $ cat /usr/share/signify-openbsd-keys/openbsd-66-base.pub 69 | untrusted comment: openbsd 6.6 base public key 70 | RWSvK/c+cFe24BIalifKnqoqdvLlXfeZ9MIj3MINndNeKgyYw5PpcWGn 71 | 72 | $ signify-openbsd -C -p /usr/share/signify-openbsd-keys/openbsd-66-base.pub -x SHA256.sig install66.fs 73 | Signature Verified 74 | install66.fs: OK 75 | ``` 76 | 77 | Insert a USB disk. Run `dmesg` to identify its label. Then copy the installation file to the USB disk: 78 | 79 | ```console 80 | $ sudo dd if=install66.fs of=/dev/sdd bs=1M 81 | ``` 82 | 83 | Install OpenBSD 6.6 84 | --- 85 | 86 | 1. Boot the APU and set serial console parameters 87 | 88 | Press `F10` at boot and select the USB disk. 89 | 90 | Set the serial console parameters: 91 | 92 | ```console 93 | Booting from Hard Disk... 94 | Using drive 0, partition 3. 95 | Loading...... 96 | probing: pc0 com0 com1 com2 com3 mem[639K 3325M 752M a20=on] 97 | disk: hd0+ hd1+* 98 | >> OpenBSD/amd64 BOOT 3.45 99 | boot> stty com0 115200 100 | boot> set tty com0 101 | switching console to com>> OpenBSD/amd64 BOOT 3.45 102 | boot> [Press Enter] 103 | ``` 104 | 105 | 2. Enable full disk encryption 106 | 107 | Select the shell option: 108 | 109 | ```console 110 | Welcome to the OpenBSD/amd64 6.6 installation program. 111 | (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? S 112 | ``` 113 | 114 | Since the installer does not have many device nodes by default, make sure the /dev/sd0 device exists: 115 | 116 | ```console 117 | # cd /dev && sh MAKEDEV sd0 118 | ``` 119 | 120 | You may want to write random data to the drive first with something like the following. This will take a while: 121 | 122 | ```console 123 | # dd if=/dev/urandom of=/dev/rsd0c bs=1m 124 | ``` 125 | 126 | If you're booting from MBR (which we are on the APU), do: 127 | 128 | ```console 129 | # fdisk -iy sd0 130 | Writing MBR at offset 0. 131 | ``` 132 | 133 | Next, create the partition layout: 134 | 135 | ```console 136 | # disklabel -E sd0 137 | Label editor (enter '?' for help at any prompt) 138 | sd0> a a 139 | offset: [64] 140 | size: [39825135] * 141 | FS type: [4.2BSD] RAID 142 | sd0> w 143 | sd0> q 144 | No label changes. 145 | ``` 146 | 147 | We'll use the entire disk, but note that the encrypted device can be split up into multiple partitions as if it were a regular hard drive. 148 | 149 | Now we can build the encrypted device on our "a" partition. 150 | 151 | ```console 152 | # bioctl -c C -l sd0a softraid0 153 | New passphrase: 154 | Re-type passphrase: 155 | sd2 at scsibus2 targ 1 lun 0: 156 | sd2: 476937MB, 512 bytes/sector, 976767473 sectors 157 | softraid0: CRYPTO volume attached as sd2 158 | ``` 159 | 160 | Make sure the /dev/sd2 device is accounted for: 161 | 162 | ```console 163 | # cd /dev && sh MAKEDEV sd2 164 | ``` 165 | 166 | As in the previous example, we'll overwrite the first megabyte of our new pseudo-device. 167 | 168 | ```console 169 | # dd if=/dev/zero of=/dev/rsd2c bs=1m count=1 170 | ``` 171 | 172 | Type `exit` to return to the main installer. 173 | 174 | 3. Install OpenBSD 6.6 175 | 176 | Select the install option: 177 | 178 | ```console 179 | Welcome to the OpenBSD/amd64 6.6 installation program. 180 | (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? I 181 | ``` 182 | 183 | Perform your install (em0 is the ethernet port closest to the serial port): 184 | 185 | ```console 186 | Terminal type? [vt220] 187 | System hostname? (short form, e.g. 'foo') nextcloud 188 | 189 | Available network interfaces are: em0 em1 em2 vlan0. 190 | Which network interface do you wish to configure? (or 'done') [em0] 191 | IPv4 address for em0? (or 'dhcp' or 'none') [dhcp] 192 | em0: * lease accepted from * (*) 193 | IPv6 address for em0? (or 'autoconf' or 'none') [none] 194 | Available network interfaces are: em0 em1 em2 vlan0. 195 | Which network interface do you wish to configure? (or 'done') [done] 196 | Using DNS domainname * 197 | Using DNS nameservers at * 198 | 199 | Password for root account? (will not echo) 200 | Password for root account? (again) 201 | Start sshd(8) by default? [yes] 202 | Change the default console to com0? [yes] 203 | Available speeds are: 9600 19200 38400 57600 115200. 204 | Which speed should com0 use? (or 'done') [115200] 205 | Setup a user? (enter a lower-case loginname, or 'no') [no] admin 206 | Full name for user admin? [admin] 207 | Password for user admin? (will not echo) 208 | Password for user admin? (again) 209 | WARNING: root is targeted by password guessing attacks, pubkeys are safer. 210 | Allow root ssh login? (yes, no, prohibit-password) [no] 211 | What timezone are you in? ('?' for list) [*] UTC 212 | 213 | Available disks are: sd0 sd1 sd2. 214 | Which disk is the root disk? ('?' for details) [sd0] ? 215 | sd0: ATA, Samsung SSD 860, RVT4 naa.5002538e40e58a29 (465.8G) 216 | sd1: SanDisk, Ultra USB 3.0, 1.00 serial.07815591270227120553 (14.3G) 217 | sd2: OPENBSD, SR CRYPTO, 006 (465.8G) 218 | Available disks are: sd0 sd1 sd2. 219 | Which disk is the root disk? ('?' for details) [sd0] sd2 220 | No valid MBR or GPT. 221 | Use (W)hole disk MBR, whole disk (G)PT or (E)dit? [whole] 222 | Setting OpenBSD MBR partition to whole sd2...done. 223 | ``` 224 | 225 | We need to enlarge the /var partition because this is where our nextcloud data directory is located. We do this by swapping the sizes of /home and /var (i.e. make /home 11.9G and /var 300.0G: 226 | 227 | ```console 228 | The auto-allocated layout for sd2 is: 229 | # size offset fstype [fsize bsize cpg] 230 | a: 1.0G 64 4.2BSD 2048 16384 1 # / 231 | b: 4.2G 2097216 swap 232 | c: 465.8G 0 unused 233 | d: 4.0G 10941664 4.2BSD 2048 16384 1 # /tmp 234 | e: 11.9G 19330240 4.2BSD 2048 16384 1 # /var 235 | f: 3.0G 44359136 4.2BSD 2048 16384 1 # /usr 236 | g: 1.0G 50650592 4.2BSD 2048 16384 1 # /usr/X11R6 237 | h: 20.0G 52747744 4.2BSD 2048 16384 1 # /usr/local 238 | i: 2.0G 94690784 4.2BSD 2048 16384 1 # /usr/src 239 | j: 6.0G 98885088 4.2BSD 2048 16384 1 # /usr/obj 240 | k: 300.0G 111468032 4.2BSD 4096 32768 1 # /home 241 | Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] e 242 | Label editor (enter '?' for help at any prompt) 243 | sd2> p 244 | OpenBSD area: 64-976752000; size: 976751936; free: 236138472 245 | # size offset fstype [fsize bsize cpg] 246 | a: 2097152 64 4.2BSD 2048 16384 1 # / 247 | b: 8844440 2097216 swap 248 | c: 976767473 0 unused 249 | d: 8388576 10941664 4.2BSD 2048 16384 1 # /tmp 250 | e: 25028896 19330240 4.2BSD 2048 16384 1 # /var 251 | f: 6291456 44359136 4.2BSD 2048 16384 1 # /usr 252 | g: 2097152 50650592 4.2BSD 2048 16384 1 # /usr/X11R6 253 | h: 41943040 52747744 4.2BSD 2048 16384 1 # /usr/local 254 | i: 4194304 94690784 4.2BSD 2048 16384 1 # /usr/src 255 | j: 12582912 98885088 4.2BSD 2048 16384 1 # /usr/obj 256 | k: 629145536 111468032 4.2BSD 4096 32768 1 # /home 257 | sd2> c k 258 | Partition k is currently 629145536 sectors in size, and can have a maximum 259 | size of 865283968 sectors. 260 | size: [629145536] 11.9G 261 | sd2*> R e 262 | [+|-]new size (with unit): [25028896] 300.0G 263 | sd2*> p 264 | OpenBSD area: 64-976752000; size: 976751936; free: 236195291 265 | # size offset fstype [fsize bsize cpg] 266 | a: 2097152 64 4.2BSD 2048 16384 1 # / 267 | b: 8844440 2097216 swap 268 | c: 976767473 0 unused 269 | d: 8388576 10941664 4.2BSD 2048 16384 1 # /tmp 270 | e: 629145600 19330240 4.2BSD 4096 32768 1 # /var 271 | f: 6291456 648475840 4.2BSD 2048 16384 1 # /usr 272 | g: 2097152 654767296 4.2BSD 2048 16384 1 # /usr/X11R6 273 | h: 41943040 656864448 4.2BSD 2048 16384 1 # /usr/local 274 | i: 4194304 698807488 4.2BSD 2048 16384 1 # /usr/src 275 | j: 12582912 703001792 4.2BSD 2048 16384 1 # /usr/obj 276 | k: 24972013 715584704 4.2BSD 4096 32768 1 # /home 277 | sd2*> w 278 | sd2> q 279 | No label changes. 280 | /dev/rsd2a: 1024.0MB in 2097152 sectors of 512 bytes 281 | 6 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 282 | /dev/rsd2k: 12193.4MB in 24972008 sectors of 512 bytes 283 | 15 cylinder groups of 814.44MB, 26062 blocks, 52224 inodes each 284 | /dev/rsd2d: 4096.0MB in 8388576 sectors of 512 bytes 285 | 21 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 286 | /dev/rsd2f: 3072.0MB in 6291456 sectors of 512 bytes 287 | 16 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 288 | /dev/rsd2g: 1024.0MB in 2097152 sectors of 512 bytes 289 | 6 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 290 | /dev/rsd2h: 20480.0MB in 41943040 sectors of 512 bytes 291 | 102 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 292 | /dev/rsd2j: 6144.0MB in 12582912 sectors of 512 bytes 293 | 31 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 294 | /dev/rsd2i: 2048.0MB in 4194304 sectors of 512 bytes 295 | 11 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each 296 | /dev/rsd2e: 307200.0MB in 629145600 sectors of 512 bytes 297 | 378 cylinder groups of 814.44MB, 26062 blocks, 52224 inodes each 298 | Available disks are: sd0 sd1. 299 | Which disk do you wish to initialize? (or 'done') [done] 300 | /dev/sd2a (e1a56df125cd094b.a) on /mnt type ffs (rw, asynchronous, local) 301 | /dev/sd2k (e1a56df125cd094b.k) on /mnt/home type ffs (rw, asynchronous, local, nodev, nosuid) 302 | /dev/sd2d (e1a56df125cd094b.d) on /mnt/tmp type ffs (rw, asynchronous, local, nodev, nosuid) 303 | /dev/sd2f (e1a56df125cd094b.f) on /mnt/usr type ffs (rw, asynchronous, local, nodev) 304 | /dev/sd2g (e1a56df125cd094b.g) on /mnt/usr/X11R6 type ffs (rw, asynchronous, local, nodev) 305 | /dev/sd2h (e1a56df125cd094b.h) on /mnt/usr/local type ffs (rw, asynchronous, local, nodev) 306 | /dev/sd2j (e1a56df125cd094b.j) on /mnt/usr/obj type ffs (rw, asynchronous, local, nodev, nosuid) 307 | /dev/sd2i (e1a56df125cd094b.i) on /mnt/usr/src type ffs (rw, asynchronous, local, nodev, nosuid) 308 | /dev/sd2e (e1a56df125cd094b.e) on /mnt/var type ffs (rw, asynchronous, local, nodev, nosuid) 309 | 310 | Let's install the sets! 311 | Location of sets? (disk http nfs or 'done') [http] 312 | HTTP proxy URL? (e.g. 'http://proxy:8080', or 'none') [none] 313 | HTTP Server? (hostname, list#, 'done' or '?') cdn.openbsd.org 314 | Server directory? [pub/OpenBSD/6.6/amd64] 315 | 316 | Select sets by entering a set name, a file name pattern or 'all'. De-select 317 | sets by prepending a '-', e.g.: '-game*'. Selected sets are labelled '[X]'. 318 | [X] bsd [X] base66.tgz [X] game66.tgz [X] xfont66.tgz 319 | [X] bsd.mp [X] comp66.tgz [X] xbase66.tgz [X] xserv66.tgz 320 | [X] bsd.rd [X] man66.tgz [X] xshare66.tgz 321 | Set name(s)? (or 'abort' or 'done') [done] 322 | Get/Verify SHA256.sig 100% |**************************| 2141 00:00 323 | Signature Verified 324 | Get/Verify bsd 100% |**************************| 18250 KB 00:02 325 | Get/Verify bsd.mp 100% |**************************| 18336 KB 00:02 326 | Get/Verify bsd.rd 100% |**************************| 10058 KB 00:01 327 | Get/Verify base66.tgz 100% |**************************| 236 MB 00:34 328 | Get/Verify comp66.tgz 100% |**************************| 72109 KB 00:10 329 | Get/Verify man66.tgz 100% |**************************| 7418 KB 00:01 330 | Get/Verify game66.tgz 100% |**************************| 2745 KB 00:00 331 | Get/Verify xbase66.tgz 100% |**************************| 22092 KB 00:03 332 | Get/Verify xshare66.tgz 100% |**************************| 4482 KB 00:00 333 | Get/Verify xfont66.tgz 100% |**************************| 39342 KB 00:06 334 | Get/Verify xserv66.tgz 100% |**************************| 15757 KB 00:02 335 | Installing bsd 100% |**************************| 18250 KB 00:00 336 | Installing bsd.mp 100% |**************************| 18336 KB 00:00 337 | Installing bsd.rd 100% |**************************| 10058 KB 00:00 338 | Installing base66.tgz 100% |**************************| 236 MB 00:41 339 | Extracting etc.tgz 100% |**************************| 260 KB 00:00 340 | Installing comp66.tgz 100% |**************************| 72109 KB 00:19 341 | Installing man66.tgz 100% |**************************| 7418 KB 00:02 342 | Installing game66.tgz 100% |**************************| 2745 KB 00:00 343 | Installing xbase66.tgz 100% |**************************| 22092 KB 00:05 344 | Extracting xetc.tgz 100% |**************************| 7017 00:00 345 | Installing xshare66.tgz 100% |**************************| 4482 KB 00:02 346 | Installing xfont66.tgz 100% |**************************| 39342 KB 00:07 347 | Installing xserv66.tgz 100% |**************************| 15757 KB 00:03 348 | Location of sets? (disk http nfs or 'done') [done] 349 | Saving configuration files... done. 350 | Making all device nodes... done. 351 | Multiprocessor machine; using bsd.mp instead of bsd. 352 | Relinking to create unique kernel... done. 353 | 354 | CONGRATULATIONS! Your OpenBSD install has been successfully completed! 355 | 356 | When you login to your new system the first time, please read your mail 357 | using the 'mail' command. 358 | 359 | Exit to (S)hell, (H)alt or (R)eboot? [reboot] 360 | ``` 361 | 362 | 4. Configure your system 363 | 364 | Don't forget to remove your USB stick, or you will continue to boot into the installer. With full disk encryption [if your password starts with an "n"](https://poolp.org/posts/2018-01-29/install-openbsd-on-dedibox-with-full-disk-encryption/) you must first enter the serial console parameters before you can decrypt the disk. Press enter twice to skip the password prompt: 365 | 366 | ```console 367 | Booting from Hard Disk... 368 | Using drive 0, partition 3. 369 | Loading...... 370 | probing: pc0 com0 com1 com2 com3 mem[639K 3325M 752M a20=on] 371 | disk: hd0+ sr0* 372 | >> OpenBSD/amd64 BOOT 3.45 373 | Passphrase: 374 | aborting... 375 | Passphrase: 376 | aborting... 377 | open(sr0a:/etc/boot.conf): Operation not permitted 378 | boot> stty com0 115200 379 | boot> set tty com0 380 | switching console to com>> OpenBSD/amd64 BOOT 3.45 381 | boot> 382 | Passphrase: 383 | ``` 384 | 385 | Log in as admin 386 | 387 | Enable doas: 388 | 389 | ```console 390 | $ su 391 | # cp /etc/examples/doas.conf /etc 392 | ``` 393 | 394 | Make it look like this: 395 | 396 | ``` 397 | # $OpenBSD: doas.conf,v 1.1 2016/09/03 11:58:32 pirofti Exp $ 398 | # Configuration sample file for doas(1). 399 | # See doas.conf(5) for syntax and examples. 400 | 401 | # Non-exhaustive list of variables needed to build release(8) and ports(7) 402 | #permit nopass setenv { \ 403 | # FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \ 404 | # DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \ 405 | # MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \ 406 | # PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \ 407 | # SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc 408 | 409 | # Allow wheel by default 410 | permit persist keepenv :wheel 411 | ``` 412 | 413 | Test doas: 414 | 415 | ```console 416 | # exit 417 | $ doas su 418 | doas (admin@nextcloud.*) password: 419 | # exit 420 | ``` 421 | 422 | Enable ntpd. Edit `/etc/rc.conf.local` and append: 423 | 424 | ``` 425 | ntpd_flags=-s 426 | ``` 427 | 428 | Disable root account: 429 | 430 | ```console 431 | $ doas usermod -p'*' root 432 | ``` 433 | 434 | Update your system: 435 | 436 | ```console 437 | $ doas syspatch 438 | $ doas fw_update 439 | ``` 440 | 441 | [Add your ssh key](https://www.cyberciti.biz/faq/how-to-set-up-ssh-keys-on-linux-unix/) to `~/.ssh/authorized_keys` 442 | 443 | Edit `/etc/ssh/sshd_config` and set these values unless you explicitly need them: 444 | 445 | ``` 446 | PasswordAuthentication no 447 | PermitRootLogin no 448 | MaxAuthTries 2 449 | MaxSessions 2 450 | AllowAgentForwarding no 451 | AllowTcpForwarding no 452 | TCPKeepAlive no 453 | Compression no 454 | ClientAliveInterval 2 455 | ClientAliveCountMax 2 456 | ``` 457 | 458 | Paste this to /etc/pf.conf: 459 | 460 | ``` 461 | #! ##################################### !# 462 | #! ## pf.conf for NextCloud instances ## !# 463 | #! ## --- ## !# 464 | #! ## Last edit: 20200330 by admin ## !# 465 | #! ##################################### !# 466 | 467 | 468 | ##################################### 469 | ### MACRO AND TABLE SECTION ### 470 | ##################################### 471 | 472 | ext_if = "em0" # External interface 473 | int_if = "lo0" # Internal/loopback interface 474 | public_ip = "{" $ext_if "}" # Grabs the public IPv4 and IPv6 of this machine 475 | local_ip = $int_if:0 # Grabs the local/loopback IP 476 | 477 | in_tcp_services_restricted = "{ ssh }" # Allow SSH incoming - restrictive 478 | in_tcp_services = "{ http, https }" # Allow HTTP and HTTPS incoming 479 | out_tcp_services = "{ ssh, http, https, domain, ntp, 67 }" # Allow SSH, HTTP, HTTPS, DNS, NTP, and DHCP outgoing 480 | out_udp_services = "{ domain, ntp, 67 }" # Allow DNS, NTP, and DHCP outgoing 481 | lo_tcp_services = "{ postgresql, 9000, 6379}" # Loopback rule for PSQL and Redis 482 | 483 | icmp_types = "{ echoreq, unreach }" 484 | icmp6_types = "{ echoreq, routersol, routeradv, neighbradv, neighbrsol }" 485 | 486 | table persist # Table for SSH bruteforcers 487 | 488 | match in all scrub (no-df) 489 | 490 | ##################################### 491 | #### FIREWALL RULES ### 492 | ##################################### 493 | 494 | block log all 495 | 496 | antispoof log quick for $ext_if 497 | antispoof log for $int_if 498 | 499 | block in log quick from {no-route urpf-failed} to any 500 | 501 | block log quick from 502 | block log quick from 503 | 504 | pass in on $ext_if inet proto tcp from any to $public_ip port $in_tcp_services_restricted flags S/SA keep state (max-src-conn 8, max-src-conn-rate 4/30, overload flush global) 505 | #pass in on $ext_if inet6 proto tcp from any to $public_ip port $in_tcp_services_restricted flags S/SA keep state (max-src-conn 8, max-src-conn-rate 4/30, overload flush global) 506 | 507 | pass in on $ext_if inet proto tcp from any to $public_ip port $in_tcp_services keep state 508 | #pass in on $ext_if inet6 proto tcp from any to $public_ip port $in_tcp_services keep state 509 | 510 | pass out on $ext_if inet proto tcp from $public_ip to any port $out_tcp_services keep state 511 | #pass out on $ext_if inet6 proto tcp from $public_ip to any port $out_tcp_services keep state 512 | pass out on $ext_if inet proto udp from $public_ip to any port $out_udp_services keep state 513 | #pass out on $ext_if inet6 proto udp from $public_ip to any port $out_udp_services keep state 514 | 515 | pass on $int_if inet proto tcp from $local_ip to $local_ip port $lo_tcp_services 516 | #pass on $int_if inet6 proto tcp from $local_ip to $local_ip port $lo_tcp_services 517 | 518 | 519 | pass on $ext_if inet proto icmp all icmp-type $icmp_types keep state 520 | #pass on $ext_if inet6 proto icmp6 all icmp6-type $icmp6_types keep state 521 | 522 | pass out on $ext_if inet proto udp from $public_ip to any port 33433 >< 33626 keep state 523 | #pass out on $ext_if inet6 proto udp from $public_ip to any port 33433 >< 33626 keep state 524 | ``` 525 | 526 | Turn PF off and back on again: 527 | 528 | ```console 529 | $ doas pfctl -d ; doas pfctl -e -f /etc/pf.conf 530 | pf disabled 531 | pf enabled 532 | ``` 533 | 534 | Reboot so you boot on a brand new up-to-date system with latest stable kernel: 535 | 536 | ```console 537 | $ doas reboot 538 | ``` 539 | 540 | Download/install prerequisites 541 | --- 542 | 543 | 1. Install PostgreSQL server: 544 | 545 | ```console 546 | $ doas pkg_add postgresql-server 547 | ``` 548 | 549 | 2. Install PHP and some modules. If you are asked which PHP-version to install, answer PHP 7.3 each time. 550 | 551 | ```console 552 | $ doas pkg_add php php-curl php-gd php-intl php-pdo_pgsql php-xml php-zip redis pecl73-redis 553 | ``` 554 | 555 | 3. Enable the PHP modules 556 | 557 | ```console 558 | $ doas cp /etc/php-7.3.sample/* /etc/php-7.3 559 | ``` 560 | 561 | 4. Automatically start these services. Do not start these services yet. 562 | 563 | ```console 564 | $ doas rcctl enable postgresql php73_fpm redis 565 | ``` 566 | 567 | 5. Install a file so the webserver can resolve DNS queries from inside its chroot and another file so NextCloud can verify HTTPS certificates: 568 | 569 | ```console 570 | $ doas mkdir -p /var/www/etc/ssl 571 | $ doas cp /etc/resolv.conf /var/www/etc/resolv.conf 572 | $ doas cp /etc/ssl/cert.pem /var/www/etc/ssl/cert.pem 573 | $ doas cp /etc/ssl/openssl.cnf /var/www/etc/ssl/openssl.cnf 574 | $ doas chown -R www:www /var/www/etc 575 | ``` 576 | 577 | Dynamic DNS 578 | --- 579 | 580 | 1. If you're setting up the box at home and you have a dynamic IP address I recommend getting a [dynamic DNS host](https://nsupdate.info). 581 | 582 | 2. Install ddclient 583 | 584 | ```console 585 | $ doas pkg_add ddclient 586 | ``` 587 | 588 | 3. Append dynamic DNS host's ddclient config to `/etc/ddclient/ddclient.conf` 589 | 590 | 4. Inital sync 591 | 592 | ```console 593 | $ doas ddclient 594 | ``` 595 | 596 | 5. Enable ddclient service 597 | 598 | ```console 599 | $ doas rcctl enable ddclient 600 | ``` 601 | 602 | 6. Apply correct ownership to `/var/db/client/ddclient.cache` 603 | 604 | ```console 605 | $ doas chown -R _ddclient:wheel /var/db/ddclient 606 | ``` 607 | 608 | Enable and configure httpd 609 | --- 610 | 611 | 1. Use this configuration as a starting point for your `/etc/httpd.conf`, replacing `` with the dynamic DNS hostname you just created: 612 | 613 | ``` 614 | server "" { 615 | listen on * port 80 616 | root "/nextcloud" 617 | location "/.well-known/acme-challenge/*" { 618 | root { "/acme" } 619 | request strip 2 620 | } 621 | } 622 | ``` 623 | 624 | Check whether the configuration is deemed valid with `doas httpd -n`. 625 | 626 | 2. Prepare acme-client for the SSL certificates, courtesy of Let’s Encrypt. Edit `/etc/acme-client`, replacing `` with your dynamic DNS hostname: 627 | 628 | ``` 629 | authority letsencrypt { 630 | api url "https://acme-v02.api.letsencrypt.org/directory" 631 | account key "/etc/acme/letsencrypt-privkey.pem" 632 | } 633 | authority letsencrypt-staging { 634 | api url "https://acme-staging.api.letsencrypt.org/directory" 635 | account key "/etc/acme/letsencrypt-staging-privkey.pem" 636 | } 637 | domain { 638 | domain key "/etc/ssl/private/.key" 639 | domain certificate "/etc/ssl/.crt" 640 | domain full chain certificate "/etc/ssl/.pem" 641 | sign with letsencrypt 642 | } 643 | ``` 644 | 645 | 3. Create the corresponding directories: 646 | 647 | ```console 648 | $ doas mkdir -p -m 700 /etc/acme 649 | $ doas mkdir -p -m 700 /etc/ssl/acme/private 650 | $ doas mkdir -p -m 755 /var/www/acme 651 | ``` 652 | 653 | 4. Time to fetch the certificates 654 | 655 | ```console 656 | $ doas rcctl enable httpd && doas rcctl restart httpd && doas acme-client -v 657 | ``` 658 | 659 | 5. If that went successful, grab the OCSP stapling file: 660 | 661 | ```console 662 | $ doas ocspcheck -N -o /etc/ssl/.ocsp.pem /etc/ssl/.pem 663 | ``` 664 | 665 | 6. Edit the crontab to automatically renew the certificates and stapling file. Append the following in the crontab (`doas crontab -e`): 666 | 667 | ``` 668 | 0 0 * * * acme-client && rcctl reload httpd 669 | 0 * * * * ocspcheck -N -o /etc/ssl/.ocsp.pem /etc/ssl/.pem && rcctl reload httpd 670 | ``` 671 | 672 | Configure httpd further 673 | --- 674 | 675 | 1. Edit /etc/httpd.conf with these values. _Do not restart httpd afterwards!_ 676 | 677 | ``` 678 | server "" { 679 | listen on * tls port 443 680 | hsts { 681 | preload 682 | subdomains 683 | } 684 | root "/nextcloud" 685 | directory index "index.php" 686 | tls { 687 | certificate "/etc/ssl/.pem" 688 | key "/etc/ssl/private/.key" 689 | ocsp "/etc/ssl/.ocsp.pem" 690 | ciphers "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA" 691 | dhe "auto" 692 | ecdhe "P-384" 693 | } 694 | connection max request body 537919488 695 | 696 | location "/.well-known/acme-challenge/*" { 697 | root { "/acme" } 698 | request strip 2 699 | } 700 | 701 | # First deny access to the specified files 702 | location "/db_structure.xml" { block } 703 | location "/.ht*" { block } 704 | location "/README" { block } 705 | location "/data*" { block } 706 | location "/config*" { block } 707 | location "/build*" { block } 708 | location "/tests*" { block } 709 | location "/config*" { block } 710 | location "/lib*" { block } 711 | location "/3rdparty*" { block } 712 | location "/templates*" { block } 713 | location "/data*" { block } 714 | location "/.ht*" { block } 715 | location "/.user*" { block } 716 | location "/autotest*" { block } 717 | location "/occ*" { block } 718 | location "/issue*" { block } 719 | location "/indie*" { block } 720 | location "/db_*" { block } 721 | location "/console*" { block } 722 | 723 | location "/*.php*" { 724 | fastcgi socket "/run/php-fpm.sock" 725 | } 726 | 727 | location "/.well-known/host-meta" { 728 | block return 301 "/public.php?service=host-meta" 729 | } 730 | location "/.well-known/host-meta.json" { 731 | block return 301 "/public.php?service=host-meta-json" 732 | } 733 | location "/.well-known/webfinger" { 734 | block return 301 "/public.php?service=webfinger" 735 | } 736 | location "/.well-known/carddav" { 737 | block return 301 "/remote.php/dav/" 738 | } 739 | location "/.well-known/caldav" { 740 | block return 301 "/remote.php/dav/" 741 | } 742 | } 743 | 744 | server "" { 745 | listen on * port 80 746 | block return 301 "https://$REQUEST_URI" 747 | } 748 | ``` 749 | 750 | PHP and PostgreSQL 751 | --- 752 | 753 | 1. Since this is the first time we’re using PostgreSQL on this machine, we’ll need to initialize the database. 754 | 755 | ```console 756 | $ doas su - _postgresql 757 | $ mkdir /var/postgresql/data 758 | $ initdb -D /var/postgresql/data -U postgres -A md5 -W 759 | ``` 760 | 761 | 2. Switch back to our regular user by typing `exit` and confirming with `whoami`. Now, let’s start the database by issuing a single command. 762 | 763 | ```console 764 | $ doas rcctl enable postgresql && doas rcctl start postgresql 765 | ``` 766 | 767 | PHP Configuration 768 | --- 769 | 770 | 1. Now we have to change the PHP configuration with some higher limits as the default only allows uploading of files that are two MB at max. Open `/etc/php-7.3.ini` and edit these values: 771 | 772 | ``` 773 | memory_limit = -1 774 | max_input_time = 180 775 | upload_max_filesize = 512M 776 | post_max_size = 32M 777 | opcache.enable=1 778 | opcache.enable_cli=1 779 | opcache.memory_consumption=128 780 | opcache.interned_strings_buffer=8 781 | opcache.max_accelerated_files=10000 782 | opcache.revalidate_freq=1 783 | opcache.save_comments = 1 784 | ``` 785 | 786 | Installing Nextcloud 787 | --- 788 | 789 | 1. We’ve come quite a long way. Fortunately, we’re almost there! Grab and verify the most current version of Nextcloud and extract it to `/var/www/nextcloud`: 790 | 791 | ```console 792 | $ ftp https://download.nextcloud.com/server/releases/nextcloud-18.0.4.zip 793 | $ ftp https://download.nextcloud.com/server/releases/nextcloud-18.0.4.zip.asc 794 | $ doas pkg_add gnupg unzip 795 | $ gpg2 --fetch-keys https://nextcloud.com/nextcloud.asc 796 | $ gpg2 --verify nextcloud-18.0.4.zip.asc 797 | gpg: assuming signed data in 'nextcloud-18.0.4.zip' 798 | gpg: Signature made Wed Apr 22 19:35:41 2020 UTC 799 | gpg: using RSA key D75899B9A724937A 800 | gpg: Good signature from "Nextcloud Security " [unknown] 801 | gpg: WARNING: This key is not certified with a trusted signature! 802 | gpg: There is no indication that the signature belongs to the owner. 803 | Primary key fingerprint: 2880 6A87 8AE4 23A2 8372 792E D758 99B9 A724 937A 804 | $ doas unzip -d /var/www nextcloud-18.0.4.zip 805 | $ doas chown -R www:www /var/www/nextcloud 806 | ``` 807 | 808 | 2. Before we can use Nextcloud, we need to create a database to store the data. Replace `secret-password` with a strong passphrase of your liking: 809 | 810 | ```console 811 | $ doas su - _postgresql 812 | $ psql -d template1 -U postgres 813 | template1=# CREATE USER nextcloud WITH PASSWORD 'secret-password'; 814 | template1=# CREATE DATABASE nextcloud; 815 | template1=# GRANT ALL PRIVILEGES ON DATABASE nextcloud to nextcloud; 816 | template1=# \q 817 | ``` 818 | 819 | 3. Check whether you are still running as the postgresql user with `whoami`. If so, just give it an exit to switch back to admin. Start the required services. We’ve set these services earlier to enabled, so with a restart, the services will also start on boot time: 820 | 821 | ```console 822 | doas reboot 823 | ``` 824 | 4. PHP must append the chroot path `/var/www` to any command. Create and edit `/var/www/nextcloud/config/custom.config.php` to look like this: 825 | 826 | ``` 827 | ((php_sapi_name() == 'cli') ? '/var/www' : '') . '/nextcloud/data', 830 | ); 831 | ``` 832 | 833 | 5. Fire up your browser and head to your subdomain. You should be greeted there with the installation wizard. 834 | 835 | 6. Fill out the fields 836 | 837 | ``` 838 | Username: Choose a username 839 | Password: Enter a strong password 840 | Datadirectory: `nextcloud/data` 841 | Database type: PostgreSQL 842 | Database user: nextcloud 843 | Database password: 'secret-password' from before 844 | Database name: nextcloud 845 | Database host: localhost 846 | ``` 847 | 848 | 7. After the installation, edit `/var/www/nextcloud/config/config.php` and add these lines before the closing `);`. 849 | 850 | ``` 851 | 'memcache.local' => '\OC\Memcache\Redis', 852 | 'memcache.locking' => '\OC\Memcache\Redis', 853 | 'redis' => array( 854 | 'host' => '127.0.0.1', 855 | 'port' => 6379, 856 | ), 857 | ``` 858 | 859 | 8. And last but not least, a cronjob for some regular housekeeping and indexing. By default, it runs one task with each pageload. The preferred way here is to set this via a cronjob under the `www` user (`doas -u www crontab -e`). 860 | 861 | ``` 862 | */5 * * * * php -f /var/www/nextcloud/cron.php 863 | ``` 864 | 865 | 9. Customize Nextcloud to your liking and definitely add 2FA for the admin account. 866 | 867 | Fix Warnings 868 | --- 869 | 870 | 1. If you see the warning `PHP does not seem to be setup properly to query system environment variables. The test with getenv("PATH") only returns an empty response. Please check the installation documentation ↗ for PHP configuration notes and the PHP configuration of your server, especially when using php-fpm.` 871 | 872 | Edit `/etc/php-fpm.conf` and uncomment these lines, by removing the `;` 873 | 874 | ``` 875 | ;env[HOSTNAME] = $HOSTNAME 876 | ;env[PATH] = /usr/local/bin:/usr/bin:/bin 877 | ;env[TMP] = /tmp 878 | ;env[TMPDIR] = /tmp 879 | ;env[TEMP] = /tmp 880 | ``` 881 | 882 | Restart services to apply changes 883 | 884 | ```console 885 | $ doas rcctl restart httpd redis php73_fpm postgresql 886 | ``` 887 | 888 | 2. If you see the warning `The database is missing some indexes. Due to the fact that adding indexes on big tables could take some time they were not added automatically. By running "occ db:add-missing-indices" those missing indexes could be added manually while the instance keeps running. Once the indexes are added queries to those tables are usually much faster.` 889 | 890 | Run this command 891 | 892 | ```console 893 | $ doas -u www php /var/www/nextcloud/occ db:add-missing-indices 894 | ``` 895 | 896 | Restart services to apply changes 897 | 898 | ```console 899 | $ doas rcctl restart httpd redis php73_fpm postgresql 900 | ``` 901 | 902 | 3. If you see the warning `This instance is missing some recommended PHP modules. For improved performance and better compatibility it is highly recommended to install them.` 903 | 904 | Run this command 905 | 906 | ```console 907 | $ doas pkg_add pecl73-imagick 908 | $ doas cp /etc/php-7.3.sample/imagick.ini /etc/php-7.3 909 | ``` 910 | 911 | Restart services to apply changes 912 | 913 | ```console 914 | $ doas rcctl restart httpd redis php73_fpm postgresql 915 | ``` 916 | 917 | 4. If you see the warning `Some columns in the database are missing a conversion to big int. Due to the fact that changing column types on big tables could take some time they were not changed automatically. By running 'occ db:convert-filecache-bigint' those pending changes could be applied manually. This operation needs to be made while the instance is offline. For further details read the documentation page about this. 918 | 919 | Run this command 920 | 921 | ```console 922 | $ doas -u www php /var/www/nextcloud/occ db:convert-filecache-bigint 923 | ``` 924 | 925 | Restart services to apply changes 926 | 927 | ```console 928 | $ doas rcctl restart httpd redis php73_fpm postgresql 929 | ``` 930 | 931 | Tests 932 | --- 933 | 934 | 1. Go to [scan.nextcloud.com](https://scan.nextcloud.com/) and enter your dynamic DNS hostname. 935 | 936 | 2. Go to [ssllabs.com/ssltest](https://www.ssllabs.com/ssltest/) and enter your dynamic DNS hostname. 937 | 938 | 3. Go to [hardenize.com](https://www.hardenize.com), enter your dynamic DNS hostname, and look at the "WWW" section. 939 | 940 | Backups 941 | --- 942 | 943 | 1. Database 944 | 945 | You might have to play around with permissions on /var/www/nextcloud and your mountpoint. 946 | 947 | GPG encrypted backup to USB drive 948 | 949 | ```console 950 | $ doas -u www /usr/local/bin/php /var/www/nextcloud/occ maintenance:mode --on 951 | $ PGPASSWORD="" pg_dump nextcloud -U nextcloud | gpg2 -e -r -o //nextcloud-sqlbkp_`date +"%Y%m%d"`.bak.gpg 952 | $ doas -u www /usr/local/bin/php /var/www/nextcloud/occ maintenance:mode --off 953 | ``` 954 | 955 | Unencrypted backup to USB drive 956 | ```console 957 | $ doas -u www /usr/local/bin/php /var/www/nextcloud/occ maintenance:mode --on 958 | $ PGPASSWORD="" pg_dump nextcloud -U nextcloud -f //nextcloud-sqlbkp_`date +"%Y%m%d"`.bak 959 | $ doas -u www /usr/local/bin/php /var/www/nextcloud/occ maintenance:mode --off 960 | ``` 961 | 962 | 2. Full server backup with duplicity 963 | 964 | Duplicity is an excellent backup software. It creates a full backup at first and then performs an incremental backup (i.e., only backing up any files that are new or changed since the last backup run), until the last full backup is older than one month. 965 | 966 | ```console 967 | $ doas pkg_add duplicity 968 | $ doas -u www /usr/local/bin/php /var/www/nextcloud/occ maintenance:mode --on 969 | $ duplicity --encrypt-key --exclude / --exclude /tmp --exclude /sys --exclude /dev / file:/// 970 | $ doas -u www /usr/local/bin/php /var/www/nextcloud/occ maintenance:mode --off 971 | ``` 972 | 973 | Resources 974 | --- 975 | 976 | * [drduh PC-Engines-APU-Router-Guide](https://github.com/drduh/PC-Engines-APU-Router-Guide) 977 | * [OpenBSD Full Disk Encryption](https://www.openbsd.org/faq/faq14.html#softraidFDE) 978 | * [h3artbl33d NextCloud on OpenBSD](https://www.h3artbl33d.nl/communication/2018/10/07/nextcloud-openbsd/) 979 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /images/Puffy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nixbitcoin/OpenBSD-Nextcloud/3c7ae9149d6f1aa166b7172d8e88baae26337359/images/Puffy.png --------------------------------------------------------------------------------