design.md 1.6 KB

Context

The trojan-go service runs as the trojan user (non-root) and needs to: (1) read TLS cert/key files from /etc/letsencrypt/, (2) bind to port 443. Currently, cert files are owned by root with restrictive permissions, and the systemd unit only uses AmbientCapabilities without CapabilityBoundingSet.

Goals / Non-Goals

Goals:

  • Ensure the trojan user can read the TLS certificate and key files
  • Ensure CAP_NET_BIND_SERVICE is properly granted to the trojan-go process
  • Maintain certbot auto-renewal with correct permission propagation

Non-Goals:

  • Change the trojan-go binary or version
  • Replace certbot with a different certificate solution

Decisions

Copy cert files to a trojan-owned directory instead of changing /etc/letsencrypt permissions

Changing the entire /etc/letsencrypt tree to be readable by the trojan user is a security concern. Instead, copy the cert and key to /etc/trojan-go/tls/ owned by the trojan user after each certbot renewal. This keeps the Let's Encrypt directory locked down while giving trojan exactly what it needs.

Add CapabilityBoundingSet alongside AmbientCapabilities

AmbientCapabilities alone may not be sufficient on all systems. Adding CapabilityBoundingSet ensures the capability is available to the process even when the bounding set is restricted.

Risks / Trade-offs

  • [Cert copy lag on renewal] → The certbot --deploy-hook copies certs after renewal, so there's a brief window where trojan serves the old cert. Mitigation: the hook reloads trojan after copying.
  • [Extra disk I/O] → Negligible — two small PEM files copied per renewal.