# Running amanda behind an apache reverse proxy

**URL:** <https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229>\
**Category:** Get Help\
**Tags:** amanda, galaxy-ng\
**Created:** [January 30, 2026, 10:55pm UTC](https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229 "2026-01-30T22:55:47Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [January 30, 2026, 10:55pm UTC](https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229/1 "2026-01-30T22:55:47Z")

</div>

This post started off as a plea for help, but I’ve pretty much got everything working! I thought I’d pass this along in case anyone else is trying to do the same thing.

The problem is to run [https://github.com/sivel/amanda/](https://github.com/sivel/amanda/) behind an Apache httpd reverse proxy. I’ve set it up first on my local laptop which is running both Apache httpd and amanda in order to find the sharp corners before moving it onto a “for realz” httpd that’s already doing a few other internal tasks.

BTW, hitting it locally is working fantastically! (Thanks, @sivel !) I’m using the `-ui` option to get a web GUI, a custom `-port` (5001 instead of the default 5000, for reasons), and a custom `-artifacts` path.

With all that in place and `http://localhost:5001/` throwing no unpleasant surprises, the remaining task is to configure the Apache httpd server to reverse proxy the service as `http://laptop.madeup.org/amanda`. I can’t expose the custom port 5001 in the VLAN this is ultimately supposed to run in, hence the httpd proxy. And while I’m using `http` on the laptop, the “real” server has certificates, so that will be `https`.

Through trial and error, I’ve found three paths into amanda that need to be proxied: `/`, `/api`, and `/_ui`. Here’s how I’m handling that so far:

```ini
ServerName laptop.madeup.org

ProxyPassMatch "^/amanda(.*)" "http://localhost:5001$1"
ProxyPassReverse "/amanda" "http://localhost:5001"

ProxyPassMatch "^/api(.*)" "http://localhost:5001/api$1"
ProxyPassReverse "/api" "http://localhost:5001/api"

ProxyPassMatch "^/_ui(.*)" "http://localhost:5001/_ui$1"
ProxyPassReverse "/_ui" "http://localhost:5001/_ui"

AddOutputFilterByType SUBSTITUTE text/html
AddOutputFilterByType SUBSTITUTE application/json
Substitute "s|http://localhost:5001|http://laptop.madeup.org/amanda|q"

```

The `ProxyPass*` directives only alter specific headers. It’s the `Substitute` directive that “fixes” the urls contained in the `text/html` and `application/json` bodies that amanda returns.

The only part it doesn’t handle correctly is the “Copy” button to copy the install string. Also, that install string is, for example,

```plaintext
$ ansible-galaxy collection install -s http://laptop.madeup.org/ utoddl.logical==1.0.0

```

which doesn’t include the `/amanda` bit on the server parameter. Fortunately the `ansible-galaxy` command does the Right Thing™ when that part is included, like this:

```plaintext
$ ansible-galaxy collection install -s http://laptop.madeup.org/amanda utoddl.logical==1.0.0

```

I don’t do this sort of thing very often, so it took several hours longer than it should have. Writing this up wasn’t so quick either. The hope is it’ll save somebody else the time it cost me. And as always, if you have suggestions for how this could be done better, I’d love to hear them.

* * *

As a bonus, here’s the (trivial) systemd `amanda.service` file I created in the process. Cheers!

```conf
# /etc/systemd/system/amanda.service
# See https://github.com/sivel/amanda/

[Unit]
Description=Ansible Galaxy Collections v3 API endpoints
After=network.target

[Service]
Type=exec
Environment=LANG=C
User=httpd
ExecStart=/opt/local/amanda/bin/amanda -ui -artifacts=/opt/local/amanda/artifacts -port 5001

[Install]
WantedBy=multi-user.target

```

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [February 2, 2026, 4:55pm UTC](https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229/2 "2026-02-02T16:55:07Z")

</div>

It could also be a bug in the UI, that is not outside the realm of possibility. I don’t have the UI running behind a proxy currently, only the API. I can attempt to take a look later.

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [February 2, 2026, 5:38pm UTC](https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229/3 "2026-02-02T17:38:41Z")

</div>

Ok, there were a couple of issues that could be addressed, and I’ve pushed them and new binaries are built:

> **[Amanda Downloads](https://sivel.github.io/amanda/)**

Here is an apache config that should work (although I only tested using caddy)

```auto
ProxyPreserveHost On
RequestHeader set X-Forwarded-Prefix "/amanda"
ProxyPass "/amanda/" "http://localhost:5000/"
ProxyPassReverse "/amanda/" "http://localhost:5000/"

```

I’ve added this info to the README as well.

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [February 2, 2026, 10:06pm UTC](https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229/4 "2026-02-02T22:06:06Z")

</div>

I’ve been trying variations on that apache httpd config with the new binary since you posted earlier today. I can get almost everything to work, but never quite all the things at the same time.

The “things” are:

- the “←Back” button at the top of the 2nd page (always works)
- the pull-down list of versions (fragile)
- the repository link under “Links” (always works)
- the “download tarball” link under “Download” (suffers from hostname identity crisis, see below)
- the “ansible-galaxy …” string under “Install” for copy-n-paste (okay if the pull-down versions are okay)
- the “Copy” button next to said string (throwing javascript errors)
- the host in the various user-facing URLs

That last one is the worst. It can be the hostname, the ipv4 address, or localhost in user facing URLs or background requests. I’ve thrown every trick I know at it. The result is the config below — the most stable I’ve found all day. Everything works with this config except the “Copy” button. (Wo0T!) It’s throwing this:

```auto
Uncaught TypeError: can't access property "writeText", navigator.clipboard is undefined
    copyInstallCmd http://tango.trailsong.org/amanda:399

```

BTW, that “Copy” button worked earlier this afternoon. There seems to be network issues with a certain cdn from which it pulls in some javascript. (Which is kind of scary if the point is to reduce our dependency on external network resources. Hmm.) Maybe that’s okay though if it only affects the UI. We’d mostly be hitting it through scripts, not browsers.

Here’s the config. For context, `192.168.254.250` is my local static ipv4 address for `tango.trailsong.org`, and I’m running amanda on port `5001` (again, because reasons).

```auto
ServerName tango.trailsong.org
<LocationMatch "^/(amanda|api|_ui)(.*)">
  SetEnvIf Request_URI "^/(amanda|api|_ui)(.*)" x_forwarded_prefix=$1
  RequestHeader set X-Forwarded-Prefix /%{x_forwarded_prefix}e
  RequestHeader set Host tango.trailsong.org
  Header set Access-Control-Allow-Origin: *
  ProxyPreserveHost On
  ProxyPassMatch "http://localhost:5001$2"
  ProxyPassReverse "http://localhost:5001"
  AddOutputFilterByType SUBSTITUTE text/html
  AddOutputFilterByType SUBSTITUTE application/json
  Substitute "s|http://localhost:5001|http://tango.trailsong.org/%{x_forwarded_prefix}e|iq"
  Substitute "s|http://192.168.254.250|http://tango.trailsong.org|iq"
</LocationMatch>

```

Leaving out any of those things breaks _something_ in the above “things” list. Or at least it seems that way to me. I’ve reloaded variations on the above 62 times this afternoon and my brain is fried. I would have thought `ProxyPreserveHost On` would fix a lot, but the `Host` request header was often the ipv4 address rather than `tango.trailsong.org`. I’m going to quit banging my head to let the wall recover. It’s good enough to use as is; **it’s definitely better after your changes earlier today,** so thanks for that. If you’d like me to test something specific with this setup, ask away. But I’m taking a break for a while.

Thanks again for making this available.

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [February 3, 2026, 9:39pm UTC](https://forum.ansible.com/t/running-amanda-behind-an-apache-reverse-proxy/45229/5 "2026-02-03T21:39:56Z")

</div>

The copy button only works on localhost or HTTPS, so instead of complicating the code, it’ll only be shown in those scenarios. Otherwise, manual selection and copying is required.

Your config also still seems a bit complicated, I’ve tried to update the example in the readme to be a bit more simple as well. I’m no longer the apache expert I was 20 years ago, so that’s about the best I can do for now.
