Once you start letting people edit the config files, you get into a spot where now you basically need to be able to parse the config files to read file paths. That often means making version-specific parsers for configuration options that are introduced or removed in some versions, or have differing defaults (i.e. in 1.2 if they don't set "storage_path" it's at /x/, but in 1.3 if they don't set it, it defaults to /y/).
That gets to be a lot of work.
Then it gets even worse when the users can edit the Docker config for the images, because all bets are off at that point. The user could do all kinds of weird, fucky shit that infinitely loops naive backup scripts because of host volume mounts or have one of the mounts actually be part of NFS mount on the host with like 200ms of latency so backups just hang for forever and etc.
It's just begging for an infinite series of bugs from people who did something weird with their config and ended up backing up their whole drive instead of the Docker folder, or removing their whole root drive because they mount their host FS root in the backups folder and it got deleted by the "old backup cleanup" script, or who knows what.
At some point, it's easier to just make your own setup where you define the limitations of that setup than it is to use someone else's setup but have to find the limitations on your own.
Is your project public? I'm working on one as well and would love to see what you have cooking.
The rough gist is that it's for hosting dedicated servers for video games, with an emphasis on having an easier to use UI than most providers combined with a usable API/CLI for advanced users. Ie. Instead of editing config files as regular text files, I want to offer a view with drop downs for each config option, a description of what each value does. (with some hidden for orchestration reasons, like the port it listens on)
Architecture-wise, it's a 3-tier app. HTTP API frontend talks to gRPC backend talks to Postgres. gRPC in that middle tier because I want to move the control plane for the agents into gRPC. Currently, the control plane consists of generating an Ansible inventory and executing it, and Ansible handles downloading the game if it doesn't exist, making dirs, SFTPing configs, install a Prometheus agent, etc.
It's not anything I intend to hyperscale, but I've always been the dedicated server guy among my friends, so I figured I might as well make a little thing out of it. I'd be happy with a small ARR.
That way lies madness...
What can be done instead is to provide your own unified (some schema validated) configuration options, and generate the app specific config files from your source of truth. Then you can know what the user can configure and how to back everything up (and how to do a lot of other things in automated fashion). And you also have a safe upgrade path if format of any underlaying config changes.
I opted to store the app and version, and have a function that retrieves a config parser for it. I just didn't want to manage 300 tables just to get the schema to work.
That's also partially because I'm using Ent in Go, so it generates a struct for each table. It'd make my auto-complete useless, and that's not a price I'm willing to pay on a personal project lol
Docker and Docker Compose is pretty good for self-hosting, except you have to understand enough to realize that it's not as simple as it sounds. You can easily lose data you didn't know you had if you're not paying attention.
"I'll just delete the container and restart" sounds like a great solution, but you just blew away your photos or whatever because you didn't know it created some volume for you.
I have a btrfs volume as the root of all the apps. Each application is in an individual subvolume so they can be snapshotted at upgrade time. The docker-compose.yml file points each app's volume to a relative directory inside that subvolume.
This way I can move them around individually, and all their data is right there. I can back them up pretty easily too.
Works for me and my use case, but you could never expect it to be turn key, and you couldn't hand it off to somebody non-technical.
Just because Docker selfhosting has "taken off" doesn't mean it isn't still a dead end.
EDIT: Also, to be clear, Docker is also a "specific ecosystem". It's very popular, it doesn't make it any more general than anything else.
So to give you an idea, Sandstorm requires: An app always must recover from forced termination (the only way it shuts apps down!) and that a given app carry all of the code it needs to update its data from any previous version. If you don't do these things, your homelabber will inevitably be fixing stuff themselves in various apps because their server lost power or the app developer demanded some bespoke intermediate inane update steps, or you missed a few versions while your server was off.
What percentage of apps made available via Docker meets those requirements? Probably a lot less than you'd think. (Most of them that do easily work on Sandstorm!) But if you want to make selfhosting work for non-sysadmins (or sysadmins who don't want to do a second job when they get home from their main job), you have to do these things.
Another thing is that you basically have to have security right because your users and even your server admin probably aren't experts, and definitely aren't paying for an enterprise-class firewall. So a big part of Sandstorm's opinionated app design is around making it fundamentally impossible for app vulnerabilities to exist. Things like proxying everything through the platform, isolating individual documents into their own app instances, handling authentication and authorization, etc. all become core to making apps secure enough to not have to worry about them that much.
This is especially important because a lot of selfhosted apps get abandoned and unmaintained, but selfhosters still want to use them. Of course, all these things fundamentally require changes to the app your random Docker container shipper can't insist on, and that's before we get even into performance concerns, which are key since selfhosters tend to use old or cheap hardware.
If you want to use a monolith you will have conflicts sooner or later. Of you want to use multiple VMs you need to orchestrate them.
If you know how to do the above you are good to go to learn docker which is ultimately much simpler.
Everything is auto updated from a single YAML specification (which I usually pin), so the process to update something is "change the version in the config, commit, and the server will pick the change up and deploy it".
It's just a thin layer over "git pull; docker compose restart", but I love it.