<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Bader Zaidan</title>
    <description>Laughing at your security since 2012.
</description>
    <link>https://zaidan.tech/</link>
    <atom:link href="https://zaidan.tech/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 23 Jan 2024 00:00:00 +0000</pubDate>
    <lastBuildDate>Tue, 23 Jan 2024 00:00:00 +0000</lastBuildDate>
    <generator>Jekyll v4.3.3</generator>
    
      <item>
        <title>A Quick and Not-So-Easy Nextcloud Setup</title>
        <description>&lt;p&gt;Nextcloud is pretty straight-forward to deploy, especially using &lt;a href=&quot;https://hub.docker.com/_/nextcloud&quot;&gt;their official docker image&lt;/a&gt;, but there are a few things that you might come across and would need to know that are spread all over their docs or forums. I wrote a relatively short guide on how you could deploy a working Nextcloud docker container.&lt;/p&gt;

&lt;p&gt;The goal in my case is to run a reasonably modular, upgradeable and usable container, proxied through the host server’s NGINX and with SSL/TLS via Let’s Encrypt.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;An up-to-date GNU/Linux distro,&lt;/li&gt;
  &lt;li&gt;NGINX,&lt;/li&gt;
  &lt;li&gt;Certbot,&lt;/li&gt;
  &lt;li&gt;Docker and docker-compose,&lt;/li&gt;
  &lt;li&gt;A few GiBs of disk space, and some more for your files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most convenient way to configure the container is via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose&lt;/code&gt;. You should ideally pass the passwords via docker secrets, for which you need to &lt;a href=&quot;https://docs.docker.com/get-started/swarm-deploy/&quot;&gt;run a swarm&lt;/a&gt;, or running a &lt;a href=&quot;https://www.vaultproject.io/&quot;&gt;HashiCorp vault&lt;/a&gt;, but that overcomplicates this tutorial and will be discussed in a future post. For now, we’ll pass them via environment files.&lt;/p&gt;

&lt;p&gt;To begin, create directory somewhere and add your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose.yaml&lt;/code&gt; file. It should look like the one below. (click to expand)&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;docker-compose.yaml&lt;/summary&gt;

  &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3&apos;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;nextcloud&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mariadb&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;--transaction-isolation=READ-COMMITTED --binlog-format=ROW&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${MYSQLDIR}:/var/lib/mysql&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;env_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;DB_ENV_FILE&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# CHANGE&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nextcloud&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PORT:80&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# CHANGE &apos;PORT&apos; to a proxy port number. e.g. 9999&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${WEBDIR}:/var/www/html&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${DATADIR}:/var/www/html/data&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;env_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;APP_ENV_FILE&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# CHANGE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/details&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;As stated above, the docker will access your passwords through environment variables, which are read from the files mentioned above under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;env_file&lt;/code&gt;. Here’s an example of what the files would look like.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;DB_ENV_FILE&lt;/summary&gt;
  &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DB_ROOT_PASS  &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DB_USER_PASS  &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nextcloud
&lt;span class=&quot;nv&quot;&gt;MYSQL_USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nextcloud  &lt;span class=&quot;c&quot;&gt;# Optionally change&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;MYSQLDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/mysql/dir  &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;TZ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Europe/Berlin  &lt;span class=&quot;c&quot;&gt;# Recommended, change for user&apos;s timezone&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
  &lt;summary&gt;APP_ENV_FILE&lt;/summary&gt;
  &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;MYSQL_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;db
&lt;span class=&quot;nv&quot;&gt;OVERWRITEHOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nextcloud.example.com &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;OVERWRITEPROTOCOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;https
&lt;span class=&quot;nv&quot;&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DB_USER_PASS &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nextcloud
&lt;span class=&quot;nv&quot;&gt;MYSQL_USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nextcloud  &lt;span class=&quot;c&quot;&gt;# Optionally change, see DB_ENV_FILE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;WEBDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/nextcloud/web/dir &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;DATADIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/nextcloud/data/dir &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;VIRTUAL_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nextcloud.example.com &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;TZ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Europe/Berlin &lt;span class=&quot;c&quot;&gt;# Timezone, Optional but Recommended&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;nginx&quot;&gt;NGINX&lt;/h3&gt;

