Run MEGAcmd CLI in a Docker container
I've been looking into cloud storage for a small scheduled backup. MEGA caught my eye since it has end-to-end encryption, a generous 20GB to 30GB free tier, and no bandwidth charges or limits; though, I'm sure there's some throttling involved. It also has a command-line interface called MEGAcmd for scripting (also known as MEGA CMD).
MEGA isn't perfect, as seen on Rclone's overview table, its APIs lack a lot of features. But it's well-known and well reviewed so I'm willing to give it a go.
For this backup, I didn't use Restic and Rclone as their integration uses a reverse engineered library which doesn't support a bunch of basic features which Rclone relies on. So if the official MEGAcmd CLI is good enough, I can avoid introducing additional software and compatibility issues into the chain.
One of the downsides of MEGAcmd is that it's not distributed as a standalone CLI on Linux. It needs to be installed with a package manager and relies on a server running in the background. For scheduled backups, I'd rather not have that server always running and hogging resources. I'd also rather not install third-party packages. The solution? Containers.
Existing solutions
MEGAcmd does not distribute official container images, but they do provide Dockerfiles in their code repository which build from source. However, they seem to be strictly for building MEGAcmd, not running it in a container.
There are many other attempts at containerising MEGAcmd, but they differ and often involve build steps I'd rather avoid to keep things simple. The aim is to use a well maintained official base image and an official MEGAcmd release. Nothing inbetween. Updates should also be straight forward without relying on a third-party.
Create a new user
We'll be using Podman instead of Docker as it's a lot lighter and can run rootless. Additionally, to avoid accidentally giving MEGAcmd read or write permissions to files it doesn't need access to, we can create a new user.
sudo adduser mega-cmd
su - mega-cmd
Build a container image
We'll need a Dockerfile:
# ~/docker-megacmd/Dockerfile
FROM ubuntu:noble
WORKDIR /root
RUN apt-get update && apt-get install -y curl \
&& curl -O https://mega.nz/linux/repo/xUbuntu_24.04/amd64/megacmd-xUbuntu_24.04_amd64.deb \
&& apt-get install -y "$PWD/megacmd-xUbuntu_24.04_amd64.deb" \
&& rm "$PWD/megacmd-xUbuntu_24.04_amd64.deb" \
&& rm -rf /var/lib/apt/lists/*
CMD ["mega-cmd-server"]
MEGAcmd doesn't officially support Alpine so I ended up using Ubuntu. Using official pre-built packages involves a lot less maintenance than manually installing dependencies to build and run MEGAcmd in an unsupported environment.
We can build the image with Podman.
podman build -t megacmd ~/docker-megacmd
Sometimes Podman will give bus-related warnings. Configuring cgroup_manager
fixes that. This can be done with a command line flag, but using a configuration file ensures all commands we run uses the same configuration. Otherwise, it can cause incompatibility issues.
# ~/.config/containers/containers.conf.d/containers.conf
[engine]
cgroup_manager="cgroupfs"
Start a container
Once the image is built, we can create and start a container.
podman create --name "megacmd" --restart "on-failure:3" \
-v megacmd-data:/root/.megaCmd:rw \
-v /etc/machine-id:/etc/machine-id:ro \
-v /myfiles:/myfiles:ro \
megacmd
- MEGAcmd stores configuration, sessions and caches in
~/.megaCmd
on the container, which we are persisting in a named volume calledmegacmd-data
. - We need to set
/etc/machine-id
as it's used by some commands. Ubuntu's default/etc/machine-id
file exists but it's empty. - We can mount any directories we want to backup with read-only permissions. It's useful to match the paths between host and container so that our commands can naturally use host paths instead of having to translate them to container paths.
- We can automatically restart the container if MegaCMD crashes unexpectedly. We also want to limit the number of retries to avoid spamming Mega's APIs which can cause throttling.
podman start megacmd
Since mega-cmd-server
is the default CMD
, starting the container will start the server and tie them together. If the server stops, the container will stop too. The server will also log everything that its doing which Podman will automatically record. We can view and query the logs with:
podman logs megacmd
Stop a container
Annoyingly, mega-cmd-server
does not handle signals. This includes the default SIGTERM
sent by podman stop
. So Podman will timeout after the default 10 seconds and force kill the process. To safely stop the server, we need to use mega-quit
. This means we should avoid using --restart=always
as it conflicts with mega-quit
. We can follow up with podman stop
just in case.
podman exec megacmd mega-quit
podman stop megacmd
We could write a small wrapper script to catch signals and call mega-quit
, but that will introduce more maintenance work.
Run commands
MEGAcmd provides mega-cmd
which is an interactive shell to run various commands. However, with this container approach, it's better to run those commands standalone with podman exec
. They're all available using a mega-
prefix. So whoami
is mega-whoami
.
podman exec megacmd mega-whoami
Most of these mega-<cmd>
commands are simple wrappers around mega-exec <cmd>
so we could run that directly.
We can run one-off commands in separate throwaway containers too.
podman run --rm \
-v megacmd-data:/root/.megaCmd:rw \
-v /etc/machine-id:/etc/machine-id:ro \
-v /myfiles:/myfiles:ro \
megacmd mega-whoami
MEGAcmd commands always start mega-cmd-server
if it's not already running, so we're better off using podman start
and podman exec
to avoid unnecessary resource usage.
Update container images
To update MEGAcmd and the Ubuntu base image, we can rebuild with --no-caches
.
podman build -t megacmd --no-caches ~/docker-megacmd
After that's done, we'll need to remove and recreate any existing containers.
Since MEGAcmd on Linux relies on the distro's package manager, mega-update
is not available to automatically update MEGAcmd. You can technically update the container using the usual apt
commands, but that introduces critical but temporary state into the container which is best avoided. You can schedule a cronjob to rebuild the container image instead.
Conclusion
That's pretty much everything. MEGAcmd now runs in a container and can easily be started, stopped and removed. To switch MEGA users or configuration, we can change the named volume. There's a lot we can do more easily with MEGAcmd in a container.
Thanks for reading.