Caddy 2 config for Ampache - rewrite rules not working for Subsonic API endpoints

1. Caddy version (caddy version):

v2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=

2. How I run Caddy:

systemd service

a. System environment:

Ubuntu 21.10 with systemd

b. Command:

sudo systemctl start caddy

c. Service/unit/compose file:

caddy.service:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

{
       debug
}

music.lycr.gs {
        root * /var/www/ampache/public

        log {
                output file /var/log/caddy/music.lycr.gs.access.log {
                        roll_keep_for  14d # days
                }
        }

        encode gzip

        php_fastcgi unix//var/run/php/php8.0-fpm.sock
        file_server

        # Rewrite rules for Subsonic backend
        @rest {
                path_regexp rest ^/rest/(.*).view$
        }
        rewrite @rest /rest/index.php?action={re.rest.1}
        @rest-fake {
                path_regexp rest-fake ^/rest/fake/(.+)$
        }
        rewrite @rest-fake /play/{re.rest-fake.1}

        # Rewrite rule for Channels
        @channel {
                path_regexp channel ^/channel/([0-9]+)/(.*)$
        }
        rewrite @channel /channel/index.php?channel={re.channel.1}&target={re.channel.2}
}

3. The problem I’m having:

Ampache supports the Subsonic API for clients to interact with it. Subsonic’s API endpoints (and the clients that interact with them) use *.view paths, while Ampache handles these under index.php with an action query parameter corresponding to the desired Subsonic action.

The rewrite rules I’ve got for Subsonic-compatible API access to Ampache don’t seem to work. I’ve attempted to convert the rewrite rules that were given for Caddy v1, but when I access the URL that a Subsonic client would use (i.e. a *.view path) I get a complaint that the request is missing parameters. When I access the URL that Ampache expects (i.e. index.php?action=[....]) I get the expected API response.

The log entry for the .view path access doesn’t show the rewritten URL - but I’m not sure if it’s supposed to. I tried turning on debug but it didn’t seem to show any more information about the rewrite rule being matched or not.

For clarity:
If I make a request to /rest/getPlaylist.view?u=[credential]&p=[credential]&v=1.2.0&c=DSub&id=400000146 I get an error.
If I make a request to /rest/index.php?action=getPlaylist&u=[credential]&p=[credential]&v=1.2.0&c=DSub&id=400000146 I get a successful response.

I just don’t know how to rewrite the former URL into the latter.

4. Error messages and/or full log output:

Prettified access log entry associated with the request I’m trying to rewrite:

{
  "level": "info",
  "ts": 1641252459.9322948,
  "logger": "http.log.access.log0",
  "msg": "handled request",
  "request": {
    "remote_addr": "49.186.76.193:31919",
    "proto": "HTTP/2.0",
    "method": "GET",
    "host": "music.lycr.gs",
    "uri": "/rest/getPlaylist.view?u=[credential]&p=[credential]&v=1.2.0&c=DSub&id=400000146",
    "headers": {
      "User-Agent": [
        "curl/7.80.0"
      ],
      "Accept": [
        "*/*"
      ]
    },
    "tls": {
      "resumed": false,
      "version": 772,
      "cipher_suite": 4865,
      "proto": "h2",
      "proto_mutual": true,
      "server_name": "music.lycr.gs"
    }
  },
  "common_log": "49.186.76.193 - - [03/Jan/2022:23:27:39 +0000] \"GET /rest/getPlaylist.view?u=[credential]&p=[credential]&v=1.2.0&c=DSub&id=400000146 HTTP/2.0\" 200 213",
  "user_id": "",
  "duration": 0.005692749,
  "size": 213,
  "status": 200,
  "resp_headers": {
    "Server": [
      "Caddy"
    ],
    "Content-Type": [
      "text/xml; charset=UTF-8"
    ],
    "Access-Control-Allow-Origin": [
      "*"
    ]
  }
}

(it gets a 200 OK back but the content is the error message below):

<subsonic-response status="failed" version="1.13.0">
  <error code="10" message="Missing Subsonic base parameters"/>
</subsonic-response>

5. What I already tried:

I’ve read through the documentation for path_regexp in an attempt to understand what the difference is between what I’ve converted from the v1 example, and what it should be - but I’m not sure what I’m missing. I’ve had a look at the route and handle directives but I don’t think I need these (I only need to do a single redirect, and I don’t need to specify the ordering or make them mutually exclusive).

6. Links to relevant resources:

Ampache’s suggested configuration for Caddy: Installation · ampache/ampache Wiki · GitHub (this is a v1 configuration which I have attempted to convert for v2)
A previous discussion of configuring Caddy for Ampache: Ampache on Caddy (nginx config convert) (I believe this is the source of Ampache’s suggested configuration)

This is embarrassing - it looks like I had it correct with the inclusion of {query} in the rewrite rule, which was my most recent change… but I hadn’t restarted Caddy to use the new config after adding that element. I had it in my head that Caddy listened for changes to its config file and would reload automatically.

Please let me know if I need to do anything to mark this topic as closed; if not I’m happy for it to be closed.

1 Like

Glad you figured it out!

After any config change, you can use sudo systemctl reload caddy to do a graceful reload (zero downtime).

Your regexp has a minor mistake, when matching a file extension like .view, the dot is read as the regexp “any be character”. You probably want to escape the dot to match a literal dot.

Also, for those matchers, you can use the single line syntax and omit the { } braces. Reads a bit shorter:

Thanks, both of those tweaks are helpful! I think I had noticed the dot in .view but left it when I saw it was the same as the sample v1 config Ampache provides…

I was going to ask if there was a way to break up longer regexes (some of the additional rewrites suggested by the Ampache config are quite large) but I think they’re probably as good as they’ll get. I might move them out into a file and import it.

Thanks again for the tips :slight_smile:

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.