A Practical How-To Guide for Hosting MariaDB in ContainerStation

Introduction

Having done a very small amount of experimentation, I have now succeeded in getting an instance of the latest stable release of MariaDB up and running in ContainerStation. In order to verify operations, this process has also involved the following:-

  • Creating a dedicated service user, backup, with restricted permissions for that role

  • Establishing a remote connection via PHPMyAdmin

  • Creating a test database and performing a test backup

  • Deleting a record from the test database and performing a test restore

  • Writing and testing a script to be used to automate database backups

  • Enrolling the script in the native QTS crontab for full automation

Subordinate to and following this initial post, you will find a series of ‘reply’ posts that will walk you through this process, step-by-step.

Before you read on, an important disclaimer: I am not an employee of QNAP or MariaDB, I’m not a professional DBA. I’m a moderately competent technologist who is comfortable working on a (Linux) command line, using SSH, and experimenting. I’m not an expert in any of the elements I’m about to discuss, but I have experimented sufficiently to get all this working. Please bear this in mind as you read through this guide – and please post a reply if you spot errors or improvement opportunities.

But before we get to the fun stuff, we need to ask and answer three critical questions. The first is: Given that QNAP already provide MariaDB as a native application running on QTS, why would we need or want to install it within ContainerStation? Surely that’s just an extra layer of overhead we don’t need?

This is a critical question and it’s important that we consider it and only proceed beyond this point if we have a legitimate reason for doing so. In a nutshell, the three most likely affirmative answers to this question are:-

  • If you know at installation time that you’re going to need to move your MariaDB instance to another hardware platform in the foreseeable future – because exporting a container, taking it somewhere else and then importing it is a lot easier than running multiple installs and potentially archiving and restoring a bunch of databases…

  • If you discover that an application you want to deploy on to MariaDB has a requirement for features not available in the QNAP/QTS native version of the App. (This was the case for me – I’ve started working with BookStack, which needs to use the utf8mb4 character set, one not available in the version of MariaDB currently supported by QNAP [10.5.8 at the time of writing]).

  • If your NAS is not running production or mission-critical functions and it would be safe to experiment – and if you’ve either got permission from the relevant manager, or you have the authority to self-approve the work. [Nothing we’re about to do is inherently dangerous, but better safe than sorry].

The second question we should ask is: What other options – apart from using ContainerStation, are there?

When I looked, I came up with two principle alternatives: run MariaDB on another host; or, instead of using ContainerStation, use VirtualizationStation. I don’t want to divert us from the main task, but I do think it important to respond to these two alternatives:-

  • I decided that I would prefer to continue hosting MariaDB on my QNAP NAS because of the data integrity protection it afforded me (RAID-6 volume; mine is powered through a very capable UPS) and because any “second” host, irrespective of what it might be, would bring with it more hardware to maintain, another OS and stack to maintain, plus, of course, a greater consumption of electricity.

  • I did take a look at VirtualizationStation and I’m very intrigued and will experiment further. On the plus side, VS would allow me to operate as if I had separate hardware without the overheads – and in particular it would simplify the backup/administration of MariaDB, allow for more effective vulnerability management and updates… On the minus side, I can mitigate the vulnerability issue in other ways… and VS consumes quite a bit more of the NAS resources than ContainerStation does.

Your use case will almost certainly be different – and possibly unique – so before spending hours of effort deploying the solution described here, make sure it’s the right one for you. In particular, think about the complexity of patching updates to code running in ContainerStation. Is your implementation high risk? If so, think about that carefully.

OK, if I haven’t discouraged you… away we go!

We really appreciate your detailed sharing! Our community definitely needs more helpful contributions like this.

I will also ask our internal team to test out the configuration based on your setup.

Once again, thank you wholeheartedly for your effort and contribution!

00a. Before We Get Started – Preparation and Warning

Let’s get the warning out of the way first:

Here be dragons.

A full implementation of this guide is going to require that you access your QNAP NAS via SSH [as well as the web admin interface], edit local infrastructure [specifically crontab, possibly local shares] as well as deploy and configure software to your NAS.

If you’re not entirely comfortable with all of these practices, please stop here*.*

I have tested all of the steps described in this guide… and they work for my personal setup. Just to be completely clear, the components I used to develop these notes include:-

  • A QNAP NAS – in my case I’m using one of my TVS-672XTs, running QTS 5.2.7.3256

  • A desktop workstation – in my case a home-build PC running Mint Linux 21.3

  • A copy of PHPMyAdmin 5.2.1 – in my case running on a Raspberry Pi (4B)
    [There is no reason why you could not substitute e.g. MySQL Workbench in place of PHPMyAdmin – basically you’re just going to need a client to create a test DB and populate it with a table and a couple of dummy records].

  • A non-“Admin” account on your QNAP NAS. You do have an account that you use for all your basic QNAP housekeeping, right? It’s not like you use the factory “Admin” account for everything… and are risking being locked out of your NAS if something unpredictably bad were to happen…? Just checking…

  • A static IP Address. We’re going to be assigning a dedicated (static) IP Address to our MariaDB container. This is because we don’t want to have to reconfigure our client machines in the event that a DHCP Lease expires and a different IP address gets assigned – and of course because we are going to want to access MariaDB from other hosts on our network, not just the QNAP NAS itself.

00b. Before We Get Started – A Data Gathering Requirement

Let’s ask an important question: given that the entire point of container-based technology is that a container image is self-contained, with everything it needs to execute a program; and given that as a result the boundary of containers is designed to not be crossed, exactly how are we going to back up our MariaDB data? So far I’ve found three possible answers to this question:-

  • You can stop the entire container and export it to a tar file – and then enrol the tar image in a conventional (e.g. HBS3) backup solution, or copy it to another location on a different NAS or external drive. This is perfectly reliable, but it means that all the databases you run are going to be inaccessible for the duration of the backup process – and the more you have and the larger their data sets, the longer that down-time will be.

  • You can perform mariadb-dump commands against your running database[s] (which takes less time and produces smaller files), then use “docker cp” command to copy the extract file[s] through the container boundary and on to your native QTS file system. This is just as reliable and potentially a tiny bit quicker, but some of the disk space saved in the per-Database “.sql” dump files may be lost because you’ll end up with two backup files (the extract inside the MariaDB container – and the extract outside the MariaDB container) unless you perform additional housekeeping.

  • Finally, you can – at the time that you create your container, but only then – establish a logical and permanently-open bridge between the container file system and the native QTS [NAS] file system. This allows you to perform similar mariadb-dump commands as used in the second option, but the output file can be written directly to the native QTS file system, without the need to create a local copy inside the container and then “docker cp” that file across the container boundary. In short, this is the technically simplest solution, but it does create permanently open “bridge” between the two file systems.

Obviously, I can’t make this decision for you. But if we want to take the third option – my personal choice – then we’re going to need to get information about the actual file system within an installed MariaDB container – so that we know a link-point for our file system ‘bridge’ and we’re going to need it before we create our MariaDB container! But in order to do that, we’re going to need to look “inside” the official MariaDB container – and I found two possible ways to achieve this, but only got one to work.

The non-working method [you’re welcome to experiment] is to use a script that implements the Docker API and use that to extract the image. Here’s a link to one I tried and failed to get working and which uses the Docker API to download a Docker image to your local file system, without the need to have docker installed. Perhaps you will have more success than me…

