Skip to content

feat: add nginx reverse proxy to docker-compose#423

Merged
cameri merged 2 commits intocameri:mainfrom
kanishka0411:feat/nginx-docker-compose
Apr 10, 2026
Merged

feat: add nginx reverse proxy to docker-compose#423
cameri merged 2 commits intocameri:mainfrom
kanishka0411:feat/nginx-docker-compose

Conversation

@kanishka0411
Copy link
Copy Markdown
Contributor

Description

Added an nginx reverse proxy with Let's Encrypt SSL as an optional docker-compose overlay. It follows the same pattern as the tor setup-separate compose file, separate start script, doesn't touch the main start flow.

Related Issue

Fixes #36

Motivation and Context

Operators need a reverse proxy for TLS, NIP-05, etc. This gives a ready-to-go nginx + certbot setup without getting in the way of people who already run their own proxy.

How Has This Been Tested?

  • Script syntax validated with bash -n
  • Compose config merge validated with docker compose config
  • Full ACME flow needs a public domain so couldn't test that locally, would appreciate help testing if possible

Screenshots (if appropriate):

Types of changes

  • Non-functional change (docs, style, minor refactor)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my code changes.
  • All new and existing tests passed.

volumes:
- ${PWD}/nginx/ssl:/etc/letsencrypt
- certbot-webroot:/var/www/certbot
entrypoint: >
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be an entrypoint script instead so that we can keep the compose file neat and tidy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Moved it to scripts/certbot_entrypoint.sh :-)

Comment on lines +212 to 215
or, with Nginx reverse proxy and Let's Encrypt SSL:
```
COMPOSE_FILE=docker-compose.yml:docker-compose.windows.yml
RELAY_DOMAIN=relay.example.com CERTBOT_EMAIL=you@example.com ./scripts/start_with_nginx
```
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an optional Docker Compose overlay that runs Nostream behind an nginx reverse proxy with automated Let’s Encrypt (certbot) TLS, intended to support operator needs like TLS termination and NIP-05 without changing the default startup flow.

Changes:

  • Added docker-compose.nginx.yml defining nginx + certbot services and shared volumes for ACME webroot and certificates.
  • Added scripts/start_with_nginx to generate nginx config, bootstrap a temporary cert, and start the merged compose stack.
  • Updated README quick-start instructions to document the new nginx startup option.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 9 comments.

File Description
scripts/start_with_nginx New startup script to generate nginx config, bootstrap TLS files, and run compose overlay.
docker-compose.nginx.yml New compose overlay defining nginx reverse proxy and certbot issuance/renewal flow.
nginx/conf.d/nostream.conf.template New nginx vhost template for HTTP->HTTPS + websocket proxying to nostream.
README.md Documents how to start with nginx + Let’s Encrypt using env vars.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +4
#!/bin/bash
PROJECT_ROOT="$(dirname $(readlink -f "${BASH_SOURCE[0]}"))/.."
DOCKER_COMPOSE_FILE="${PROJECT_ROOT}/docker-compose.yml"
DOCKER_COMPOSE_NGINX_FILE="${PROJECT_ROOT}/docker-compose.nginx.yml"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script relies on compose files that use ${PWD} for volume mounts; since the script never cds into PROJECT_ROOT, running it from any directory other than the repo root will mount the wrong host paths. Consider cd "${PROJECT_ROOT}" (or the repo root) before invoking docker compose and/or make the directory check enforce running from the root directory.

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +71
-f $DOCKER_COMPOSE_FILE \
-f $DOCKER_COMPOSE_NGINX_FILE \
up --build --remove-orphans $@
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docker compose invocation should quote variables and forward args as "$@" to avoid word-splitting/globbing (e.g., paths with spaces or flags containing spaces). Similarly, -f arguments should be -f "${DOCKER_COMPOSE_FILE}" etc.

Suggested change
-f $DOCKER_COMPOSE_FILE \
-f $DOCKER_COMPOSE_NGINX_FILE \
up --build --remove-orphans $@
-f "${DOCKER_COMPOSE_FILE}" \
-f "${DOCKER_COMPOSE_NGINX_FILE}" \
up --build --remove-orphans "$@"

