Securing a CUPS Print Server Admin Web Console?

I'm trying to set up a standalone CUPS print server in a dedicated printer VLAN, where the admin web interface is only accessible via a Ziti service routing to port 631. I’ve configured the Ziti bind policy to route traffic to 127.0.0.1 on port 631 and am running the CUPS server as standalone, so it only listens on localhost.

The problem is that CUPS checks the Host header in requests. It expects localhost but instead sees factory-printers-cups.ziti, and then it rejects the request with an error:

E [07/Nov/2024:09:58:39 -0600] [Client 282] Request from "localhost" using invalid Host: field "factory-printers-cups.ziti".

I tried modifying the /etc/hosts file to include the ziti domain, but this didn't seem to work either.

127.0.0.1   localhost factory-printers-cups.ziti

Instead of running it as local standalone, I could enable the remote printing and remote admin features with:

sudo cupsctl --remote-admin

But then it's insecure so I'd need to set up additional firewall rules to block direct traffic on port 631. Plus, it'd be nice to not have to specify a static IP (I have a printnode client running on this server, so I don't need any users to connect to it).

Using OpenZiti’s offloading to localhost would be perfect if it could keep the Host header as localhost as well. Is there a way to configure the Ziti service so that it rewrites the Host header to localhost when offloading to 127.0.0.1? Or, any other suggestions on how to handle this kind of setup without opening up additional network exposure?

The only other solution I can think of is spinning up an nginx server and modifying the header, and make the ziti service offload onto the nginx port, but it feels like overkill.
server {
listen 8631; # NGINX listens on this port
server_name factory-printers-cups.ziti;

location / {
    proxy_pass http://127.0.0.1:631;  # Forward to CUPS on port 631
    proxy_set_header Host localhost;  # Rewrite Host header to 'localhost'
}

}

Any advice or recommendations would be much appreciated if there's a way to do this with ziti alone!

Hi and thanks for the great question! It seems like this problem comes up a lot for people who try to tunnel cups. The OpenZiti tunnelers are strictly creatures of tcp/ip and udp, so they can’t see or influence the application layer protocol that’s being tunneled.

Have you tried the ServerName / ServerAlias cupsd.conf settings mentioned by Lionel in this thread?

Thank you for that link, it looks like its from 2010 and I tried the following CUPS config header:

LogLevel debug
PageLogFormat
MaxLogSize 0
ErrorPolicy retry-job

Listen localhost:631
Listen /run/cups/cups.sock
Browsing On
BrowseLocalProtocols dnssd
DefaultAuthType Basic
WebInterface Yes
ServerName factory-printers-cups.ziti
ServerAlias factory-printers-cups.ziti

But unfortunately after reloading the daemon and restarting the cups service, and rerouting the ziti service to 631 directly, I got the same errors. Either I don't understand CUPS configurations well enough to know why this didn't work per the linked solution, or its outdated and no longer works with CUPS.

I can confirm that my solution using nginx as a reverse proxy to port 631 and rewriting the headers in the proxy pass does in fact work great, so I'm going to go with that.

Glad you got it working! I had wondered if you could use an IP address. IP's are more fragile in a lot of ways so it might not work out but that's possibly a different approach... Then again, it's hard to be "a working solution". :slight_smile:

cheers

1 Like