My solution involves a few more steps, but it’s simple and reliable: perform a pilot install of MariaDB from docker; explore the installed image to get the information we need; then un-install the image and perform a clean install, this time with the parameters we want to include at container creation time.

Honestly, by the time you’ve worked your way through the teething troubles of a 3rd party script solution, you might just as well perform a “pilot” deployment direct from Docker Hub. You do you.

Please note that once you have used ContainerStation to create your container, the only way to change to or from the third option is to delete and re-create that container. So please take a moment to make an informed decision…

The remainder of this guide will cover all three options, so please pay particular attention when they’re discussed.

01. Selecting the Correct MariaDB Containers

It probably won’t come as a surprise to learn that the MariaDB Team have one container image file for every supported version of their product. This gives us three important questions to answer before we can get started:

  • How do we know that the Docker image of MariaDB that we want to install is an official file and not a maliciously modified copy?

  • Is there a specific version of MariaDB that we actually need to install?

  • Once we’ve determined which version of MariaDB that we want, how do we tell ContainerStation which version we want, so that the correct one is actually deployed?

The first question is the easiest to answer: ContainerStation is hard-coded to pull all it’s Docker image files directly from “hub.docker.com”, the official Docker Repository. If you’re not prepared to trust ContainerStation to do that reliably, then I’m going to very respectfully suggest you stop reading here, since addressing that concern is beyond the scope of this guide.

The second question isn’t really one that I can really answer for you, because that answer will depend entirely on your use cases. However, I can share a couple of tips. As we’re about to see, those responsible for the MariaDB image files have created two images with special names, “mariadb-latest” and “mariadb-lts”, where “lts” represents “Long Term Support”. If you have a requirement to be on either the most recent stable release, or one with extended support, you should select from one of these two named images.

To check availability of specific (and official!) MariaDB images, first, open a tab in your browser and navigate to “https://hub.docker.com/”. If the URL just before this sentence is an active hyperlink, please do double-check your browser location bar and inspect the site certificate to confirm you are at the official Docker site. Once there, you’ll find two routes to the data we need.

The first is to look to the left gutter margin of the home page. In the section entitled “Trusted content”, you should see a link with the title, “Docker Official Images”. When I follow that link in November 2025, I’m taken to a “search results” page that starts with “1 – 30 of 178 available results” – and the MariaDB image is on the 6th row. Alternatively, we can simply use the web site search bar (in the horizontal top menu/navigation bar) and enter “MariaDB” as the search term.

You will find that there are in fact multiple different MariaDB packages (for example I see “mariadb”, “mariadb/maxscale”, etc.) offered at Docker Hub. We need to select the first, “mariadb”. It should be easy to spot as the seal in the logo is coloured brown instead of being a black outline and to the right of the name “mariadb” we should see a small blue-green rosette, and the label, “Docker Official Images”. At the time of writing, the first meta-data for this item (“Pulls”) shows it has been downloaded more than 1 billion times. This is the package we want.

Click on the name – the link will take you to a page with detailed information on all the different release versions of this “main” MariaDB image. Immediately below the page heading we should find two tabs: “Overview” and “Tags”.

If not selected by default, click on “Overview” and note a block of 60+ hyperlinks to “Supported tags and respective Dockerfile links”. If you look closely, then one of the entries in that table should always be “latest” and another should always be “lts” (for Long Term Support). Note that if you are looking for the “LTS” variant, there will likely be 3 or 4 versions on this page that have “lts” as part of their name. Only one file should be named “lts” without any additional text, so if you’re using “Ctrl-F” to find it, keep hitting “Next” until you get to the correct version. Depending on your requirements, select and click on one of the links on this page – it doesn’t have to be either “latest” or “lts” if your need is for a specific version of the software. The list is ordered such that the most recent/bleeding edge versions appear first, with chronologically older editions appear in reverse-date order. (As an aside, the “current” version supported by QNAP – 10.5.8 – has aged off the bottom of this list… Good that we have Docker as an option, then!)

At the time of writing, when I click on “latest”, my browser is redirected to a GitHub page, with a raw Docker configuration/manifest file for the image. You can then perform a text search on that page (Ctrl-F in a browser) using “version” as the search term. If all goes well, you should find your cursor highlighting text in a block headed with “# OCI annotations to image” – and in this block you’ll find a parameter with the something similar to this value:-

org.opencontainers.image.version=“12.0.2” \

From this, we can determine that “mariadb:latest” will install (currently) version 12.0.2 of the database. Let’s make a note of that – we can check later to ensure that this works as expected. Of course, if you need/want a different version, then you can pick from any of the explicit “version stamped” alternatives on the previous “Overview” page at DockerHub and use the validation step described above to confirm that the manifest in your selected package matches the version you require. I should probably also point that whilst there are other Docker repositories on the internet and whilst ContainerStation does allow you to import copies of containers you have downloaded and cached locally, at the outset one of the questions we said we would answer concerned how we would ensure that we download legitimate code and not malware.

This is the answer to that question: we’re using the ContainerStation import mechanism [which is “hard-coded” to DockerHub] and we’ve checked and ensured that we’re about to pull an Official MariaDB image from that repository.

The critical point to note is that the exact text of the “tags” listed on the previous page provides the element that we will need to supply to ContainerStation to tell it which version of MariaDB that we want to install. We’ll see how that works in a moment.

02. Install ContainerStation from the QNAP App Store

Access your QNAP NAS via the Web Admin interface. Once you have authenticated, locate the “App Center” application – this will most likely either be pinned to your desktop, or accessible from the “Main Menu”, which, in the case of QTS 5.2.7, appears as an icon on the top left of the Web Admin interface – it looks like 3 horizontal bars.

Once you have opened “AppCenter”, click on “Utilities” in the left gutter margin and then search for “Container Station” [by default all individual apps in each category will be sorted in alpha order].

Click the blue-on-white button to ‘Install’.

Simples.

It should take a few minutes to pull down and install the code [depending on your network speed]. Once the installation is complete, the activation button will switch from blue-on-white “Install” to white-on-blue “Open”.

03. ContainerStation First Launch and Data Volume Selection

Disclaimer – I can’t give you explicit instructions here, because the specific steps you take are going to be determined by the underlying configuration of the QNAP NAS on which you’re installing ContainerStation and the way that it has been configured in terms of Volumes, LUNs (Logical UNits), etc.

IMPORTANT: If you’re not sure about the configuration of your NAS, then before you proceed, go to “Control Panel” and look for an applet in the “System” grouping/cluster that is called “Storage & Snapshots”. In here, you should find an overview of the low-level configuration of your NAS that was specified when drives were first added and it was initially set up. In my case I have a single Volume, imaginatively titled, “DataVol1” which is a RAID6 array across 6 x WD Red 12Tb drives. If you check “Storage & Snapshots” and find anything other than a single volume listed, I’d strongly recommend you ask the person who configured your NAS where they might prefer that you store the “/Container” folder. You need to think about the likely data occupancy requirements, especially considering we’re going to be installing a database engine which could potentially be very demanding on storage. Make sure, before you go past this point, that you know where you should be installing “/Container”.