&lt;p&gt;Nextcloud is proxied through NGINX, which requires a few config modifications. Most of it is directly copied from their documentation, but the headers are slightly modified, as I include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy_intercept_errors&lt;/code&gt; for custom error pages.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;nginx.conf&lt;/summary&gt;

  &lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nextcloud.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# CHANGE&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/var/log/nginx/nextcloud_access.log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Optionally change&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;auth_basic&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# CHANGE&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# PROXY_URL: typically 127.0.0.1&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# PORT:      see `docker-config.yaml` (e.g. 9999)&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://PROXY_URL:PORT/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Proxy headers&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$http_upgrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upgrade&lt;/span&gt;           &lt;span class=&quot;nv&quot;&gt;$http_upgrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Connection&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;upgrade&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Host&lt;/span&gt;              &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Real-IP&lt;/span&gt;         &lt;span class=&quot;nv&quot;&gt;$remote_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-For&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-Host&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-Port&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;$server_port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;## Proxy timeouts, buffering&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_connect_timeout&lt;/span&gt;              &lt;span class=&quot;s&quot;&gt;60s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_send_timeout&lt;/span&gt;                 &lt;span class=&quot;s&quot;&gt;60s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_read_timeout&lt;/span&gt;                 &lt;span class=&quot;s&quot;&gt;60s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_max_temp_file_size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_buffering&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_request_buffering&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;## OPTIONAL: Custom error pages&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_intercept_errors&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;## Headers&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Access-Control-Allow-Origin&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Access-Control-Allow-Headers&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Access-Control-Expose-Headers&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;content-range,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;content-length,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;accept-ranges&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Access-Control-Allow-Methods&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-XSS-Protection&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;mode=block&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=31536000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;includeSubdomains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;preload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;kn&quot;&gt;client_max_body_size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# You MAY need to make this bigger. Depends on use-case.&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;## Needed for CALDAV sync&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/.well-known/carddav&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;/remote.php/dav&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/.well-known/caldav&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;/remote.php/dav&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;## OPTIONAL. See &quot;Custom error pages&quot;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;error_page&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;501&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;502&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;503&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;504&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/errorpage.html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/errorpage.html&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/some/location/here&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# CHANGE&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/details&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;What’s next? Your Letsencrypt certificate. Not much to explain here:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;certbot &lt;span class=&quot;nt&quot;&gt;--nginx&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; nextcloud.example.com  &lt;span class=&quot;c&quot;&gt;# CHANGE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and ensure your NGINX ssl config is using &lt;a href=&quot;https://ssl-config.mozilla.org/&quot;&gt;the recommended (or better) configuration&lt;/a&gt;. Certbot should have added a cron job to automatically renew the certificate.&lt;/p&gt;

&lt;h3 id=&quot;logging&quot;&gt;Logging&lt;/h3&gt;

&lt;p&gt;You should &lt;a href=&quot;https://help.nextcloud.com/t/nextcloud-log-how-to-enable-compression-after-rotation/114525/2&quot;&gt;enable logrotate&lt;/a&gt; for your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;access_log&lt;/code&gt; file, as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/www/html/data/nextcloud.log&lt;/code&gt;. Keep in mind, Nextcloud has &lt;a href=&quot;https://docs.nextcloud.com/server/17/admin_manual/configuration_server/config_sample_php_parameters.html#logging&quot;&gt;built-in log size limiting&lt;/a&gt;, which you can set as follows in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/www/html/config/config.php&lt;/code&gt;. &lt;em&gt;Note: this will overwrite the log file, and not ‘rotate’ in the traditional sense.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 10 MiB limit&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;&apos;log_rotate_size&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;caching&quot;&gt;Caching&lt;/h2&gt;
&lt;p&gt;This could significantly improve performance. I will cover this at a later date, so &lt;a href=&quot;https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/caching_configuration.html&quot;&gt;refer to the documentation for now.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;useful-commands&quot;&gt;Useful Commands&lt;/h2&gt;

&lt;details&gt;

  &lt;summary&gt;Click to expand&lt;/summary&gt;

  &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;## Create and run your container from docker-compose.yaml&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;## You can also update this way&lt;/span&gt;
docker-compose pull
docker-compose up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## Update docker app&lt;/span&gt;
docker-compose &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;app bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apt-get update &amp;amp;&amp;amp; apt-get -y upgrade&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## Install imagemagick, required for SVG support&lt;/span&gt;
docker-compose &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;app bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apt-get install -y imagemagick&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## Run an occ command. Remember this for later!&lt;/span&gt;
docker-compose &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--user&lt;/span&gt; www-data app php occ &amp;lt;&lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;common-issues&quot;&gt;Common Issues&lt;/h2&gt;

&lt;h4 id=&quot;failing-regular-cron-jobs&quot;&gt;Failing Regular cron jobs&lt;/h4&gt;