Copilot uses AI. Check for mistakes.
echo "Usage: RELAY_DOMAIN=relay.example.com CERTBOT_EMAIL=you@example.com ./scripts/start_with_nginx"
exit 1
fi

Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RELAY_DOMAIN is used to build filesystem paths and is injected into the generated nginx config; currently it’s only checked for being non-empty. To avoid accidental path traversal (e.g., values containing / or ..) and to fail fast on invalid hostnames, validate RELAY_DOMAIN against an FQDN-safe regex before using it.

Suggested change
FQDN_REGEX='^([A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$'
if [[ ! "${RELAY_DOMAIN}" =~ ${FQDN_REGEX} ]]; then
echo "Error: RELAY_DOMAIN must be a valid fully-qualified domain name."
echo "Usage: RELAY_DOMAIN=relay.example.com CERTBOT_EMAIL=you@example.com ./scripts/start_with_nginx"
exit 1
fi

Copilot uses AI. Check for mistakes.
default:

certbot:
image: certbot/certbot:latest
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using certbot/certbot:latest makes deployments non-reproducible and can introduce breaking changes unexpectedly. Pin to a specific version (or digest) so operators get predictable behavior and upgrades are explicit.

Suggested change
image: certbot/certbot:latest
image: certbot/certbot:v2.11.0

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +22
nginx -s reload;
rm -f /etc/nginx/ssl/reload-nginx;
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nginx reload watcher removes the signal file even if nginx -s reload fails, which can leave nginx serving the old/self-signed cert without another reload attempt. Consider testing config (nginx -t) and only deleting the signal file after a successful reload (or retry on failure).

Suggested change
nginx -s reload;
rm -f /etc/nginx/ssl/reload-nginx;
if nginx -t && nginx -s reload; then
rm -f /etc/nginx/ssl/reload-nginx;
fi;

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
# Nginx configuration for Nostream relay
# Replace ${RELAY_DOMAIN} with your actual domain before use
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is a template that the start script substitutes automatically; the comment suggests manual replacement, which can be confusing for operators editing it directly. Consider updating the header comment to reflect the intended workflow (script-generated config).

Suggested change
# Nginx configuration for Nostream relay
# Replace ${RELAY_DOMAIN} with your actual domain before use
# Nginx configuration template for Nostream relay
# ${RELAY_DOMAIN} is substituted automatically by the start script/deployment process

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +44
certbot certonly
--webroot
--webroot-path=/var/www/certbot
--email ${CERTBOT_EMAIL}
--agree-tos
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the certbot entrypoint, if the initial certbot certonly fails, the shell still proceeds into the infinite certbot renew loop (no set -e, and the loop isn’t gated on certonly success). This can leave nginx serving the self-signed cert indefinitely; consider exiting on certonly failure (or enabling set -e).

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +38
if [ ! -f /etc/letsencrypt/renewal/${RELAY_DOMAIN}.conf ]; then
rm -rf /etc/letsencrypt/live/${RELAY_DOMAIN};
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RELAY_DOMAIN is required but if it’s unset, Compose will substitute an empty string here and certbot will operate on /etc/letsencrypt/renewal/.conf / live/, which is easy to miss. Consider using required-variable interpolation (e.g., ${RELAY_DOMAIN:?RELAY_DOMAIN required}) to fail fast.

Copilot uses AI. Check for mistakes.
certbot certonly
--webroot
--webroot-path=/var/www/certbot
--email ${CERTBOT_EMAIL}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CERTBOT_EMAIL is required but if it’s unset, Compose will substitute an empty string and certbot will be invoked with an invalid --email value. Consider required-variable interpolation (e.g., ${CERTBOT_EMAIL:?CERTBOT_EMAIL required}) so misconfiguration fails fast.

Suggested change
--email ${CERTBOT_EMAIL}
--email ${CERTBOT_EMAIL:?CERTBOT_EMAIL required}

Copilot uses AI. Check for mistakes.
@cameri cameri merged commit 0bae0a3 into cameri:main Apr 10, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add nginx to docker-compose template

3 participants