How I host my stuff

I got into selfhosting seriously around 2 months ago. I added and removed I don't know how many applications but what I have now is close to what I started with, bar the addition of immich. I knew about immich from the start but couldn't figure out storage until much later.

Everything lives in a single compose file. I know now that this isn't the ideal way and you should try to isolate unrelated services but it works and it's probably not that bad. Oh and I don't own the hardware and it's all on a VPS so you could say it's not really "selfhosted". But, I guess I could move everything to a home server (if I had reliable internet and a spare computer) without much trouble so it's not that different maybe?

Caddy (reverse proxy)

I use the very simple Caddy reverse proxy. It's really awesome and comes with automatic certificate management.

caddy:
  image: caddy:2
  container_name: caddy
  restart: always
  ports:
    - 80:80
    - 443:443
    - 443:443/udp # for HTTP/3
  volumes:
    - ./Caddyfile:/etc/caddy/Caddyfile:ro # this is what you need to
                                          # change the most
    - ./caddy-config:/config
    - ./caddy-data:/data # important stuff like logs and certificates
  environment:
    LOG_FILE: "/data/access.log"

This is the one service that hasn't changed in so long that I almost forgot how it works. If I want to selfhost a new application, all I have to do is add the following to my Caddyfile.

subdomain.cy7.sh {
	reverse_proxy <new application>:80 {
		header_up X-Real-IP {client_ip}
	}
}

Vaultwarden (password manager)

Vaultwarden was the first real service I had up. I tried the official version first. I thought it wouldn't be too complicated since they had a guide but oh my did it fry my 1 vCPU server.

vaultwarden:
   image: vaultwarden/server
   container_name: vaultwarden
   restart: always
   environment:
     DOMAIN: "https://pass.cy.sh"
     ADMIN_TOKEN: ${VAULTWARDEN_ADMIN_TOKEN} # password for web admin
                                             # interface
     LOG_FILE: /data/vaultwarden.log
     TZ: America/Toronto
     PUSH_ENABLED: true                              # for
     PUSH_INSTALLATION_ID: ${PUSH_INSTALLATION_ID}   # push
     PUSH_INSTALLATION_KEY: ${PUSH_INSTALLATION_KEY} # notifications
   volumes:
     - /vw-data:/data # protect this folder with care

I don't ever get push notifications from bitwarden, but apparently you need to set that up for automatic sync to work.

Linkding (bookmark manager)

Linkding is a really good bookmark manager. Confusing name I know, but I like the reasoning behind it.

linkding:
   image: sissbruecker/linkding:latest-plus # plus is important!
   container_name: linkding
   restart: always
   volumes:
     - /opt/linkding/data:/etc/linkding/data
   ulimits:
     nofile:
       soft: 1048576 # i know it's weird
       hard: 1048576 # but keep reading

This wasn't so smooth sailing and I shut it down to try Raindrop at one point. It ate a lot of memory from the start and stopped working completely not much later because malloc() would fail. Apparently this is an upstream issue, but luckily there's an easy fix.

I wished that my bookmark manager would also save a local copy of the stuff I save in case the webpage didn't exist anymore. Linkding's readme said it supports that and I was happy, but it'd ask Internet Archive to save it and store a link to the wayback machine's version instead. It took me a long time to figure out that there are two versions of docker images. The regular and default one is of course with latest tag. But, there's another with latest-plus tag and that comes with chromium and hence supports local snapshots. It makes why they have different versions (latest-plus is heavier), but I feel so stupid that it took me so long to figure that out. I have been loving Linkding since then.

There's a nice chrome and firefox extension that lets you quickly bookmark stuff. My favorite feature is being able to search through my bookmarks from the address bar by prefixing the query with ld.

Finally, if you use an iPhone, use this shortcut to add a "Send to Linkding" button in your share menu. It's so useful to save stuff to read later when I'm not on my computer.

Forgejo (git forge)

I really like this one too. Cause it works well without eating too much resources and I think it's cool to host repos on my domain. What I have setup is not much different from the instructions. I have it setup with PostgreSQL but SQLite works too. I had issues with using git over SSH when I had my stuff behind cloudflare so I disabled SSH in favor of HTTPS. Now that it's not behind cloudflare, I still haven't enabled SSH (yet). There's a process that you need to follow for SSH passthrough to work with docker and I'm too lazy to do it all over again (tbh i don't mind not having ssh anymore).

FreshRSS (news aggregator)

I started with FreshRSS but quickly switched to Miniflux cause it was "minimal". I switched back after I realized that the NetNewsWire iOS app supports FreshRSS as a backend. What I like more about FreshRSS is being able to read articles without visiting the link. I never thought about this as a feature but I like it now! The provided instructions for installing with docker is quite thorough so you should follow that. I use it with the default SQLite database, but it supports a bunch.

Immich (photos backup)

There's not much to say. It's really good and I cancelled my Google Photos subscription. Read the instructions carefully cause I really messed this up trying to it slightly my way.

My VPS doesn't have a lot of storage so I had more to figure out. Immich doesn't support any remote storage officially. I use rsync.net for all of my backups and they are awesome in that they support any protocol that runs on Unix so I wondered if I could take advantage of that. rclone recommends that you use it over SFTP so that's what I did.

Since immich doesn't support remote storage, I knew it wouldn't work over a simple fuse mount. rclone can emulate a normal filesystem with vfs file caching so I thought no biggie and ran it with --vfs-cache-mode full. It seemed to work, but it rclone's cache quickly ate up all of my storage and crashed :(. This was again because I was stupid and ignored this big fat warning:

So yeah I used --vfs-cache-mode writes instead and it worked.

export RCLONE_CONFIG_PASS=$(pass show rclone/crashtan)
config=/home/cy/.config/rclone/rclone.conf
sudo -E rclone mount \
    --config $config \
    --daemon --vfs-cache-mode writes \
    photos: /mnt/photos

It was painfully slow to load thumbnails and my initial solution was to use Cloudflare to cache everything. It seemed to work when I told Cloudflare to ignore Cache-control: private, but soon I figured out that this was a big security no no. Now, I store my thumbnails and other stuff that would be nice if it loaded faster on an SSD. I don't know how long I can sustain this but I'm happy until then.

IMMICH_DB_DATA_LOCATION=/opt/immich/postgres
IMMICH_UPLOAD_LOCATION=/mnt/photos/immich
IMMICH_THUMBS_LOCATION=/opt/immich/thumbs
IMMICH_PROFILE_LOCATION=/opt/immich/profile
IMMICH_ENCODED_VIDEO_LOCATION=/opt/immich/encoded-video

And then came another problem. I wanted to make AI work cause it'd be a pain to search for that specific photo otherwise. But since I was running on a 1vCPU 2GB RAM VPS, I knew I had to be more clever. Immich supports running ML (among other things) on a remote machine. In my case, the remote machine would be my laptop. I used Wireguard to connect my VPS and laptop at first, but later resorted to cloudflare tunnel instead just because it's a little more convenient. It took a couple days for the ML to complete, but it worked really well in the end. Execpt for the fact that I had to turn my laptop on before I could search. Even for things you'd think would be possible without AI.

But face grouping still works.

AdGuard (DNS-level adblocker)

Everybody uses this so I won't explain. I wanted to block ads on my phone that's all.