Vikunja with local mysql

I’m trying to setup a vikunja instance on my server. Since the server has mariadb running anyway for a nextcloud instance, I figured that using the mysql backend made the most sense. However, it seems that I’m running into authentication issues with this setup. My guess is that this is due to vikunja running under a dynamic systemd user instead of a permanent system user which the mysql socket authentication cannot authenticate. This might also be totally off the mark, I don’t have much experience with database servers yet.

Has anyone here managed to get a similar setup to work? Or am I the only one trying this madness? I’m using the current stable branch (nixos-25.11) updated last week.

1 Like

That’s a pretty good guess. The solution to this problem is to add the dynamic user to a group with SupplementaryGroups. If the socket remains invisible, you may need to add it to the visible paths with ReadWritePaths, or do some fenangling with systemd socket passing via file descriptors that most services seem incapable of supporting.

Do you have any idea what group that be? Actually, I don’t think the issue is the socket being invisible. To me it is looking like this:

  • When I try to list all vikunja users (which should be none currently, because it’s a fresh install) with the command vikunja user list I get

    time=2026-04-13T13:05:25.706+02:00 level=INFO msg="Using config file: /etc/vikunja/config.yaml"
    time=2026-04-13T13:05:25.708+02:00 level=ERROR msg="Could not init file handler: storage validation failed: failed to access file storage directory at /var/lib/vikunja/files: stat /var/lib/vikunja/files: permission denied\n[process uid=1000 gid=100]"
    

    The directory /var/lib/vikunja is a symlink to /var/lib/private/vikunja and file permissions are

    ls -la /var/lib
    lrwxrwxrwx  root  root  vikunja -> private/vikunja
    
    sudo ls -la /var/lib/private
    drwxr-xr-x  nobody  nogroup  vikunja
    

    Here nobody and nogroup stem from the fact that the vikunja server is running under the dynamic systemd user. It looks like the vikunja binary is trying to access the directory with the wrong user (maybe my private login user?).

  • When I try the same with sudo I get a different error message

    time=2026-04-13T13:05:59.434+02:00 level=INFO msg="Using config file: /etc/vikunja/config.yaml"
    time=2026-04-13T13:05:59.435+02:00 level=INFO msg="Running migrations…"
    time=2026-04-13T13:05:59.436+02:00 level=ERROR msg="Migration failed: Error 1698 (28000): Access denied for user 'vikunja'@'localhost'"
    

    Now the binary cannot access the database as the vikunja user (which I created inside mariadb with unix socket authentication.

In both cases it seems like the binary tries to access data with the wrong permissions. I don’t know which of the two cases is actually failing earlier because I have not looked at the vikunja source code yet. And I can’t run the command as the vikunja user because that user doesn’t exist outside of systemd.

The only solution I can think of right now is to update nixpkgs to create a vikunja system user that runs the server instead of using the dynamic user feature. However, I wanted to check here for advice before opening an issue and/or a PR.

The dynamic systemd user has some security advantages but complicates interprocess communication.

My last attempt to introduce a configuration option for a local system user was not successful.

Without local user, there are not many options left, possible workaround: use a full localhost network stack + db user authentication instead of (lightweight) sockets.

A new group with a name of your choice. That said, yeah, your analysis suggests that the service can see the db socket, so that works fine; I’d need to see runtime logs of your service to see what’s actually wrong.

That’s because you’re trying to do socket peer authentication with the root user, when the database is owned by vikunja.

You can, while the service is running the user exists. sudo -su vikunja should work.

If you cannot get the service to run, you can use systemd-run to create a temporary service with a dynamic user named vikunja instead.

Technically, systemd-run is also a way better way to manually run commands “in” the respectice service, since you can emulate the environment exactly, unlike with sudo. That does require being familiar with systemd though.

Of course you can do that, it’s definitely easier, but no, it’s perfectly possible to do this with dynamic users, I’ve done so plenty of times with other services.

Looking at the log output of journalctl for the vikunja service again, the service might actually be okay for now (the webserver is running at least and the login page is showing up). However, I cannot really tell as there is no real activity on the service just yet. What I’m struggling with at the moment is the creation of my user inside vikunja. I don’t want just anyone to be able to register a user on my server. Therefore I disabled user registration in the configuration. However, this means that I need to create my user in a shell with the vikunja command, and the error messages of my attempts at this I have posted above. If you think that any other log output would help then I’m happy to provide.

I tried this and I failed because sudo -su does not do any of the state directory magic that systemd does. So the command still has no access to the state directory /var/lib/vikunja.

Then I guess this is what I will try next. Sadly I’m not too familiar with systemd. So far I didn’t get this to work either.

Yeah, I did some reading on it but not a lot. It indeed seems like a good security feature, but as soon as other processes or state in other places get involved it gets tricky. I wonder ifit is worth the trouble in this instance.

That is unfortunate. I might add my use case to the discussion for what it is worth.

I would rather avoid that if possible since secret management is another deep rabbit hole on NixOS that I managed to not fall into up until now.

Really? I imagine the issue is more that the configuration isn’t in /etc so your command probably uses default directories or something.

It’s a little hard to help debug without spinning up a vikunja service myself (and I kinda lack the domain-specific knowledge to do that properly, though I guess I could try), but it would help if you at least shared command output of your experiments.

You are referring to this experiment?

sudo --user vikunja vikunja user list

2026/04/22 11:02:16 failed to create modcache index dir: mkdir /.cache: permission denied
time=2026-04-22T11:02:16.661+02:00 level=INFO msg="Using config file: /etc/vikunja/config.yaml"
time=2026-04-22T11:02:16.661+02:00 level=ERROR msg="Could not init file handler: storage validation failed: failed to access file storage directory at /var/lib/vikunja/files: stat /var/lib/vikunja/files: permission denied\n[process uid=63638 gid=63638]"

As you can see the command still does not have access to /var/lib/vikunja. The way I understood it systemd is somehow mounting /var/lib/private/vikunja back to /var/lib/vikunja just for the service in question. That way the service does not gain access to anyhing else in /var/lib/private because that directory is owned by root with permissions 700. It is only seeing its own remounted data. I suspect (but have too little understanding to prove it) that sudo --user does not enter the environment where that remount has happened (this must happen per service as otherwise the system would be pointless).

I also tried sudo -su vikunja as you suggested. But since that user does not have access to my terminfo this left me with an unusable shell.