[Unit] Description=Expose millenia's vLLM chat server on the headscale interface only # Why a forwarder instead of just rebinding vLLM: vllm-chat.service is shared. # Petal, Gogobee and Open WebUI all talk to 127.0.0.1:8000, and Open WebUI keeps # its endpoint in its own database rather than in env, so moving vLLM's bind # address would mean editing three consumers and reloading a 35B AWQ model # (minutes of downtime for all of them). This adds a second door instead: local # callers keep loopback untouched, and only the headscale address gains a # listener. Nothing about vllm-chat changes. # # Deliberately NOT 0.0.0.0 — this reaches a public VPS over the VPN, and the # LAN has no business seeing an unauthenticated inference endpoint. After=network-online.target tailscaled.service vllm-chat.service Wants=network-online.target BindsTo=vllm-chat.service [Service] Type=simple # fork: one child per connection, so a single client can't block the others. # reuseaddr: survive a restart while sockets are still in TIME_WAIT. # The bind address is millenia's headscale IP; if tailscaled hasn't brought the # interface up yet the bind fails and Restart retries until it has. ExecStart=/usr/bin/socat -d TCP-LISTEN:8000,bind=100.64.0.2,fork,reuseaddr TCP:127.0.0.1:8000 Restart=always RestartSec=5 # Long generations hold a connection open; don't let systemd reap a healthy one. TimeoutStopSec=10 # The process only shuttles bytes between two sockets — give it nothing else. NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ProtectKernelTunables=true ProtectControlGroups=true RestrictAddressFamilies=AF_INET AF_INET6 DynamicUser=true [Install] WantedBy=multi-user.target