Linkwarden user here. Can confirm - it's a great tool to dump links for later. I've setup an iOS shortcut that lets me share links directly to linkwarden. Super handy
Selfhosted
A place to share alternatives to popular online services that can be self-hosted without giving up privacy or locking you into a service you don't control.
Rules:
-
Be civil: we're here to support and learn from one another. Insults won't be tolerated. Flame wars are frowned upon.
-
No spam posting.
-
Posts have to be centered around self-hosting. There are other communities for discussing hardware or home computing. If it's not obvious why your post topic revolves around selfhosting, please include details to make it clear.
-
Don't duplicate the full text of your blog or github here. Just post the link for folks to click.
-
Submission headline should match the article title (donât cherry-pick information from the title to fit your agenda).
-
No trolling.
Resources:
- selfh.st Newsletter and index of selfhosted software and apps
- awesome-selfhosted software
- awesome-sysadmin resources
- Self-Hosted Podcast from Jupiter Broadcasting
Any issues on the community? Report it using the report flag.
Questions? DM the mods!
Great to hear! Just wait till you hear about the upcoming official mobile app!
Nice, how are you hosting it?
This is a fantastic tool, but Iâd love to confidently expose the API to the internet for the shortcut. To do that you need read-only and running as a user; I saw that thatâs not a thing that works from the issues.
Any thoughts on getting those security features working? Cause the app itself is so smooth Iâd let my parents use it and be confident they wouldnât need to be herded constantly.
So you want to disable registration? It's possible.
No what I said isn't about user registration; it's about adding these to the docker-compose.yml
:
read_only: true
user: 6969:6969
to prevent running as root and making the file system read-only. The API needs to be exposed without a VPN or other proxy login since my parents' can't handle that, so if I was able to implement these recommended security steps I'd feel like I could open up the container to the internet at large without too much risk.
Per this issue https://github.com/linkwarden/linkwarden/issues/799 it seems like there's a lot of steps to take to get these settings to work.
It would be also ideal if I didn't have to give the container (but not a deal-breaker):
cap_add:
- CAP_SYS_ADMIN
- CAP_SYS_CHROOT
as the issue also states is required for the headless chrome scraper browser.
I am using it internally now and it's really good, but to open it up for my parents (which I think they'd dig) I'd definitely want these security settings on without major issues. Linkwarden is an internet-facing application so these recommended security practicies are in its wheel-house, feature-wise, as well.
Hope that helps clear up my comment!
Oh I see, thanks for letting me know! Yes that's actually requested and we'll be getting to it sometime.
Great to hear! Itâs seriously slick and âjust worksâ. With those security features up you can tout them on the cloud offering too :)
So I have mine running in a podman quadlet. It runs as root in the container but it is unpriviledged. Mine has NET_ADMIN and SYS_MODULE but I honestly can't remember why... SYS_ADMIN seems extreme though
Edit: I'm dumb, and the linkwarden container has no capabilities set. I set them for the tailscale container which definitely needs it.
Care to share your quartet? Iâm just getting into the quads with trixie out - and I havenât gotten this working yetâŠ
The permissions do seem intense; if youâre getting by without maybe those arenât quite needed!
Sure thing, I'll edit this reply when I get back to my computer. Just note that I also have a tailscale and nginx container in the pod which are not necessary.
You'll see my nginx config which reverse proxies to the port the service is running on. On public servers I have another nginx running with SSL that proxies to the port I map the pod's port 80 to.
I usually run my pods as an unpriviledged user with loginctl enable-linger
which starts the enabled systemctl --user
services on boot.
All that being said I haven't publically exposed linkwarden yet, mainly because it's the second most resource intensive service I run and I have all my public stuff on a shitty vps.
Edit: My opsec is so bad hahaha
Edit2: I just realized the caps I gave were to the tailscale container, not the linkwarden container. Linkwarden can run with no caps :)
I added the tailscale stuff back
files:
linkwarden-pod.kube:
[Install]
WantedBy=default.target
[Kube]
# Point to the yaml in the same directory
Yaml=linkwarden-pod.yml
PublishPort=127.0.0.1:7777:80
AutoUpdate=registry
[Service]
Restart=always
linkwarden-pod.yml:
***
apiVersion: v1
kind: Pod
metadata:
name: linkwarden
spec:
containers:
- name: ts-linkwarden
image: docker.io/tailscale/tailscale:latest
env:
- name: TS_HOSTNAME
value: "link"
- name: TS_STATE_DIR
value: /var/lib/tailscale
- name: TS_AUTHKEY
valueFrom:
secretKeyRef:
name: ts-auth-kube
key: ts-auth
volumeMounts:
- name: linkwarden-ts-storage
mountPath: /var/lib/tailscale
securityContext:
capabilities:
add:
- NET_ADMIN
- SYS_MODULE
- name: linkwarden
image: ghcr.io/linkwarden/linkwarden:latest
env:
- name: INSTANCE_NAME
value: link.mydomain.com
- name: AUTH_URL
value: http://linkwarden:3000/api/v1/auth
- name: NEXTAUTH_SECRET
value: LOL_I_JUST_PUBLISHED_THIS_I_CHANGED_IT
- name: DATABASE_URL
value: postgresql://postgres:password@linkwarden-postgres:5432/postgres
- name: NEXT_PUBLIC_DISABLE_REGISTRATION
value: "true"
- name: linkwarden-nginx
image: docker.io/library/nginx:alpine
volumeMounts:
- name: linkwarden-nginx-conf
subPath: nginx.conf
mountPath: /etc/nginx/nginx.conf
readOnly: true
- name: linkwarden-postgres
image: docker.io/library/postgres:latest
env:
- name: POSTGRES_PASSWORD
value: "password"
volumeMounts:
- name: linkwarden-postgres-db
mountPath: /var/lib/postgresql/data
volumes:
- name: linkwarden-nginx-conf
configMap:
name: linkwarden-nginx-conf
items:
- key: nginx.conf
path: nginx.conf
- name: linkwarden-postgres-db
persistentVolumeClaim:
claimName: linkwarden-postgres-db-claim
- name: linkwarden-ts-storage
persistentVolumeClaim:
claimName: linkwarden-ts-pv-claim
***
apiVersion: v1
kind: ConfigMap
metadata:
name: linkwarden-nginx-conf
data:
nginx.conf: |
#user nobody;
worker_processes 1;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip off;
# set_real_ip_from cw.55.55.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
server {
listen 80;
server_name _;
location / {
proxy_pass http://localhost:3000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Accept-Encoding "";
proxy_set_header Host $host;
}
}
}
I also have a little helper script you might like
copy.sh:
#!/bin/bash
SYSTEMD_DIRECTORY="${HOME}/.config/containers/systemd"
POD_NAME="linkwarden-pod"
mkdir -p "$SYSTEMD_DIRECTORY"
cp "${POD_NAME}".{kube,yml} "${SYSTEMD_DIRECTORY}"/
systemctl --user daemon-reload
Thanks! Thisâll def help me get tooled up for podman :)