Skip to content

Reverse proxy and HTTPS

aseStack's default production listener is:

127.0.0.1:15173

Keep that listener private and publish the dashboard through a reverse proxy at https://control.example.com. The proxy terminates TLS, preserves the original host and scheme, and forwards requests to the local listener.

HTTPS is required for production passkeys and matches the default secure-cookie setting.

Before you start

Confirm that:

  • control.example.com resolves to the reverse-proxy host;
  • inbound TCP 80 and 443 reach the proxy;
  • local port 15173 is not exposed publicly; and
  • the controller is healthy locally.
curl -fsS http://127.0.0.1:15173/api/v1/health

Controller settings

When aseStack was installed with ASESTACK_PUBLIC_URL=https://control.example.com, the installer included both the public and direct origins in the initial trusted-origin set.

For an existing installation, check these values in /etc/asestack/asestack.env:

ASESTACK_ADDR=127.0.0.1:15173
ASESTACK_PUBLIC_URL=https://control.example.com
ASESTACK_SECURE_COOKIES=true
ASESTACK_TRUSTED_ORIGINS=https://control.example.com,http://127.0.0.1:15173

After editing the environment file, restart the controller:

sudo systemctl restart asestack

Keep ASESTACK_TRUSTED_ORIGINS limited to actual administration origins. Do not add wildcard origins.

Option A: Caddy

Caddy is the shortest configuration when the controller is directly reachable on ports 80 and 443:

control.example.com {
    reverse_proxy 127.0.0.1:15173
}

Caddy obtains and renews the certificate and supplies the normal forwarded headers automatically. Reload Caddy after validating its configuration.

Option B: Nginx Proxy Manager

Create a Proxy Host with:

Field Value
Domain Names control.example.com
Scheme http
Forward Hostname / IP 127.0.0.1
Forward Port 15173
Websockets Support Enabled

On the SSL tab, request or select the certificate, enable Force SSL, and save the host.

Add the following in the proxy host's advanced configuration so long-lived monitoring responses are not buffered and enrollment URL generation sees the public origin:

proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 3600s;

Option C: Nginx

The following server blocks preserve the headers used for secure cookies, callback URLs, audit IPs, and generated enrollment URLs. Replace the certificate paths with the files created by your ACME client.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name control.example.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name control.example.com;

    ssl_certificate     /etc/letsencrypt/live/control.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/control.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:15173;
        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_buffering off;
        proxy_read_timeout 3600s;
    }
}

Validate before reloading:

sudo nginx -t
sudo systemctl reload nginx

Verify the public origin

Check the public health endpoint and response headers:

curl -fsS https://control.example.com/api/v1/health
curl -I https://control.example.com/

Then open https://control.example.com, sign in, and leave the dashboard open long enough to confirm that live monitoring updates continue.

Confirm that the application listener is still loopback-only:

sudo ss -ltnp 'sport = :15173'

The local address should be 127.0.0.1:15173 unless you intentionally use a private remote-proxy layout.

Header behavior

These proxy details matter:

  • Host and X-Forwarded-Host identify the public controller hostname.
  • X-Forwarded-Proto: https tells aseStack that the browser used HTTPS.
  • X-Real-IP or X-Forwarded-For carries the client address used by rate limits and audit records.
  • Disabled response buffering keeps the metrics event stream responsive.

An explicit ASESTACK_PUBLIC_URL takes precedence when aseStack generates enrollment scripts. This prevents a proxy mistake from putting an internal address into a sensitive install script.

Troubleshooting

Login succeeds and then returns to the login page

Confirm that the browser is using HTTPS and the proxy sends X-Forwarded-Proto: https. Check that ASESTACK_SECURE_COOKIES=true and that the browser is not switching between hostnames.

A save or other authenticated action is rejected

Confirm that the browser origin is present in ASESTACK_TRUSTED_ORIGINS, the proxy preserves Host, and the dashboard is not being embedded or served from a second hostname.

Enrollment scripts use the wrong URL

Set Settings → Controller Settings → Controller URL to https://control.example.com, or set ASESTACK_PUBLIC_URL in the environment file and restart aseStack.

Monitoring stops updating

Disable proxy buffering and increase the proxy read timeout. aseStack's live monitoring endpoint uses a long-lived event stream.

Continue with the first-login checklist or enroll a managed server.