Launch ContainerStation by clicking on its icon. You should see a “Welcome” banner, beneath which you’ll see text:-

“Welcome to Container Station

Container Station will create a shared folder named “Container” in File Station to store all
images and containers by default.”

Beneath the above text, you should be given a combo [drop-down] box, pre-selected to the value “/Container” and below this there is a button, “Start”. Now – my NAS is set with a single Volume and this is what I see offered [because I have no alternative]. As noted above, if you have multiple volumes setup on your NAS, you will certainly see something different here. Apologies if that’s you – you’re going to have to work this bit out for yourself. Once you’ve identified and set the correct location for the Shared Folder, click “Start” and let the script run to completion.

I would just note that in my case, with the volume selected being the main data volume for the NAS, ContainerStation is being given the opportunity to grow in size as much as it needs. That may be a good thing, or it may be a risk, depending on the reliability of the code you choose to run in hosted containers and the possibility that it might consume vast amounts of disk space – for example by writing excessively long log files with no automated clean-up process. Please take a moment to consider your intended uses before deciding where to deploy the “/Container” share.

In my case, when I set up ContainerStation, I was asked if I agreed to allow usage data to be collected and set to QNAP. This is not a technical question I can answer for you. Please note, however, that if your QNAP is owned by your employer, the decision may not be yours to make.

OK, at this point, we have container stationed installed, configured, empty, but available. When launched, by default we should see a “home page” entitled “Overview”, with a breakdown of Containers, Applications, and NAS resources – CPU, Memory and the “Top 5 by CPU Utilization” containers. This should, at this point, all be nice and quiet.

04. Creating our MariaDB Container

At this point I’m going to assume that you will want to proceed directly with creating a MariaDB container… but you’re likely to have a couple of questions first.

  • Wait – why would we need to create a Container? Surely the whole point here is that we’re going to be running a pre-built instance of MariaDB?

    Good question. I’m not an expert in the intricacies of Docker, but my basic understanding is that we create a local (empty) container and then populate it with an Official MariaDB image that we download from the Official Docker hub.

  • Wait – I’ve read a report on {insert tech news web site of your choice} that suggests that up to 20% of public Docker libraries host images that are riddled with malware – things like Bitcoin miners. How do I know you’re not about to guide me in to installing a bunch of malware you just uploaded?

    Better question. It shows that you are approaching this with a security-based mindset. The answer is pretty straightforward – we’re going to tell ContainerStation the name of the image file we want to retrieve, but it will go to the default Docker repository directly, rather than ask us to identify the URL of the image. Through this mechanism, you should have good confidence that we are going to pull down a legitimate image.

In the top right of the ContainerStation window, you should see a combo-box style widget with white text on a blue background and the default label of “Explore”. Click the down arrow to expand the drop-down and then from the menu, you should find the first option is “Create Container”. Select that.

A pop-up window should appear, entitled “Create Container”, with tab 1 of 3 marked as “Select Image”. In the main panel of the first tab are 3 controls – a pair of radio buttons to select between Basic and Advanced Modes, a combo-box labelled “Registry” and a text box named “Image”.

First, change the Mode to Advanced. We’re going to need to use the Advanced settings to pass run-time parameters to MariaDB when it spins up. As you make the change, you’ll see the “Registry” combo box replaced by two more radio buttons, “Docker image” and “LXD image”. Leave this set to “Docker image” (because we’re going to be deploying a Docker-format file). Notice that the grey text inside the “Image” box reads, ‘registry/image:version’ – and the “:version” bit is very important, as we’ll see.

The radio button “Docker image” basically instructs the script to use Docker Hub as the source for its image file and the “Image” text box is the parameter we need to provide to tell the installer script which package and which version of that package we want to install.

This is where we supply the name of the relevant image file that we identified when we searched Docker Hub. For example, in my case the value provided for the “Image” field was mariadb:latest”.

However, if you were running an application that needed a specific release version, this is where you would specify the edition that you wanted. For example, at the time of writing, the web application NextCloud is supporting release 31.0.10 and it’s internal infrastructure validation checks advise that it performs best on “MariaDFB >=10.6 and<= 11.4”. So if I wanted to host NextCloud, I would use the value, “mariadb:11.4” or perhaps “mariaDB:11.4.9”.

Once you have specified your required version, click “Next” [in the bottom right of the window]. That should result in the installer briefly displaying a pop-up banner of “retrieving information” – it is validating the details we just provided, by searching for that image at DockerHub.

You should now see that your window has moved from “1. Select Image” to “2. Configure Container” and that we have a bunch of new boxes that we need to complete.

The first of these is “Name”. This is the human-readable name that we’re going to give to this container, running in the new, local “ContainerStation” environment that we just installed. We need to be a bit thoughtful about this name – calling it “Xb17-123f” isn’t likely going to be much help. If this is your first container but you are likely to have multiple, then I suggest that you consider establishing a naming convention. Here are a few elements that you might want to include in a structured naming format:-

  • Container Content – if you’re going to be running multiple different software stacks – MariaDB, OpenLDAP, Jupyter, Plex, RStudio and so on, then you’re going to want to include “MariaDB” or similar in the name.

  • Container Purpose – is this a [D]evelopment container for programmers, a [T]est container for pre-production validation and user testing, a [P]roduction environment, or perhaps even a [C]ontingency or [B]ackup instance for use in emergencies? A single-character label makes it easy to see which, at a glance.

  • Content Version – if, like me, you’re following this guide to get access to a more recent version of MariaDB than comes bundled with QTS, then you might want to adjust the name to MariaDB_P12-0-2 or similar.

  • You might deploy dedicated containers for specific applications – so you might have a MariaDB container dedicated to supporting a single application, in which case the name of the App will feature, such as MariaDB_NextCloud or MDB_NC.

  • Finally, please bear in mind that whatever name you choose, you will have to type this exact string in to “docker” commands at a shell prompt, to tell Docker which of its containers you want your instructions to apply to. So don’t make it too complex, as you’ll be typing this quite a few times.

As the saying goes, “You do You”, but, please, take a moment to think this through.

Next up is the “Restart Policy” – which includes the options ‘None’, ‘Always’, ‘On Failure’ and ‘Unless Stopped’. The default here is ‘Unless Stopped’ and the meaning of the options should be pretty self-explanatory. I chose to leave this with the default. Here’s a link to the official Docker documentation if you’d like to explore further.

Next we get to “Network Configuration” – and this is an important setting which might easily cause confusion, so I think it is worth digging in to a little bit here. On the screen, there is a high chance that the field, “Exposed” ports has been pre-set to “3306/tcp” and greyed out, even though, further down the page, there is an option to specify a “Container Port” that is also pre-set to the value 3306 [the default TCP port for MariaDB/MySQL].

Here’s the catch… If you change this value to a non-Standard port for MariaDB, you will be able to bring your container up and start it, but you almost certainly won’t be able to connect to your database over the network. This is because the actual MariaDB binaries use other configuration files – embedded within the container image – and may not respect what you set here. [Disclaimer – it didn’t for me!] Be wary of changing this value – and see further below for a way to check and determine which port your live MariaDB binary starts to listen on. As long as you’re assigning a dedicated IP Address to your container, running on the MariaDB default port of 3306 should not be a problem.

Don’t click “Next” just yet – there’s more to do…