&lt;p&gt;You can replace the built in AJAX/Webcron with a either a host cron job or systemd timer service. For cron, append a docker user crontab via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crontab -e&lt;/code&gt; to:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-crontab&quot;&gt;## run every 5 minutes
*/5 * * * * docker exec --user www-data nextcloud_app_1  php -f cron.php
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or if you prefer systemd timers, add the following files to a systemd service path:&lt;/p&gt;
&lt;details&gt;

  &lt;summary&gt;nextcloudcron.service&lt;/summary&gt;
  &lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[Unit]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Nextcloud cron&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Requires&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker.service&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[Service]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# CHANGE, user that can run docker commands on server.
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DOCKER_PRIVILEGED_USER&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ExecStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/usr/bin/docker exec --user www-data nextcloud_app_1  php -f cron.php&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;KillMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;process&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;

  &lt;summary&gt;nextcloudcron.timer&lt;/summary&gt;

  &lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[Unit]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Run Nextcloud cron every 5 minutes&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[Timer]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;OnBootSec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;5min&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;OnUnitActiveSec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;5min&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;nextcloudcron.service&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[Install]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;WantedBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;timers.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;and enable the service as follows in your shell:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# either with sudo or as root&lt;/span&gt;
systemctl daemon-reload
systemctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;nextcloudcron.service
systemctl &lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--now&lt;/span&gt; nextcloudcron.timer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Be sure to replace in settings under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nextcloud.example.com/settings/admin&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;current-issues&quot;&gt;Current Issues&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Nextcloud updates sometimes need a few days before they are available via docker, since &lt;a href=&quot;https://github.com/nextcloud/docker/issues/1735&quot;&gt;the workflow they use is very strange&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nextcloud.com/encryption/&quot;&gt;Standard server-side encryption&lt;/a&gt; has to be manually enabled, and it does not encrypt file names or folder structures, only the file data itself.
    &lt;ul&gt;
      &lt;li&gt;Confirm that you have enabled it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;occ encryption:status&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;Once it is enabled, you have to &lt;a href=&quot;https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/encryption_configuration.html&quot;&gt;run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;occ encryption:encrypt-all&lt;/code&gt; to encrypt files uploaded&lt;/a&gt; before it it was enabled, as per docs:&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Encrypt all data files for all users. For performance reasons, when you enable encryption on a Nextcloud server only new and changed files are encrypted. This command gives you the option to encrypt all files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;The server-size encryption implementation is somewhat questionable:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://nextcloud.com/blog/encryption-in-nextcloud/&quot;&gt;Keys are stored on the server&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;If user keys are enabled, keys are encrypted with users’ passwords and the private keys are stored on the server. Given most Nextcloud users run apps which regularly contact the server, this increases the attack surface.&lt;/li&gt;
      &lt;li&gt;The docs recommend storing on 3rd party or external storage with eCryptFS or LUKS, which add complexity, cost and requires trust of any possible 3rd parties (which is the main reason people switch to Nextcloud.)&lt;/li&gt;
      &lt;li&gt;Some data is &lt;a href=&quot;https://docs.nextcloud.com/server/23/admin_manual/configuration_files/encryption_configuration.html#files-not-encrypted&quot;&gt;still unencrypted anyways&lt;/a&gt;, including calendar and tasks.&lt;/li&gt;
      &lt;li&gt;File size increases by ~35%.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;End-to-end encryption &lt;a href=&quot;https://nextcloud.com/endtoend/&quot;&gt;severely limits usability&lt;/a&gt;:
    &lt;ul&gt;
      &lt;li&gt;Many Nextcloud Apps do not support E2E.&lt;/li&gt;
      &lt;li&gt;It will be impossible to use certain features such as CalDAV sync, sharing, etc.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;common-issues-and-considerations&quot;&gt;Common Issues and Considerations&lt;/h2&gt;
&lt;p&gt;So far, the only issue I had (disregarding the delayed 23.0.4 update) was an inaccessible file due to transactional locking right after upgrading to version 24. You usually do not need to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;occ maintenance:repair&lt;/code&gt; since this is done automatically after an update, but feel free to try.&lt;/p&gt;

&lt;p&gt;If you are running redis, flushing might work as per &lt;a href=&quot;https://help.nextcloud.com/t/file-is-locked-how-to-unlock/1883/40?page=3&quot;&gt;this forum post&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Login&lt;/span&gt;
redis-cli &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /var/run/redis/redis.sock
&lt;span class=&quot;c&quot;&gt;# Log in to redis and flush&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; auth YOUR_REDIS_PASSWORD
&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; flushall
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you do not run redis, or the above doesn’t work, try to rescan first by running the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;occ&lt;/code&gt; commands:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;occ files:scan &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;
occ files:repair-tree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Some exceptions may be printed during or after the process. Reading through should confirm that locking is the issue. If not, then the suggestions below likely won’t help you.&lt;/p&gt;

