<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[TrialAndSucceed]]></title><description><![CDATA[TrialAndSucceed]]></description><link>https://trialandsucceed.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>TrialAndSucceed</title><link>https://trialandsucceed.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 09 Sep 2026 11:11:51 GMT</lastBuildDate><atom:link href="https://trialandsucceed.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to make an encrypted backup to a Nextcloud instance on a daily basis]]></title><description><![CDATA[As I installed Fedora on my laptop, I was thinking about my current backup strategy and ways to improve it. Until that time, I had done an rsync-based copy to an external drive on a more or less weekl]]></description><link>https://trialandsucceed.hashnode.dev/how-to-make-an-encrypted-backup-to-a-nextcloud-instance-on-a-daily-basis</link><guid isPermaLink="true">https://trialandsucceed.hashnode.dev/how-to-make-an-encrypted-backup-to-a-nextcloud-instance-on-a-daily-basis</guid><category><![CDATA[Linux]]></category><category><![CDATA[Backup]]></category><category><![CDATA[Nextcloud]]></category><category><![CDATA[bash script]]></category><dc:creator><![CDATA[andreasgreiff]]></dc:creator><pubDate>Mon, 13 Jul 2026 18:23:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a11815a1a3cf7bffc0977fa/bb426402-ec12-4dfd-9fc3-1a56b25f5ecc.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As I installed Fedora on my laptop, I was thinking about my current backup strategy and ways to improve it. Until that time, I had done an rsync-based copy to an external drive on a more or less weekly basis . I could do it more often, but for me it was annoying to grab the drive, plug it into the system, and decrypt the drive. So I was thinking about changing my strategy to an encrypted cloud backup on a daily basis.</p>
<h2>Configure the Nextcloud instance and set it up on the local PC</h2>
<p>The cloud storage of my choice is a hosted Nextcloud instance . I am already using it for my smartphone backups and as storage for my Joplin and Obsidian.</p>
<p>At the very beginning , I logged into my instance with the user for whom I want to store the backup data. In the files section , I then created a new folder in which the data should be backed up, called "l_back".</p>
<p>The next step was, to install the Nextcloud client on my local machine:<br /><code>sudo dnf install nextcloud-client</code></p>
<p>In the next step, it is necessary to log into the Nextcloud instance. For this, the client opens the webpage of the instance where the user has to install their account. After the successful login , permission for the client is requested . After the acceptance of this, the local Nextcloud client is connected to the instance. The next part is to choose which folders should be synced. Important in this case is to choose the "l_back" folder.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a11815a1a3cf7bffc0977fa/4cefe2b6-eaf0-4efc-b14e-98f78dea9f12.png" alt="Nextcloud Client - Folders to sync" style="display:block;margin:0 auto" />

<h2>Prepare the encryption</h2>
<p>For the encryption of the data, I am using GnuPG as a tool . There are a few steps that need to be done before it can be used in the script. On a Fedora system, run the following script:<br /><code>sudo dnf install gnupg2</code></p>
<p>To view the currently available keys , run the following command:<br /><code>gpg --list-keys</code></p>
<p>To create a new key pair:<br /><code>gpg --gen-key</code></p>
<p>Now you are asked about your name and your email address . The email address is needed in the script to identify the key that should be used for the encryption. The newly generated key pair is now stored in: /home/USER/.gnupg/</p>
<h2>The Backup Script</h2>
<p>The heart of the backup process is the script that should do the work. I want to back up specific files and folders. They should be compressed into an archive. The archive should then be encrypted. At least the encrypted data should be written to a given location. In that location, a folder should be created for the current day. The complete script can be found here:</p>
<p><a href="https://gitlab.com/greiffa/trialandsucceed/-/blob/66b9e2fa2837b0631cdb3e0099117307a181a238/scripts/nextcloudBackup.sh">https://gitlab.com/greiffa/trialandsucceed/-/blob/66b9e2fa2837b0631cdb3e0099117307a181a238/scripts/nextcloudBackup.sh</a></p>
<p>Let's get through the script.</p>
<h3>The start of the script</h3>
<p>In the Configuration section, the current date is selected and stored in the format yyyy_mm_dd. There is also the path to the directory to be set in which the data should be copied. As you can see, the current date is directly connected to the path.</p>
<pre><code class="language-shell"># Configuration
CURRENT_DATE=$(date +%Y_%m_%d)
BACKUP_DEST="/home/andi/Nextcloud/l_back/$CURRENT_DATE"
</code></pre>
<p>The next part is the definition of the array, which contains the path to the files and folders that should be backed up.</p>
<pre><code class="language-shell"># Array of files/folders to backup
BACKUP_ITEMS=(
    "/etc/yum.repos.d" # system repositories
)
</code></pre>
<h3>The function backup_item</h3>
<p>The magic happens in the next part of the script, called "backup_item". At the beginning of the script, the given parameter $1 is stored in a local variable.</p>
<pre><code class="language-shell">local source_path="$1"
</code></pre>
<p>The next block of code checks if the source that should be backed up really exists. If not, the function ends, and a return code of 1 is given back.</p>
<pre><code class="language-shell"># Check if source exists
if [ ! -e "$source_path" ]; then
    echo "ERROR: Source path does not exist: $source_path"
    return 1
