Hi, and sorry for a long-winded post.
I’m quite new to running my own servers and GNU/Linux in general. I set up TrueNAS on my old computer and I’ve been tinkering with it for a few months and most recently started messing with all sort of containerized apps.
I’m now getting to the point of wanting to expose a service to the public internet (Picoshare for quickly sharing files with friends) without Tailscale, because I want my friends to be able access it without messing with VPNs, but I have some concerns about this. I’ll list them at the bottom of the post.
This is my app setup currently:
ix-applications configuration
- Portainer
- Only configarion is that I set Portainer Data Storage to
/mnt/pool_0/Apps/portainer/data
- Only configarion is that I set Portainer Data Storage to
- Tailscale
- Auth things to get it working
- Checked
Host network
, not sure if necessary - State storage binds to
/mnt/pool_0/Apps/tailscale
Portainer
- Using the default “local” environment that just showed up.
- I think all of my apps use bind mounts.
- Created networks
backend
andfrontend
that use thebridge
driver. - Bunch of apps deployed via docker-compose, namely:
- Nginx Proxy Manager, used for reverse proxying
- Joins
backend
andfrontend
networks. - Bind mounts to
/mnt/pool_o/Apps/nginx/data
andcerts
. - Running on ports
80
and443
, and I’ve added the port forwarding rule for that in my router. - I add Proxy Hosts via the UI, for example:
budget.mydomain.com
routes tohttps://actualserver:5006
. - I add Let’s Encrypt wildcard certs for my local services via DNS challenge here.
- Joins
- Adguard Home, mostly used for local DNS rewrites
- Joins
backend
andfrontend
networks. - Bind mounts to
/mnt/pool_o/Apps/adguardhome/data
andconfig
. - I add my local DNS rewrites here. I just use my bought domain instead of
.local
or.internal
, for examplebudget.mydomain.com
points to192.168.0.4
which is the IP of my TrueNAS box and thus goes Nginx which is setup to listen on the 443/80 ports.
- Joins
- Bunch of services that I only access via Tailscale or when at home
- ActualBudget, Changedetection, etc.
- Joins
frontend
network. - Added to NPM and Adguard Home for easy local access via domain.
- Joins
- ActualBudget, Changedetection, etc.
- Service(s) that I want to expose to the internet
- Picoshare
- Joins
frontend
network. - Bind mount to
/mnt/pool_o/Apps/picoshare/data
- Added to NPM as
share.mydomain.com
- Using a bunch of extra headers to get A+ rating on
https://securityheaders.com/
- Using it’s own Let’s Encrypt cert instead of the wildcard one.
- Using a bunch of extra headers to get A+ rating on
- Instead of local DNS rewrite, this is added to Cloudflare DNS as an A record.
- Btw, I can’t use Cloudflare DNS Proxy, because I believe Cloudflare prohibits using it for file sharing in it’s terms of service. I tried it anyway, but the transfer speeds were terrible.
- Joins
- Picoshare
- Nginx Proxy Manager, used for reverse proxying
Now, my concerns
When I setup Portainer as an ix-application, I believe it runs as a root user instead of Apps by default. I can’t easily change it to anything else either because there simply is no setting to change it in the deployment UI in Scale.
(Maybe it could be possible by messing with the template compose-file? But I feel like that would easily stop Portainer from working.)
I have also kept the /mnt/pool_0/Apps/*
datasets ACL very simple. Basically root has full control to all of them.
My concern is that what if a bad actor finds a vulnerability in picoshare (or anything else I might want to expose to the public), is it possible for the actor to then escape the container and access the bind mounts in the dataset, and then execute malicious scripts on my TrueNAS server? Or just traverse elsewhere in my system? Or I imagine just getting access to Portainer would be pretty bad.
This is where my lack of knowledge comes to full display. I’m not sure if this attack vector is even a possibility.
How could I mitigate these concerns if it is? Is it possible to change which user Portainer runs as? If not, can I then create some ACL, or whatever privileges, inside Portainer and then perhaps mirror them to the datasets to limit the risk of a vulnerable service risking my whole system?
Any help would be appreciated. I fully assume I’m missing some critical noob knowledge.