&lt;p&gt;If the suggestions above don’t work, you might need to delete the lock entries in mariadb. Log in to mariadb via:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# CHANGE MYSQL_USER to your mysql database user&lt;/span&gt;
docker-compose &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;db mariadb &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; MYSQL_USER &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and run the following commands in its interpreter. The broken entries should have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.lock&lt;/code&gt; of -1. Keep in mind: This suggestion comes with no warranty. I am &lt;strong&gt;not&lt;/strong&gt; responsible if your kittens die or babies explode, so back up your files.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;Nuke from orbit&lt;/summary&gt;

  &lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- select your nextcloud database&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nextcloud&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- search &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oc_file_locks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oc_file_locks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Delete ALL broken file locks. These files may not be accessible anymore.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oc_file_locks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Alternatively, delete the files by ID one by one:&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oc_file_locks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KNOWN_ID_HERE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/details&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;The issue SHOULD be solved now, and the locked files can be deleted and/or reuploaded if you need to.&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hub.docker.com/_/nextcloud&quot;&gt;Docker Hub link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.thepolyglotdeveloper.com/2017/03/nginx-reverse-proxy-containerized-docker-applications/&quot;&gt;A blog post by Nic Raboy&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;anything-else&quot;&gt;Anything Else&lt;/h2&gt;
&lt;p&gt;I’ll write a guide on how to enable redis and either docker secrets or vaults post-installation.&lt;/p&gt;
</description>
        <pubDate>Sat, 30 Apr 2022 00:00:00 +0000</pubDate>
        <link>https://zaidan.tech/2022/04/30/quick-and-easy-nextcloud.html</link>
        <guid isPermaLink="true">https://zaidan.tech/2022/04/30/quick-and-easy-nextcloud.html</guid>
        
        
      </item>
    
      <item>
        <title>Javascript concurrency and linting</title>
        <description>&lt;h3 id=&quot;papaparse-promise-and-jshint&quot;&gt;Papaparse, Promise, and JSHint&lt;/h3&gt;

&lt;p&gt;Few people will have to deal with concurrency issues with JS. As of two days ago, I became one of those people.&lt;/p&gt;

&lt;p&gt;A project I am working on at work at the moment is a Geocharts implementation. To spare you the details, we have to fetch some data from a remote server, parse it (using Papaparse), and throw it into the Charts array.&lt;/p&gt;

&lt;p&gt;Work with Papaparse enough, you will learn that it won’t work well with asynchronous code by default, and you’ll figure out that getting async/await to work with it is a pain in the back-side. After a few hours of work, I was able to solve the issue with JS Promise with the help of our good friend &lt;a href=&quot;https://stackoverflow.com/questions/31375531/how-to-use-promises-with-papaparse&quot;&gt;Stack Overflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My solution looks like this:&lt;/p&gt;
&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[...]&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;Papa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// results is an array with an object for every URL.&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;google&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setOnLoadCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;drawMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You then continue, as you would, for your Geocharts code.&lt;/p&gt;

&lt;p&gt;In the process of working on this project, I’ve started using a linter for Javascript called JSHint integrated with VSCode. This will come in useful as you begin to define what you consider to be good and bad coding practices, since it will help you remain consistent with your code. What you define in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jshintrc&lt;/code&gt; is up to you, but a decent starter is the &lt;a href=&quot;https://github.com/jshint/jshint/blob/master/examples/.jshintrc&quot;&gt;default example&lt;/a&gt;. A few modifications I’ve done were:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;moz&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Allow Mozilla-specific syntax&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;esversion&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// ECMAScript version 6&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;lastsemic&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Require last semicolon in {} statements&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;eqnull&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// do not allow == null&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// true: Requires all functions run in ES5 Strict Mode &lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Happy hacking.&lt;/p&gt;
</description>
        <pubDate>Wed, 22 Apr 2020 00:00:00 +0000</pubDate>
        <link>https://zaidan.tech/2020/04/22/js-concurrency-lint.html</link>
        <guid isPermaLink="true">https://zaidan.tech/2020/04/22/js-concurrency-lint.html</guid>
        
        <category>js</category>
        
        
      </item>
    
  </channel>
</rss>
