How I Use Git to Backup and Sync Obsidian Between Phone and PC (Free, No Cloud, No Fuss)
A guide on setting up an automatic sync and backup for your files using osync

This blog post goes hand in hand with my video “How I Sync Obsidian Between Phone and PC (Free, No Cloud, No Fuss)”. The two cover the same setup, but the different formats might help clear up any confusion during the tutorial section.
Osync is an independent project; it is neither affiliated with nor endorsed by Obsidian.
Attributions for all images, logos, sound effects, and media used in this post or in the YouTube video are listed here, shared under their respective licenses.
Backstory
I like taking notes whenever I have ideas, and one never knows when ideas will strike.
This particular project started that way: I had an idea, grabbed my phone, opened the notes app, and quickly wrote it down. And that’s where the problem begins, because my notes app is where ideas go to be forgotten and die.
I’m sure some of you know the feeling. The lack of organization is terrible, and that alone makes us less likely to write things down unless they feel absolutely crucial. My own notes app is cluttered beyond belief. It’s also not a great medium for writing or reading longer thoughts. I can’t really explain why—maybe it’s the tiny keyboard—but I rarely reread notes from my phone anyway.
The solution, at least for me, is Obsidian. I’ve used the app pretty consistently on Windows for a little more than two months now, and I like it. I think writing things into Obsidian would make me more likely to read them later because I also have them on my PC. Additionally, sometimes I think of something I know I noted down on my PC, but then I can’t access the notes from my phone because I don’t have Obsidian on Android.
Now, Obsidian has an Android app, but I didn’t set it up because to sync your notes through their official service, you need to pay a small monthly fee. Furthermore, at the time, I was just a little lazy; I didn’t want to watch some YouTube video to set up one of the free solutions, but I also didn’t really need to. I got enough utility on my PC.
The situation was simple: I wanted a free and reliable way to sync my notes between my phone and laptop. At first, I underestimated the scope of the project—not that it was huge, but I’m not exactly a Bash master—so it did get a bit demanding, which I welcomed.
Looking back, the process feels straightforward, but that’s hindsight. There was a lot of iteration. I initially thought something like rsync would handle everything and all I needed was a push service and a pull service running constantly. But after writing the code, I realized I needed to scrap that idea.
Challenges like realizing that a badly handled process substitution would not cause a pipefail and would lead to really weird behavior if the connection broke at a specific part of the code gave me the full software development experience. Figuring out how to correctly identify deleted files versus newly created ones, or stopping empty folders from being deleted unless explicitly requested—it was a nice experience.
There are definitely things to improve, though. I’ve complained several times about how much I dislike the ignore system, and I’m open to feedback on how to change it or make it less clunky.
Overall, figuring out how to keep two directories in sync was an interesting learning experience. It got me to explore Git and Bash commands I’d never used before and dive deep into man pages.
It showed me the insane utility that standard executable programs and built-in shell functions can give you.
Why I Use Obsidian
I like Obsidian because it’s simple, sleek, and built on Markdown.
I originally wanted to use it for the Zettelkasten method, but I’ve mostly dropped that and now use it for general note-taking, programming “recipes,” and spontaneous thoughts or ideas.
I don’t use the Graph feature much; it’s too much overhead for the way I write (currently). It’s a lot of up-front effort for notes whose long-term value is uncertain. And, if I’m honest, while I read my Obsidian notes more than the ones on my phone, I don’t reread my notes as often as I probably should—but hey, neither did Marcus Aurelius, so I can’t fault myself, haha.
No more wandering. You are not likely to read your own jottings, your histories of the ancient Greeks and Romans... — Marcus Aurelius, Meditations 3:14
Still, Obsidian is lightweight, distraction-free, and it makes me actually want to write. That’s what matters.
Why Use This Method Over Others?
I talk more about this in the video, but here’s the short version:
Obsidian Sync: the official solution. It’s great, seamless, but it’s paid.
Syncthing: probably the best free option for most people. It does what my setup does, but with a GUI, a ton of features, and years of maturity behind it.
Autosync: simple and convenient, but it depends on cloud storage and has ads.
So… why use this instead?
Honestly, I didn’t build this because I had a problem with any of those tools. It wasn’t some “Syncthing doesn’t do X, so I’ll fix it myself” moment. It started as a small experiment—one of those “let’s see if I can actually pull this off; if Linus built Git in a weekend, surely 😂” things—during which I gained a lot of appreciation and understanding for the underlying tools and for other alternatives like Syncthing.
Dealing with how these things actually work—how data moves, how to detect file deletions without an external ledger, making sure line endings are consistent between both sides, handling renaming, deleting, and updating operations, and the order they must happen in when using rsync to transfer the data—all of that was genuinely fun to figure out.
And somewhere along the way, it turned into something that’s actually pretty good for what I needed.
For me, the main strength here is that it combines syncing and backups under one umbrella. Syncthing’s biggest advantage is its relay network—it works across different networks when a direct connection can’t be established—whereas my setup is local-only for now. Both devices need to be on the same LAN and have SSH configured beforehand.
I think the real charm of this project is in its simplicity.
It’s small, transparent, and easy to read through (though it does offload complexity to underlying libraries, to be fair, lol). There’s no hidden layer or extra abstraction, just a (possibly way too long) shell script with Git and rsync doing their thing.
You can tweak it, extend it, or break it if you want to learn something.
It’s also kind of “Git-aware” by design. Git already tracks changes, so I figured, why reinvent that wheel? Instead of relying on some opaque database or sync ledger (well, I do track directories in a ledger, but if I could track directories with Git, I would have), I just let Git handle what it’s good at, let rsync handle the file transfers it’s good at, and built around them.
To be clear, this isn’t meant to replace anything.
If you want a polished, cross-network solution, Syncthing is fantastic.
But if you like the idea of a simple sync + backup system you can understand end to end, or you just want to mess around with something smaller and more easily configurable, this might be your thing.
If someone looks at this and goes, “hey, this fits my use case perfectly,” I’d be thrilled. But honestly, me using it is reason enough for it to exist.
0. Install Ubuntu
The first thing you’ll want to do is head over to the Microsoft Store and download Ubuntu.
1. Set up Git and SSH
While that’s downloading, open your browser and go to github.com.
If you don’t already have an account, create one, it’s quick and free.
If you already have one, or plan on using a bare repository instead, you can skip ahead to the repository creation section.
Once Ubuntu finishes installing, open it.
It’ll ask you to create a username and password; set those, and then run the following command:
sudo apt update && sudo apt upgrade && sudo apt install -y git gitk openssh-client rsync
This updates your system and installs all the tools we’ll need, Git, Gitk, SSH, and rsync.
You might be prompted for your password, that’s normal.
We use sudo here because it allows the command to run with administrator privileges (or in Linux terms, as the root user).
💡You may also want to install Git on Windows. It isn’t strictly necessary, but it can be convenient, especially if you don’t want to open WSL just to check a commit. Some helpful Git GUIs (e.g., GitHub Desktop) are Windows-only or more polished on Windows than on Linux. You may want to install one of these later as well.
I keep Git installed on both Windows and WSL so I can work comfortably with projects on either side. Consider what fits your workflow best.
Once that’s all done installing, we can set up SSH. This is what allows GitHub to recognize and trust your machine when you push or pull code.
If you’re setting things up with GitHub, run the following command:
ssh-keygen -t ed25519 -C “github key” -f ~/.ssh/id_ed25519_githubThis creates an SSH key pair that we’ll use for authentication.
We’re telling ssh-keygen to use the ed25519 algorithm . This is the modern and recommended choice.
The -C “github key” part adds a small comment to the key, which helps identify it later.
And the -f flag sets the file name and location.
Here we’re saving it in ~/.ssh/id_ed25519_github, which keeps it in the standard SSH key directory (~/.ssh) . You could store it anywhere, but SSH expects it there by default, and it’s safer to follow convention so you don’t lose track of it.
When it asks for a passphrase, you can just press Enter to skip it.
A passphrase acts like a second password for your key. It’s good practice to use one, but not strictly necessary for personal use if you keep your system secure.
Skipping it just means you won’t need to enter it each time you use Git.
If you ever need to secure sensitive or shared systems, though, definitely set one, and use an SSH agent so you only authenticate once per session.
Once the key is generated, switch into the SSH directory:
cd ~/.sshNow we’ll tell SSH to automatically use this key whenever you connect to GitHub.
Run the following:
cat >> ~/.ssh/config <<’EOF’
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
IdentitiesOnly yes
EOFThis appends the configuration to your SSH config file (or creates it if it doesn’t exist).
The addition essentially says:
“Whenever I connect to
github.com, use this specific key and the Git user.”
This prevents SSH from getting confused if you later add more keys for other services (for example, GitLab or private servers).
To check what’s inside the file now, run:
nano ~/.ssh/configYou can exit Nano by pressing Ctrl + X, then Y/N to confirm (if you made any changes; you shouldn’t have at this point), and Enter to save.
After that, we need to add the public key to GitHub.
Display it with:
cat ~/.ssh/id_ed25519_github.pubCopy the output, go to GitHub → Settings → SSH and GPG keys → New SSH key, and paste it there.
Give it a recognizable title, like “WSL key,” and click Add SSH key. You can name it whatever you like, this is just for your reference.
Finally, test your connection to make sure everything’s working:
ssh -T git@github.comIf all went well, you’ll see something like:
Hi username! You’ve successfully authenticated, but GitHub does not provide shell access.
And that’s it, you’re connected!
From now on, GitHub will trust your machine, and you won’t have to type your password every time you push or pull.
💡If you’re using both Windows Git and WSL Git, each environment has its own SSH directory.
You can either generate separate keys for each, or share one key by copying it between environments.
Just make sure permissions stay strict (chmod 700 ~/.sshandchmod 600 ~/.ssh/id_*) so SSH doesn’t ignore your keys.
This is just a tip, it isn’t relevant to this tutorial.
2. Clone the osync repo
Open your browser and go to the osync repository:
https://github.com/Kena-Njonge/osync
While you’re there, you can leave a ⭐ if you’d like, it helps more people discover the project.
Next, click the green “Code” button, select the SSH tab, and copy the link shown there.
Then, back in your terminal, run:
cd ~And clone the repository by running git clone, followed by the link you just copied:
git clone git@github.com:Kena-Njonge/osync.gitThis creates a new directory called osync inside your home folder.
You can verify it’s there by listing your files:
ls3. WSL config
Run:
sudo nano /etc/wsl.confMake sure the file contains the following lines (add them if they’re not there):
[boot]
systemd=true
This enables systemd inside WSL, allowing background services (like loginctl) to work properly.
Next, open Notepad on Windows and paste the following text:
[wsl2]
vmIdleTimeout=-1
When saving, choose “All files” (not “Text Document”) and name the file .wslconfig.
Save it under your user directory, e.g. C:\Users\test account\.
💡 The
.wslconfigfile controls global WSL2 settings.
SettingvmIdleTimeout=-1prevents WSL from automatically pausing the virtual machine when it’s idle, allowing it to run quietly in the background.
To video watchers: apologies for the slightly confusing way of creating it. I tried to edit most of the shenanigans out because I created a txt file the first time around.
We’re just making sure it’s recognized as a WSL config file rather than a .txt file. If you create a new text file through the shortcut, this isn’t the case.
Next, open PowerShell (you can click the “+” next to your Ubuntu tab and choose PowerShell), then run:
# Run this in PowerShell
wsl --shutdown
Wait about 8 seconds for the changes to take effect, then reopen Ubuntu.
Back in Ubuntu, enable linger mode for your user so services can run even without an open shell:
# Back in WSL: allow user services to persist
loginctl enable-linger $USER
To confirm everything is set correctly, run:
ps -p 1 -o comm=
loginctl show-user “$USER” | grep Linger
You should see:
systemd
Linger=yes
This confirms that systemd is running and linger is enabled, meaning your user services will stay active in the background even after you close the WSL terminal.
4. Create a New Repository
Next, go to GitHub and create a new repository. If you want to keep everything local and thus want to use a bare repository, skip this part.
You can name it Obsidian, or whatever you like.
If this is your first time on GitHub, let’s just call it Obsidian for simplicity.
Make sure you don’t add a README, set the repository to Private, and then click Create repository. There it is!
Now, we’ll navigate to your Obsidian vault from within WSL.
As you can see here, my vault is located on drive C: underUsers/testaccount/Documents.
Well, really, I call it a supervault, because it’s a vault (directory) that contains other vaults (directories) inside it. For example, I have one called vault within it.
If you click on the address bar at the top of File Explorer, you’ll see the full path.
Copy that path and paste it somewhere, like in Notepad, so you have it ready. Alternatively, right click on the supervault directory and copy as path.
Now back in WSL, run the following command:
cd /
This takes you to the root directory.
It’s equivalent to what I’m doing on screen. I just navigated there one directory at a time.
You can do it that way too, and eventually you’ll reach the root.
If you run:
lsYou’ll see subdirectories like bin/, mnt/, etc/, and others.
Note that path names, except for the drive letters like c, are case-sensitive and space-sensitive (well drive names are also case sensitive, I just wanted to point out that it is a capital letter on windows, but small letter here, but I think it came out a bit wrong).
You can use Tab to auto-complete folder names, but keep in mind:
auto-completion is also case-sensitive.
So, for example, I had to start with a capital T in Test account before auto-complete worked as you can see on screen.
Now we want to navigate down into the directory that contains our (super)vault.
We’ll start by changing into the mnt directory, then into c, and so on, until we reach the path we copied earlier.
5. Initialize the Repository
Now we’ll initialize our Git repository.
Run the following commands, and make sure to replace the placeholders with your own email and your name:
git config --global user.email “you@example.com”
git config --global user.name “Your Name”
git init
git checkout -b main
git add .That sets your Git identity, creates a new repository, switches to the main branch, and stages all your current files.
Next, this is where we diverge a little:
If you’re using a bare repository setup, skip to that section.
Otherwise, if you’re setting up with GitHub, run the following command; you can copy it directly from your GitHub repository page:
git remote add origin <SSH URL TO YOUR REPO>
git push -u origin main
The SSH URL looks something like this:
git@github.com:your-username/your-repo.git
💡 You might see an HTTPS option as well, but don’t use that, GitHub no longer supports password authentication over HTTPS.
Since we’re using SSH (and already configured our key earlier), this will authenticate seamlessly.
If You’re Using a Bare Repository
If you’re going the bare repo route, here’s how to do it.
Navigate to the local folder where you want to store your backups.
Ideally, this folder should be on another drive for better data safety.
Even if it’s on the same drive, it still acts as a form of backup, not a perfect one, but better than nothing.
Copy the path of this directory.
If it’s on Windows, get the WSL path by navigating to it just like we did before.
You can also run pwd once you’re inside that directory to print the full path.
(But I digress.)
Once you’re there, initialize the bare repository:
git init --bareNow go back to your vault directory.
I’m assuming you’ve already done the steps up to and including git add ., that is, setting your name and email, initializing Git, switching to main, and staging your files.
When adding the remote, make sure to quote the path to avoid issues with spaces in directory names.
And remember: if your path is on Windows, we need the path through WSL.
All you have to do now is:
git remote add origin “<PATH TO YOUR BARE REPO DIRECTORY>”
git push -u origin main
Ok now we have essentially set up everything that we need to set up for git.
7. Termux Config
Let’s quickly switch over to our phone and set up a few things before coming back.
First, download Termux from your preferred source, whether that’s F-Droid, GitHub, or the Play Store.
Only download Termux GitHub builds from the official Termux GitHub page, do not download Termux from any other site or store apart from the official ones.
The easiest way for most people is simply to grab it from the Play Store.
The Play Store version is safe and, as of recording this video, version 2025.10.05, it has no known security vulnerabilities.
It’s being actively maintained, albeit a bit more passively than the F-Droid and GitHub builds, but it’s regularly forked from the main repository.
If you’re downloading via F-Droid or GitHub, check the installation section of the GitHub README for more details.
I’ll leave a link to the Termux GitHub page here, but in general, it’s always better to search for official links yourself, just in case a shared link ever gets compromised. https://github.com/termux/termux-app
Run the following commands
Once installed, open Termux and run the following commands:
termux-setup-storage
pkg update && pkg upgrade
pkg install openssh rsync
passwd
whoami
ifconfig # note inet IP (e.g., 192.168.x.x)
pkill sshd
sshd # Termux default port = 8022
termux-wake-lock # also disable battery optimization in Android
Let’s quickly break down what we’re doing here:
termux-setup-storage-> grants Termux access to your Android filesystem.pkg update && pkg upgrade-> updates Termux packages, just like we did on PC.pkg install openssh rsync-> installs OpenSSH and rsync, both needed for syncing.passwd-> sets a new password for SSH access. Write it down!whoami-> displays your Termux username (it’s auto-generated). Write it down!ifconfig-> shows your IP address; we’ll need that to connect from the PC. Write it down!
Finding your IP
When you run ifconfig, you’ll see something like this:
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.30.42 netmask 255.255.255.0 broadcast 192.168.30.255
inet6 fe80::a1b2:c3d4:e5f6:1122 prefixlen 64 scopeid 0x20<link>
ether 3c:52:82:1a:bc:7f txqueuelen 1000 (Ethernet)
RX packets 132456 bytes 187654321 (178.9 MiB)
RX errors 0 dropped 12 overruns 0 frame 0
TX packets 124987 bytes 165432109 (157.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 10.0.0.15 netmask 255.255.255.0 broadcast 10.0.0.255
ether b8:27:eb:de:ad:be txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
TX packets 0 bytes 0 (0.0 B)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 5240 bytes 438912 (428.6 KiB)
TX packets 5240 bytes 438912 (428.6 KiB)
We’re interested in the inet line under wlan0 that’s your local (wireless) network IP.
Do not use the broadcast address (255.255.255.x), not the loopback (127.0.0.1), and not the netmask.
Copy the 192.168.x.x address, that’s what we’ll use to connect to your phone later.
This is a local ip address for your home network.
⚠️ This syncing works only on your local network. Your phone and PC must be on the same Wi-Fi/LAN.
Editing the SSH config
Next, let’s tweak the SSH server configuration.
We’ll navigate to the SSH config directory by running the following commands one at a time:
cd $PREFIX/etc/ssh # same as: cd ../usr/etc/sshOnce inside the ssh directory, open the configuration file:
nano sshd_configThis opens the SSH daemon configuration in Nano.
Find the line that says #PasswordAuthentication no and uncomment it (remove the #) and change it toPasswordAuthentication yes.
Also, find the #Port line and uncomment that as well.
After making those edits, save and exit using:
Ctrl + S (save)
Ctrl + X (exit)
Next, kill the SSH daemon:
pkill sshd
Finally, start the SSH daemon again:
sshd
Now your phone’s SSH server is active, and you’ll be able to log in using the username and password you just set.
One last thing before we switch back
Before we return to the PC, let’s make sure Termux stays awake in the background.
Run:
termux-wake-lock # also disable battery optimization in AndroidThis prevents Android from force-closing Termux to “save battery.”
Without this, the SSH server might stop running when your screen turns off.
8. Termux SSH config
It doesn’t matter which directory you’re in, run:
ssh-keygen -t ed25519 -C “termux key” -f ~/.ssh/id_ed25519_obsidianThis creates a new key pair specifically for Termux.
Next, open your SSH config file:
cd ~/.ssh/
nano configIf you already added your GitHub entry earlier, scroll to the bottom and add a new entry for your phone:
Host termux
HostName <PHONE_IP>
Port 8022
User <TERMUX_USERNAME>
IdentityFile ~/.ssh/id_ed25519_obsidian
IdentitiesOnly yes
Replace <PHONE_IP> and <TERMUX_USERNAME> with the values you noted down from Termux.
Save and exit (Ctrl + S, then Ctrl + X).
Copying the public key to your phone
Now copy your public key to the phone:
ssh-copy-id -i ~/.ssh/id_ed25519_obsidian.pub -p 8022 termuxThis tells SSH to copy the specified public key to the host named termux using port 8022.
Technically, you don’t need to specify the port here since it’s already set in the config, but it doesn’t hurt to include it either.
When prompted about the host’s fingerprint, type yes to continue.
This fingerprint is just a hash identifier confirming the host’s authenticity.
Next, enter the password you set on the phone earlier, that’s your Termux SSH password.
Testing the connection
Once that’s done, you can log in directly using:
ssh termuxIf everything worked, you should now be inside your phone’s Termux environment from your PC.
Strengthening security
Let’s disable password authentication on the phone now that SSH key login works.
Go back into your Termux SSH config file like before:
cd $PREFIX/etc/ssh
nano sshd_configFind the line:
PasswordAuthentication yes
and change it to:
PasswordAuthentication no
Save and exit, then restart the SSH daemon:
pkill sshd
sshdTo confirm the setting applied, run:
sshd -T | grep -i pass
You should see:
passwordauthentication no
Password logins are now disabled, and only your SSH key can connect.
Final setup on Termux
Create your Obsidian folder at the root of your file system just do this through your file explorer (see 32:45 in video).
Now you can navigate to it inside Termux:
cd ~/storage/shared/ObsidianThis folder will act as the sync target for your (super-)vault.
Make sure Termux is still running the SSH daemon and that the wake lock is active:
termux-wake-lock
sshdAt this point, Termux is ready to accept SSH connections from your PC and sync and your setup is secure.
9. Filling in the service and timer files and transferring the files.
.gitignore
Open your notepad and paste this
.obsidian/
.trash/call it ‘.gitignore’. Save it as “All Files” in your (super-)vault directory
This tells git to ignore these files when transferring.
💡 Honestly, I wish I didn’t have to do this here, as it is completely ugly to have two places to ignore, and I didn’t realize how big of an issue it was, that is how unintuitive the ignore system was until I was writing this post/script. I have since updated the docs to explain it a bit more, i.e. why use the
--ignoreflag and why use the .gitignore, but I realize that there is quite weird behavior that is unwanted that can happen. Rest assured that this is the highest priority thing to fix, it already was before, but now I realise how ugly the system is.
Fill in the vault-sync.service file and make the script executable
Navigate to your home dir on WSL and then into the osync folder:
cd ~
cd osyncFirst run
chmod +x osync.shThis makes the script executable if you do not do this, everything else from here on out will fail.
We are currently in the osync folder which is where we cloned the repo. Open the vault-sync.service by running:
nano vault-sync.serviceAnd fill in the paths it needs. I like to copy the file into Notepad, fill in paths there, and paste it back when done.
We already noted down our local vault path earlier. If it contains spaces, put the path in quotes. Just quote paths by default, it saves you from weird edge cases most of the time.
To get the full path to the script, exit the file (Ctrl + X) and run:
pwd
Then append /osync.sh to that path.
Config name:
termux(as we set before)Remote (phone) path: single-quote it so
~expands on the phone, not locally.
Usually:‘~/storage/shared/<DIR_NAME>’The path to your local dir through WSL we got earlier, when we went through
/mnt
Fill those into the vault_sync.service file where indicated (see video at 35:30 if you need some guidance). When done, paste it back into vault-sync.service and save (Ctrl + S, Ctrl + X).
One quick dry-run before enabling the service
From your Notepad, copy the ExecStart command part (after the lock bit, as shown on screen at 36:05).
Do not run it yet. First, remove --realrun and add --seed (like I do in the video).
It should look something like this
“~/osync/script.sh” “/mnt/c/........” termux ‘~/storage/shared/<DIR_NAME>’ --ignore .obsidian --ignore .trash --seed
This gives you a preview of what would be transferred without actually copying.
Paste it into the terminal and now run it. If you get an error like I did in the video, you probably forgot to start SSH and/or enable a wake lock on the phone. On Termux, run:
sshd
termux-wake-lock
Run the dry-run again; it should now list the planned transfers.
Now run the same command again but with --realrun to actually copy files.
Open Obsidian on your phone, you should see your vault now.
10. Final Part – systemd and Task Scheduler
If you’re not already in the osync folder, switch to it:
cd ~/osync
Now run the following commands to create the directory for your user services and copy both the service and timer files into it:
mkdir -p ~/.config/systemd/user
cp vault-sync.service vault-sync.timer ~/.config/systemd/user/This places the systemd service and timer in the correct location so your system can find them.
Next, change into that directory:
cd ~/.config/systemd/userReload the systemd daemon so it can recognize the new files, then start and enable the timer:
systemctl --user daemon-reload
systemctl --user start vault-sync.timer
systemctl --user enable vault-sync.timerThe timer automatically triggers the service at regular intervals, every few seconds by default, and the service, in turn, runs the osync script we set up earlier.
💡 In the video, I actually forgot to enable it, but it was already enabled from before, so don’t forget to enable it as I did, or it will only run once. Run the commands above to make sure it’s correctly set up.
You can confirm that everything is working by running:
systemctl --user status vault-sync.timer
You should see it listed as active (running).
Auto-starting the sync with Task Scheduler
Now for the final piece; Making sure the sync runs automatically whenever you log in to Windows.
This step ensures that WSL (and therefore your sync service) starts up without you manually opening it.
Open the Task Scheduler app on Windows and create a new task.
Give it a clear name, like Start WSL Sync.
Then set it up as follows:
Trigger: At logon
Action: Start a program
Program/script:
wsl.exeAdd arguments:
--exec dbus-launch true
Settings:
Allow task to be run on demand
Allow up to three restart attempts, waiting one minute between each
That’s it!
You can manually run the task once to test it, or just log out and back in, your sync will start quietly in the background every time you log on.
11. Small Note on Gitk
To view your diffs with Gitk, simply run:
gitk
You can do this either from within your vault’s directory in File Explorer (using the address bar) or directly in WSL.
In foresight, although Gitk is lightweight, reliable, and straightforward once you’ve set it up, some of you might prefer a more modern Git GUI. Personally, none of them currently scratch my particular itch, including GitHub Desktop and Gitk, though they’re perfectly fine tools.
Something to explore further in the future.
12. Final Notes on customization
The strength of this setup lies in its customizability, made possible by its use of simple, well-documented tools.
For example, you can easily add pre-run and post-run hooks to the vault-sync.service file or as git hooks.
This means you could run your own scripts before or after each sync; say, to count the total number of words changed and save that to a CSV, keeping a running total of how much you’ve written each day.
You could even have a script notify you via a Telegram bot in the morning if the service fails to start.
You can also customize the sync timing via the vault-sync.timer.
For instance, you might explore triggering syncs only when certain paths change; an idea I experimented with earlier but abandoned for two reasons.
First, I eventually realized it doesn’t make much sense in practice; the current default (a sync every few seconds) is probably already more frequent than necessary.
It’s fine for readability and quick diffs, but in truth, I don’t check my diffs that often anyway.
And second, path changes are not propagated well to WSL; a further motivator for me to make the switch to Linux eventually, especially with all the Omarchy hype, though I haven’t yet.
I’d actually encourage you to tune the interval yourself; it’s a good exercise in getting familiar with how systemd timers work, and it’s easy to change.
Another possible area for experimentation is the commit messages.
This one’s a bit trickier since it requires diving into the osync.sh code; but you could make it more verbose or descriptive about what changed during each sync.
Ultimately, everything here is meant to be flexible; you can shape it to fit your own workflow.
Working Across Different Networks
You can also set up the same system for different networks.
Stop the timer and service first:
systemctl --user stop vault-sync.timer
systemctl --user stop vault-sync.service
Then, update the IP address in your SSH config and save.
After that, run:
ssh -T termuxThis adds the new host to your known_hosts file so SSH can connect silently, without asking for confirmation each time, SSH will probably throw a warning here that the fingerprint has changed, that is why we need to run this first before we start the transfer.
Finally, start the timer again:
systemctl --user stop vault-sync.timer
systemctl --user stop vault-sync.service
At this point, your SSH connection should open quietly, and the sync script can run automatically.
I admit, as I have before, that this solution isn’t beautiful; we will work on a way to make this happen (semi-)automatically, similarly to Syncthing. It is a priority.
When Your Router Assigns a New IP
If your router assigns your device a new IP; which shouldn’t happen too frequently; you can simply repeat the same short process: stop the timer, update the IP, reconnect once via SSH, and restart the timer. Fixing this also falls under the scope of having connections happen (semi-)automatically.
Staying Updated
If you want to access new functionality as I or others contribute, you’ll need to pull the latest updates from the repository and restart the service.
In the future, once the more pressing improvements are done, I’ll work on making fetching updates more seamless if possible.
Subscribe to my YouTube channel to stay up to date on new releases; I will post update videos whenever a major release drops.