fi
</code></pre>
<p>If the source really exists, the basename of the object is extracted. This is used to create the target directory. This path is then created. If the creation fails, perhaps because of a permission failure, an error message is output, and the script returns with an error code of 1.</p>
<pre><code class="language-shell"># Get the basename of the item
local item_name=$(basename "$source_path")
    
# Create the destination directory for this backup object
local target_dir="${BACKUP_DEST}/" # ${item_name}/
mkdir -p "$target_dir"

if [ $? -ne 0 ]; then
    echo "ERROR: Failed to create directory: $target_dir"
    return 1
fi
</code></pre>
<p>The objects to save should be packed as zip containers and encrypted afterward. For this, a filename for an object has to be created. The filename starts with the current date, followed by an underscore, the name of the current object, and ends with .zip.enc. The complete path is built afterward from the target directory and the currently built filename.</p>
<pre><code class="language-shell"># Create the zip filename with current date
local zip_filename="${CURRENT_DATE}_${item_name}.zip.enc"
local zip_filepath="${target_dir}${zip_filename}"
echo "Backing up: $source_path"
echo "  -&gt; $zip_filepath"
</code></pre>
<p>The heart of the function builds the zipping of the source object followed by its encryption. The zip commands differ for a file from a directory. After that, there is an echo if there is a success or an error.</p>
<pre><code class="language-shell"># Use zip to compress the item and pipe it to GPG
if [ -d "$source_path" ]; then
    # For directories, zip recursively to stdout
    zip -r - "$source_path" | gpg --encrypt -r USER --output "$zip_filepath"
else
    # For files, zip to stdout
    zip - "$source_path" | gpg --encrypt -r USER --output "$zip_filepath"
fi   

if [ $? -eq 0 ]; then
    echo "  ✓ Backup completed successfully"
    return 0
else
    echo "  ✗ Backup failed"
    return 1
fi
</code></pre>
<p>The important line is this one (the directory one):</p>
<pre><code class="language-shell">zip -r - "$source_path" | gpg --encrypt -r USER --output "$zip_filepath"
</code></pre>
<p>At first, there is a zipping of the source object. The parameter -r is for the recursive packing of the whole content. The result is then piped to the gpg command. The -r defines the identity that should be used for the encryption. With --output, the destination file path is given to the function.</p>
<h3>The start part of the script</h3>
<p>As I will describe later, I am using the script on every startup of my PC and I don't want to perform the backup more than once a day. For this, I am checking at the start if the backup directory for the current date already exists , and if this is so, I end the script. If the path does not exist, it is created.</p>
<pre><code class="language-shell"># Exit if the main backup directory already exists
if [ -d "$BACKUP_DEST" ]; then
    echo "Backup destination already exists: $BACKUP_DEST"
    echo "Aborting backup."
    exit 1
fi

# Create main backup directory
mkdir -p "$BACKUP_DEST"
</code></pre>
<p>For statistics I create three variables.</p>
<pre><code class="language-shell"># Counter for statistics
total=0
success=0
failed=0
</code></pre>
<p>The next part is the iteration through the array of backup objects. In the loop, the backup_item function is called with the current object as a parameter. In the case of a failure or a success, the statistic variables are increased.</p>
<pre><code class="language-shell"># Iterate through all backup items
for item in "${BACKUP_ITEMS[@]}"; do
    total=$((total + 1))
    backup_item "$item"
    if [ $? -eq 0 ]; then
        success=$((success + 1))
    else
        failed=$((failed + 1))
    fi
done
</code></pre>
<p>In the end, the statistics are printed out, and there is a final result in the case that all backups are successful.</p>
<pre><code class="language-shell"># Summary
echo ""
echo "Backup Summary:"
echo "  Total items: $total"
echo "  Successful: $success"
echo "  Failed: $failed"

if [ $failed -eq 0 ]; then
    echo "All backups completed successfully!"
    exit 0
else
    echo "Some backups failed!"
    exit 1
fi
</code></pre>
<h2>Make the script run daily</h2>
<p>This point was a real pain for me until I got it running. At this point i had an understanding problem of how cron works. My goal is, that the script should run once a day, so i wanted to use the @daily option of cron. This does not run and i think it is because the cron does not save the undone work and start it afterwards. So i switched to @reboot and now the script works perfectly after each reboot.</p>
<p>Via the command crontab -e, i inserted an entry to my accounts contab:</p>
<pre><code class="language-shell">@reboot /home/USER/Documents/nextcloudBackup.sh
</code></pre>
<p>I checked the backed up data over a couple of restarts over the days and the backup works good for me now. I hope you like my doing and my script can help you by achieving your goals.</p>
]]></content:encoded></item></channel></rss>