05. Advanced Container Settings

Before we leave this page, we need to dig a bit deeper. Click on “Advanced Settings”, which you will find below the “Network Configuration”.

In this lowest level of detail, you should find a page broken down in to 7 vertically stacked tabs, named: Commands, Networks, Environments, Labels, Storage, Runtime and Resources.

Let’s now work through each of these in turn:-

Commands
Leave the “Command” and “Entrypoint” text boxes in their “default” settings, and make sure that the “Allocate interactive processes (-i) for the container” and “Allocate TTY prcoesses (-t) for the container” are both set to active. We are going to rely on these two parameters being set ‘on’ when we come to set up and manage the container once it’s running.

Networks - IMPORTANT
In my case I wanted to access this container via the default [10Gb] network port on my NAS… but if you have a model with multiple network ports and connections, this is where you can specify which of the network ports on your NAS that your Docker container should be visible to your network.

The “Preparation and Warning” notes at the beginning of this guide included a requirement for a static IP address, valid on the local network – and this is where that value will be used.

Change the ‘Network Mode’ radio button selector from “Default (NAT)” to “Custom”. Allow the drop-down Combo Box to remain in “bridge”, then scroll the window down to reveal a couple of additional parameters tucked away at the bottom.

One of these is a check-box with the label, ‘Use a static IP address’. Activate that check-box and the installation window will change to give a 3-row data box with ‘IP address’, ‘Subnet mask’ and ‘Gateway’ as labels for the 3 rows. You will hopefully find that the Subnet mask and Gateway are pre-populated and greyed out – this data is sourced from the main network configuration parameters of your NAS. You should also find out that some of the 4 digits of your IP address – specifically the network address portion are also pre-defined and greyed out. In my case I am using a Class B network with network address 172.16.0.0, so I have just 2 parameters to fill in. Update the values in the “IP address:” parameter to match the address you previously obtained.

Environments – CRITICAL
You can think of this element as for the specification of environment [run time] variables that the container is going to pass to MariaDB as/when MariaDB starts up. The values of these variables are essentially secure – as they are only visible here and inside the container itself, but they are critical.

That’s because you must provide a root password to the docker image of MariaDB as part of the initial configuration. To do this, click the “Add New Variable” button at the top right corner of the page in this tab. The name of the environment variable we have to create is “MARIADB_ROOT_PASSWORD” and the value we select should be something that conforms to conventional password rules. If you miss this step, your Container will not start. [OK, disclaimer. I just exaggerated when I said that you must provide a root password here. That’s not strictly true. One of the other support options is “allow no password”. I chose to write the instructions as I did above because I don’t want to encourage anyone to do anything that is insecure. The right action to take here is to use a generator to produce a secure password and use that. Please take a moment to reflect on the sensitivity of the data your DB will host and the environment in which your NAS operates. As I’ve noted before: “You do you”.

Labels
We’re going to leave the settings of this tab to their default values

Storage – IMPORTANT
In the section of this document with the title, “00b. Before We Get Started – A Data Gathering Requirement”, we considered the question of whether or not we want to create a permanent connection between the container’s internal file system and that of the NAS itself. This is where you get to decide which approach you will take.

If you’re currently performing a “pre-install” for “Option 3”…
– that is to say, deploying the MariaDB container so that you can jump in and have a look around, so that you know where to make a connection to your NAS file system, or if you’ve decided that you want to keep your MariaDB container completely isolated, you can skip Storage and leave it blank – simply jump down these notes to “Runtime” and continue.

If you’re currently performing the “second/full/final install” for “Option 3”…
– and/or you have otherwise determined the location of a folder within the MariaDB container that you wish to permanently “bridge” to the QTS file system, this is where you make that configuration. Please note: you can only make this decision at installation time – once “built” you cannot go back and edit this part of your container’s configuration. Whatever you decide here will be “final” for this particular container.

After selecting the “Storage” tab, click the “down arrow” to the right of the button labelled “Add Volume”. A pop-up window should appear below the button with three options in it – “Add Volume”, “Add Volume from Container” and “Bind Mount Host Path”. Select “Bind Mount Host Path” and note that a second “bind pair” appear in the main section of the window. This one will be differentiated with a small yellow “folder” icon – which signifies that it related to a folder native to QTS on the NAS. Click on the yellow folder icon and use the window which shows a path to actual, existing folders on the host NAS file system. Navigate through the file system until you select the remote endpoint that you want to be able to connect to from within your container. Ideally, you should make sure that the folder you select is part of an existing backup regimen – for example is enrolled within one of your existing HBS3 backups. Of course, you don’t need to have the QTS folder enrolled in an HBS3 backup before you add a MariaDB container, it’s just that if you want your exported .sql files to be archived, including the destination QTS folder in an HBS3 backup is the simplest way to do it.

Click in to the final data field, “Container:” and provide the path name to the location within the container on which we wish to mount the remote file system. (For users familiar with the soft-link operation of Linux, using the command “ln -s”, this is effectively the same thing). In our case, because our future selves were so helpful, we know that the internal folder we want to use is /var/backups. [Warning: if you’re reading this and preparing any version of MariaDB that is not 12.0.2, you really should be ignoring this hint and performing your own pre-install to check. Just saying].

Runtime
This tab controls the way that ContainerStation will spawn threads that execute the code in containers. Because ContainerStation is designed to operate three different types of container, this tab allows an administrator to help ContainerStation better understand how to interact with the executable code within. As we’re using a Docker image, we can let this remain with default values.

Resources
This tab allows you to decide whether you want to apply “upper limits” to the amount of hardware resource you are willing to allow this specific container to consume. It is likely to be very useful on larger NAS units and those with many users, because you probably don’t want one container to draw down all the available performance of the NAS. However, since this is going to be specific to your operating environment, there is no easy or obvious suggestion to make here. MariaDB recommend a minimum of 1Gb of RAM for basic operations. Stipulating CPU limits is going to be much harder, because different NAS models will have different CPUs installed.

If in doubt… either seek advice from an administrator, or try this as a rule-of-thumb… If you switch to “Limited” for any of the 3 options, the range of values will be pre-set based on your local hardware. Have a think about the range of users, workload and other applications running on the NAS in question and think about how much of the available performance you would be comfortable allocating to this one solitary container if it was “working hard”. In my case – a TVS-672XT used as a “home office” hub, I set limits at 25% of available resources across the board – and that has proven to be more than enough. Doing so gives me the confidence that even if my MariaDB container were to “go sideways” with a looping process, it will not kill my entire NAS – and, crucially, it will leave me with enough capacity/bandwidth to get in and figure out what is going wrong.

When you’re ready, click Finish.

In the background, ContainerStation will now download the “Mariadb:Latest” image from Docker Hub and then apply the various configuration parameters that we specified during the “create” process.

If we switch from the “Overview” tab of ContainerStation’s main display to “Containers” [via the left-side gutter margin], we should now see a single row in the main panel of the page, with a “Type” value of “Docker”, a “Name” value that matches the one provided earlier, and additional parameters – “Status”, “Application”, “Image”, “IP Address”, “Created On” and “Actions”.

At the bottom of the display we should also see a pair of tabs, “Logs” and “Status”.

If everything went [reasonably] well, then in the “Status” column of the table of containers, we should see a circular green icon and “Running”. Earlier in these notes, I mentioned that there was a way of checking to find out which TCP port our Docker instance of MariaDB was listening on – and this is it. Click on the “Logs” tabs and you should see a window with a black background and fairly small white text. Directly above the top right corner of this text window, you’ll see a small icon that looks like a square with an arrow pointing out of it towards the top, right corner. Click that arrow and the log window will expand to fill your browser. Unfortunately the content of this window isn’t rendered as HTML, so you can’t use “Ctrl-F” in your browser to search for the active port, but it should not be hard to find. In my case, the log contains the following:-

2025-11-06 7:59:15 0 [Note] Server socket created on IP: ‘0.0.0.0’, port: ‘3306’.
2025-11-06 7:59:15 0 [Note] Server socket created on IP: ‘::’, port: ‘3306’.

As I noted previously, when I tried to change the port via the Container setup options, I found that the value here remained stubbornly at port 3306. Eventually, I decided it wasn’t an issue since I was of course using a dedicated, static IP address and this was the only service the address would be likely to host. But I did say I would show you how to confirm the port that your MariaDB daemon is listening on and, well, this is it.

But: congratulations! You’ve just configured and installed MariaDB in Container station!

And it is currently absolutely useless!

Right now, all we’ve done is get the package downloaded and installed and got the main binary to successfully start executing. However, by default MariaDB won’t allow network connections and is supplied with just a single root/admin user. Now we need to perform a couple of very simple validation tests. The first is a simple network visibility test – just open a command prompt or shell prompt (from your workstation) and then issue the command,

ping {IP address}

where the {IP address} is the one that we applied to the container in the “Networks” tab of “Advanced Settings” and was based on the static IP address we obtained at the start of this guide. If we got our networking setup correct, we should see ICMP Echo packets returned to our workstation.

The second test, which is very helpful if you have the means to run it, is to perform an nmap scan. Nmap is a port scanning utility that can access a remote host and tell you whether or not the host is offering service for particular ports, such as TCP sockets. If your workstation is Windows based, you can download the nmap utility direct from the official Nmap web site . If your workstation is unix based, such as one based on GNU/Linux, you can almost certainly add the nmap utility direct from your local package manager.

Once you have the utility installed, simply check your container’s IP address. For example, I assigned the IP address 172.16.101.201 to my MariaDB container and when I run nmap against that IP address, this is returned:-

$ nmap 172.16.101.201
Starting Nmap 7.80 ( link to official nmap web site normally appears here ) at 2025-11-06 08:25 GMT
Nmap scan report for 172.16.101.201
Host is up (0.00012s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
3306/tcp open mysql
Nmap done: 1 IP address (1 host up) scanned in 0.08 seconds
$

In this case I have only one open/active port at the IP address, but it shows that TCP Port 3306 is open (which means that a listener is monitoring the network stack and will respond to packets with that port ID) and we can also see that the listener is “mysql” – which is what we want.

This gives us a good level of confidence that our MariaDB engine is at least installed and running.

06. Accessing Docker via SSH

As anyone familiar with MariaDB will know, it follows the principle of secure by design, which means that when it first activates, it has only a single, registered user and that it will not allow remote (i.e. network) access. Not only are we going to have to access it via the local host to get it correctly configured, we’re going to need to access it from within its Docker container.

Let’s go.

First, open a Secure Shell session to your NAS. You can use a variety of different ways to do this – for example both Windows (via a Command Prompt) and Linux (via a Terminal Session) allow you to just issue the command,

SSH {your NAS IP or DNS Name}

In the alternate, you can use a client application like PuTTY – a free SSH and telnet client available for Windows and Linux. You do you. Once you’re logged in and at the [NAS] shell prompt, enter the following command:-

docker ps

You should not need to prefix this with “sudo”, but that may depend upon the permissions of your non-Admin account that you’re using to access your NAS. In response to this command, you should see a two-line response with some basic details under column headings of “CONTAINER ID”, “IMAGE”, “COMMAND”, “CREATED”, “STATUS”, “PORTS” and “NAMES”.

The single line of detail under the headings relates to the container we just created. Make a note of the item under “NAMES” – this is the specific container name and we’re going to need this to interact with our MariaDB instance. It should match the name you gave when creating the container in the first place.

07. Access MariaDB’s File System to Locate an Endpoint for Folder Linking
If this is the first time that you have installed MariaDB and your purpose for doing so is to determine which folder node in the container’s file system can be used as a parameter in the Storage configuration described above, then obtaining the information you need is simplicity itself. First, we need to start an interactive bash (shell) session to jump inside the container. You’ll need to enter a Docker command via the active SSH session to your NAS. Since this methodology is a common way for you to interact with Docker, let’s take a moment to break down the command and understand what the various elements mean. Read through the explanation before you type it:-

sudo docker exec -it {yourContainerName} /bin/bash

In the above command string:-

sudo - tells the NAS QTS Operating System that we want to execute the following command with superuser privileges.

Docker - tells sudo that we want to invoke the docker command with privileges

exec - is shorthand for “Docker Execute” – it tells Docker that we want to invoke an executable program that can be found within the container

-it - are parameter flags and represent Interactive Mode (i) and Teletype Format (t), respectively.

{YourContainerName} - is needed in case we have multiple containers deployed within this instance of Docker. This is how we tell the Docker handler which container we want to work with.

/bin/bash - is the full path name to the executable program, inside the container, that we wish to launch. For those reading this who are not familiar with unix family operating systems, “bash” is shorthand for the “Bourne Again Shell”, an extension of one of the original command-line environments from the earliest days of unix (the Bourne Shell).

When you execute the above command, you will notice that the command prompt to your shell environment changes. It should transform to something like:-

root@{12-digit-hexadecimal-number}:/#

The odd-looking 12-character hex value is, of course, the unique Container ID that ContainerStation assigned during the creation process. Now we’re inside the MariaDB container. We need to figure out where we are in the container and what exists at that location. We’ll execute a list command and use parameters to ask for all files and longhand format (which is equivalent to asking Windows Explorer to give you the “Details” view of a folder). By convention, we will always arrive in the container at the topmost, “root” directory for it’s local file system (“/”). Execute the shell command:

ls -al

You should see roughly 24 entries in the root folder of the container, with the first 3 being “.”, “..” and “.dockerenv”, respectively. Now what we need to do is search through this file system for a location that we can use as a bridge point between the container and the NAS file system.

Scan down and find a folder named “var”. This name is written in unix 3-letter shorthand and represents “variable” and denotes that the contents of this folder is expected to be volatile over time. That’s perfect for our needs, as it is used to indicate data storage areas. Enter the folder with:

cd var

(to **change directory **to var) and then list again:

ls -al

At this point, you should see that the first folder listed is “backups”. Enter it using

cd backups

and then list again

ls -al

You should find that it is empty, which is what we want to see. This is perfect – it’s just what we’re looking for. We’re going to use this folder as the bridging point for the backups we’re going to be taking from our MariaDB databases. We don’t need to make any changes and in fact we need to exit the container shell by issuing the

exit

command. When you do this, we should see the command prompt change back to our QNAP default again. At this point, we can switch back to the browser session, go back to Container Station and, if necessary, click on the “Containers” menu option in the left gutter margin. We can then locate our “MariaDB” container – the one we just created. Clicking the gear wheel in the “Actions” column will produce a pop-up window, from which we can select either “Stop”, or if necessary “Force Stop”. Once the container has stopped, we can scroll to the bottom of the pop-up window and select “Remove” to delete the container. Once it has been removed, we can then go back and re-start the process, now that we have established where we want to bridge between the container’s file system and the QTS file system.

08. Access MariaDB’s Command Line Interpreter via Docker

Working on the basis that if you have reached this section, then you have a correctly-configured container, complete with any folder connections between the container and the QTS file system that you need. Now that we can “see” our Container, let’s access MariaDB within it. We’re going to do that with another Docker command, but as we did before, let’s break it down so that you understand what you’re doing and why. Remember, if you haven’t already done so, you must first “exit” the container to get back to the NAS QTS Operating System prompt before you execute this next step. The syntax of the command we’re going to use is:-

sudo docker exec -it {yourContainerName} mariadb -p{rootPassword}

This command breaks down as follows:-

docker exec - we want Docker to run an executable binary within a container

-it - we want to do this (i)nteractively and via a (t)eletype style interface

mariadb - we want Docker to run this specific binary within the container

-p{rootPassword} - we want to supply this password to the binary – and this is the same
password that we provided in the Environment variable earlier.

You’ll notice that we didn’t need to specify a UserID to the command – it will default to ‘root’, the main administration user.

Performing this command should grant access to the MariaDB CLI (Command Line Interpreter). I am not going to cover in detail what you should do in order to configure this fresh instance of MariaDB for use, in part because you will want to follow your own local configuration guides, in part because the specifics will depend entirely on what you want or need to use MariaDB for. The basics, however, should be pretty simple:-

  • Adopt the principle of least privilege – avoid the use of wildcards when granting permissions.

  • In particular, when allowing “network access”, don’t simply specify “%” [by itself] for “Host” (which would allow access from any host), instead use the wildcard in conjunction with your network address, to limit access to only your local address (or part of it). For example, my local IP network address is 172.16.0.0, with a mask of 255.255.0.0, so I would specify 172.16.%.% for my Host value. This will allow me to access MariaDB from my local network, but nowhere else.

  • The key thing you need to do is to create a non-root MariaDB account with the authority to access the database from your (PHPMyAdmin / MySQL Workbench) host and give that user account the permissions necessary to create new databases.

However, in addition to anything else you may do to set your new MariaDB instance, I strongly recommend that you set up a special, read-only account that you can use to perform backups of any database. If this is something you would like to do, then the following commands can deliver what is required. First, let’s create a user associated with the loopback IP address:-

CREATE USER ‘backup’@’127.0.0.1’ IDENTIFIED BY ‘{securepassword}’;

Next, let’s grant that user the permission needed to ‘SELECT’ any database:-

GRANT SELECT ON *.* TO ‘backup’@’127.0.0.1’;

This helps you to see and understand the ‘grant’ syntax for permissions. Here, ‘SELECT’ is the authority being given to the user and ‘ON *.*’ tells MariaDB to grant this permission for all local databases. It’s a special version of the grant – it won’t just give the access to all databases that exist when we issue the command, it will also automatically add the permission for all new databases created after this moment in time.

Now, ‘SELECT’ isn’t the only authority that we need to give a user to be used to run backups, so below I’ll list out the permissions I used. And to be clear, I didn’t magic this list out of thin air, I got it from the Official MariaDB documentation. Here’s the full list:-

SELECT, RELOAD, PROCESS, SHOW DATABASES,

LOCK TABLES, SHOW VIEW, EVENT, TRIGGER

By creating the ‘backup’ account with @’127.0.0.1’, you limit the use of the account to the server on which you are going to use crontab to run backup scripts. That’s just good, basic security. It means that even if someone happens to discover the password of the account, they can’t use it to (remotely) access and steal all your data.

Before we leave this section, a couple of other very useful command line statements to remember are:-

SELECT user,host FROM mysql.user;

and

SHOW GRANTS FOR ‘{user}’@’{context}’;

for example:

SHOW GRANTS FOR ‘backup’@’127.0.0.1’;

As the command’s syntax suggests, this will give you a dump of the permissions that have been assigned to the user in question – you can use this to confirm that your user has the authority needed to perform local backup activities.

Please Note: It’s so easy when you get to this part to “cheat” and issue a command such as

GRANT ALL PRIVILEGES TO *.* FOR ‘{yourUser}’@’%’;

[which gives you full authority to do anything from anywhere] but it’s worth remembering just how dangerous that is. The general rules should be: only grant authorities that are needed. Remove them the instant they are no longer required.

Now, having said that, it’s also a good idea to set up an interactive user that does have broad permissions on all content and which has the authority to access the server remotely. Not for general or permanent use, but to be kept under a “break glass” seal and pulled out in emergencies. If you decide to create such a user, then you can use it to validate the next part of this process.

09. Accessing MariaDB from PHPMyAdmin

Despite it’s somewhat dated interface, PHPMyAdmin is a remarkably powerful utility and more than capable of allowing remote management of MariaDB databases via a web interface. Thanks to it’s sophistication, there are multiple ways that details of a new MariaDB server can be added – for example it is possible to add details to the default “config.inc.php” file, or to add a second configuration file dedicated to an individual MariaDB Server.

In my case, I chose the quick-and-dirty solution and added the details for a second remote server to an existing configuration, like this (taken from my config.inc.php file) :-

$i = 0;
/**
* First server - MariaDB 5.5.68 on TVS-672XT
*/
$i++;
/* Authentication type */
$cfg[‘Servers’][$i][‘auth_type’] = ‘cookie’;
/* Server parameters */
$cfg[‘Servers’][$i][‘verbose’] = ‘TVS-672XT - MariaDB 10.5.8’;
$cfg[‘Servers’][$i][‘host’] = ‘172.16.101.2’;
$cfg[‘Servers’][$i][‘port’] = ‘3307’;
$cfg[‘Servers’][$i][‘compress’] = false;
$cfg[‘Servers’][$i][‘AllowNoPassword’] = false;

/**
* Second Server – MariaDB 12.0.2 via ContainerStation on TVS-672XT
*/
$i++;
/* Authentication type */
$cfg[‘Servers’][$i][‘auth_type’] = ‘cookie’;
/* Server parameters */
$cfg[‘Servers’][$i][‘verbose’] = ‘TVS-672XT - MariaDB 12.0.2’;
$cfg[‘Servers’][$i][‘host’] = ‘172.16.101.201’;
$cfg[‘Servers’][$i][‘port’] = ‘3306’;
$cfg[‘Servers’][$i][‘compress’] = false;
$cfg[‘Servers’][$i][‘AllowNoPassword’] = false;

As you can see from the selection of parameters and values, my setup requires me to authenticate with a supplied UserID and Password each time I open a session to PHPMyAdmin; then it keeps my session active via a browser cookie.

The eagle-eyed among you might notice that my “first server” is using Port 3307 and not 3306. That’s because at the time I installed MariaDB 10.5.8, I already had a copy of MariaDB 5.x running on the same NAS – and QTS automatically detected this and avoided a port conflict by incrementing from 3306 to 3307 for the second MariaDB daemon.

If you have an existing PHPMyAdmin instance up and running, then after saving your modified default configuration file (or adding a second file), simply execute your local equivalent of:-

sudo systemctl reload apache2

on your web host, to activate the new configuration and ensure that your PHPMyAdmin web application has updated its runtime configuration.

Open up your browser (or a new tab in your browser) and provide the URL of your PHPMyAdmin instance. If your ContainerStation image is the only remote server, you will be able to gain access simply by providing the user ID and Password you just recently created.

If you have added your ContainerStation instance as a second remote server, you should see a combo box in the login window, from which you can select which remote server you want to Administer. The descriptions that appear in the Combo Box will be taken from the value you provided with the “[‘verbose’]” environment variable in the “config.inc.php” script, as illustrated above.

By default, PHPMyAdmin will take you to a “Server Home Page” for your currently-selected server. In a gutter margin on the left of your screen you should see existing, created databases. Because this is a brand new instance of MariaDB, you should only have: “information_schema”, “mysql”, “performance_schema” and “sys” showing.

The important element to double-check here, however, is that on the right hand side of the page, in the element titled, “Database server”, you should find the attribute “Server version”.

The specific value I see from my deployed Docker image is

12.0.2-MariaDB-ubu2404 - mariadb.org binary distribution

For me, the critical element of this is “12.0.2” – because this confirms that the image is running the version of MariaDB that I want. However, note that the element “mariadb.org” also indicates the origin of the docker image. Perhaps not sufficient to guarantee that it is an authentic MariaDB image, but at every step of the way we have been careful to check authenticity.

10. Setting Up a Test Database

While we’re logged in to PHPMyAdmin (or MySQL Workbench, or whichever tool you’re using), we’re going to create a database and populate it with a table containing a couple of records.

Since I won’t know in advance which toolset you’re using, I won’t put detailed instructions here. Instead, I’ll just say that I chose to call my database, “demo”, my table “demotable” and in this I created two fields, “demokey”, which was an auto-incrementing primary key, and “demotext” which was a simple text field. You do you.

Next, we need to populate this table with some actual data. It’s important that we create at least two records. Seeing as we’ve created simple text fields, you should be able to just enter text such as

This is the first test record
This is the second test record

We’re going to use this table to test our backup process. It’s not a bad idea to use PHPMyAdmin’s “Browse” feature to view the records and make sure the text is clearly visible in each record.

Once you’ve confirmed that the records have been created (with PHPMyAdmin you can just use the “Browse” tab, which should be the left-most one once you’ve selected the table via the left gutter menu). If all is well, we can proceed to taking a backup of this database…

11. Backing Up a Containerized MariaDB Database

Return to your SSH session connected to your NAS. Once there, we can execute a variation on the following command, tailored to use the database, output folder and user names that we have set up:-

sudo docker exec -it {YourContainerName} mariadb-dump -h 127.0.0.1 -P3306
-u {yourBackupAccountName} -p{yourBackupAccountPassword}
–databases {yourDatabaseName}
–result-file /var/backups/{yourDatabaseName}.sql

Here’s a breakdown of the variables used in this command:-

-it - specifies that the command should be invoked interactively and via teletype

{yourContainerName} - is the name you specified at container creation

-h 127.0.0.1 - tells the mariadb-dump command to run is on the loopback host. More importantly, this aligns with the way that we set up our “backup” user. Do you remember how we created it as “backup@127.0.0.1”? Well, this is why…

-P3306 - identifies the TCP port being used by the MariaDB instance

-u {yourBackupAccountName}

- is the name of a MariaDB account that has been set up with rights to access the target database for backup purposes. Here, extending my example, you just need the user name, “backup”.

-p{yourAdminPassword}
This is the value that you set within the “IDENTIFIED BY ‘…’; parameter when you created that user account. IMPORTANT: In case you didn’t notice, you can leave a space between “-u” and the start of your UserID and that will be ignored, but if you leave a space between “-p” and your password, the space will be treated as part of the password and authentication will fail!

–databases {yourDatabaseName}
[Note that there is a double-hyphen before “databases”!] We’re only going to provide one database name for our test exercise (“demo”), and to be honest I recommend you always invoke the command that way. It’s easy enough to invoke it multiple times – and keeping the command simple reduces errors.

–result-file /var/backups/{yourDatabaseName}.sql

[Note that there is a double-hyphen before “result-file”!] In this parameter, the elements “/var/backups/” correspond to the folder structure that we explored and verified within MariaDB container (v12.0.2) and the name that we assign should be a meaningful representation of the database we’re archiving.

Adding the .sql suffix is not essential, but it’s a useful convention to help identify the file type from the name.

You will likely be asked to provide your account password in order to perform a sudo command on the NAS – which is standard practice for using admin functions on unix-type hosts. Once you provide it, if you’ve followed all the steps accurately, you should see your shell prompt returned without error. Usual rules apply – if you do get an error, go back and re-check extra carefully.

We need to go check that the backup ran as expected. Now, if you created the file system bridge as described in this guide, then you don’t need to re-enter the MariaDB container with:-

sudo docker exec -it {YourMariaDBContainerName} /bin/bash

because the file you just created should be visible at the destination folder you specified. If you chose not to create the bridge, re-enter the container as set out above and change to the nominal output directory with:-

cd /var/backups

and then list the contents of the folder:-

ls -al

If all went according to plan, you should see a file present, with a very recent timestamp, and the name {yourDatabaseName}.sql

If you did, congratulations! If not, go back carefully through the preceding steps and try again.

Finally, while you’re in the folder that contains your backup [either within the container or via the Secure Shell session to your NAS] execute the following command:-

cat {yourDatabaseName}.sql

This will return the contents of the file to your screen and you should see the contents of your “demo” database, complete with the table you created and the two rows of text. It’s important that you confirm those 2 records are present in this file. Because, of course, pretty soon now we’re going to delete one of them, then use this backup to restore our data…

11a. Exporting a Backup File through the Container Wall

If you have used the folder bridge method via the Storage parameter to allow your container to access the NAS file system, you’re ready to proceed and can skip ahead to the next step. However, if you didn’t create the connection, you’re going to need to copy your .sql backup file outside of your container in order to use it in a restore process.

The good news is that it’s really simple to do and requires just one command.

At the Secure Shell prompt of your NAS, enter your tailored version of the following command:

sudo docker cp {YourMariaDBContainerName}:var/backups/{yourDatabaseName}.sql /share/NFSv=4/Public/Backup/

There should be a single space between the “.sql” and the “/share/NFS”—or whatever the equivalent local path is for your QNAP NAS. Also, you should replace, “/Public/Backup” with the relevant share and folder name to identify where you would like the file to be placed.

What this command does—manually—is create a copy of your export/dump file and place the copy on a part of your NAS file system that is visible to yourself and therefore HBS3 backup.

Please Note: It also means that you now have three copies of your database—the original and two dump files. This won’t be an issue for small databases, but may become more irksome if you manage really large data structures.

What we have now achieved by this point is to complete two of the three stages of the backup process that we’re going to need for adequate backup results. The final stage, of course, would be to subscribe the destination folder (“/Public/Backup”) into a formal data management process, such as the native QTS Utility HBS3.

Also – if your database files are large and if you are using the “file copy” process to place your .sql exports outside of your MariaDB container, then you should consider an additional couple of steps. After your final/ultimate backup job has run, you should configure another job to remove the intermediate copy of the .sql file you placed in /var/backups within the MariaDB container. If you’re using HBS3 as your backup mechanism, that utility does not have the ability to either perform additional commands, or to trigger external batch jobs.

The approach I came up with was simply to set HBS3 to run on a timer and then to have a regular shell script executed by crontab at a time well after the HBS3 job would finish. Note that this isn’t entirely safe – because the “tidy up” script will run even if the HBS3 job fails…

12. Validating a MariaDB Restore

We’ve just successfully created a full backup of our “demo” MariaDB database. If the output was written to a location within the MariaDB container, we’ve then also used a second command to extract the backup from within the MariaDB container and plac it in a location where we can protect it with a more robust backup mechanism.

But does that backup actually work?!

Let’s find out.

First, using your browser, return to your PHPMyAdmin session [you may need to re-authenticate if it has timed out] and access the demo table in Browse model. See that our two dummy records are present.

It doesn’t matter which record you choose at this point, but delete one of them. This is trivial to do from PHPMyAdmin – just click the “Delete” text on the row of the record you want to remove. You’ll be presented with a “Confirm” pop-up window and then a confirmation that the record has been deleted followed by a refresh of the page showing just one record remains.

Next, go back to the “database” page for our demo database, by clicking on the database name (“demo”) as it appears in PHPMyAdmin’s left-hand gutter margin. The main window should change to show us our “demotable” and the status field “Rows” should confirm a single record remains.

Above the main part of the window are a series of command tabs, starting with “Structure” and “SQL”. Select the tab named “Import”. The first portion of the “Import” window is “File to import:”. Click the word “Browse” next to the text box that contains the starting value “No file selected” and navigate through your file system to the location where you have either just written our copied your .sql file. Make sure you have the right file and select it.

You should not need to change any of the default parameters for the import, so simply scroll to the bottom of this page and click the “Import” button. Hold your breath, cross your fingers, etc. You do you.

When the import finishes, go back to the top menu and select the “Browse” tab again. Roughly in the middle of the screen you should see both records in your table, with whichever record you just deleted safely restored via your import process.

Congratulations!

You have now successfully completed – manually – a process to perform a backup from a Container MariaDB Server to your local file system. If you ever need to perform a restore from one of your regular backups, “in anger” – because you really need to recover some data – this is the process to use.

We’re very nearly there!!!

13. Automating the Backup Process

As helpful as these manual steps are, they can get a bit tedious if you have to perform them by hand each time you want a backup, so let’s automate this with the help of the cron utility provided by our QNAP NAS and the QTS Operating System. (For the non-Unix readers, “cron” is another abbreviation – this time from “chronological”, to indicate this is a time-based control.

First, we’re going to write a shell script to perform the backup steps for us. We’re going to place this script in a folder location that is visible to us as administrators of the NAS, but is protected from regular users. This can be done via a dedicated “Admin Share”, or using a Public share and then using folder permissions to restrict access to a script folder. And of course, the location we’re going to choose should also be enrolled in an HBS3 backup too…

The file needs to contain instructions equivalent to the following example – which you can customize for your needs:-

#!/bin/bash
#

docker exec -it {YourContainerName} mariadb-dump -h 127.0.0.1 -P3306
-u {yourBackupAccountName} -p{yourBackupAccountPassword}
-databases {yourDatabaseName}
-result-file /var/backups/{yourDatabaseName}.sql

If you have created the folder “bridge” from your MariaDB container to your NAS file system, you do not need the following line:

docker cp {YourContainerName}:var/backups/{yourDatabaseName}.sql /share/NFSv=4/Public/Backup/

Instead, you should alter the parameter “-result-file” to the nominated destination directory in the “Public” share of your NAS.

The second command, “docker cp”, means “Docker Copy” and does exactly as the name suggests and automates the copying of the backup placed inside the container to a location outside the container from where it can be enrolled in regular backups.

Pay particular attention to the fact that the hyphenated prefixes for “—datsbases” and “—result-file” are *double-*hyphens, not single hyphens … Also note that you do not need to include the “sudo” prefixes in the script version of these commands - cron will execute the script with root permissions for you.

For the sake of this worked example, we’ll work on the basis that the above script is stored thus:-

/share/NFSv=4/Public/Software/QNAP/scripts/DockerMariaDBbackup.sh

Navigate to the folder containing your script and execute the command:-

ls -al

Check the permissions for the script, which should be something like -rwxrwxr-x

It doesn’t matter too much what these permissions are, as long as the character “x” appears in each of the three triplets, to indicate that the file is eXecutable by the owner, the owner’s group and other users.

Test that the script file will run as expected by entering the following from your NAS SSH session:

sudo /share/NFSv=4/Public/Software/QNAP/scripts/DockerMariaDBbackup.sh

substituting in the folder location and script name that you used for your version of the file.

Because we’re running this script with root permissions [prefixing the command with “sudo”] you should be prompted for your password. Enter that and the script should run to success. Use your workstation File Manager to go to the “/Backup/” folder location and check the datestamp of the file you just created to confirm it was written successfully.

Now the only thing that remains is to automate the scheduling of the backup job.

First, let’s navigate to the QNAP Reference Documentation, here and thoroughly read their instructions on how to edit crontab. As you can see from those instructions, you must not try the “conventional” approach via “crontab -e”, but you must instead edit the relevant file by hand.

Next, open a fresh browser tab and navigate to https://crontab.guru/, which is an exceedingly handy utility page that will help you craft a “crontab string” that will invoke your backup job on the days and at the times you want it to run.

Once you have the syntax to schedule your cron job from the guru page – and as clearly explained in the above link QNAP reference documentation, edit your QNAP crontab settings by adding the string in question in to the designated file.

To give you an idea of what this should look like… I run my backups at 01:45 every morning, and the crontab entry for that looks like this:

45 1 * * * /share/NFSv=4/Public/Software/QNAP/scripts/DockerMariaDBbackup.sh 2>/dev/null

It may not be obvious, but the part of the command that says, “2>/dev/null” is basically instructing cron that if the script generates any errors, these should simply be dropped. Why would I do that? Because the script is simple and I’ve thoroughly tested my copy - and because I validate the output at least weekly. Also, something to note about this entry in the crontab file… Each time QTS is updated, the change will typically re-order the sequence with which entries appear in the crontab file. I’m not saying it’s purely random, but I’ll admit that if there’s a rhyme or reason to that, I haven’t figured it out yet. Don’t be concerned if you check back at a later time and the file you added is not the last line in the crontab list – just scan the list and it will be there.

14. Take a Round of Applause

I mean, seriously. Not for successfully setting up MariaDB in ContainerStation, configuring and testing backups and then setting up an automated backup schedule. I mean, congratulations for having the stamina to read all the way to the bottom of this guide!

I’m impressed!

Just two tiny requests from me, before you go. First, if you see anything that can be improved, clarified, simplified or corrected, please leave a comment to that effect – or message me directly.

Second, if this has helped you, please consider “paying it forward”. If you figure something out – with your QNAP NAS or MariaDB or anything else, find your way to the relevant forum and write about it. You’re not just helping yourself, you’re helping us all.

Thank you.

1 Like