Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - amichel

#1
No I was at 26.10.
But all Solved now, I tried it again from the console and it worked like a charm.'
thank you all for your help and the inputs
#2
Hi,
during the update the kernel will not be installed as the upgrade is stuck with the message
Starting web GUI...done.

Any ideas where to look at?
#3
I "fixed" it by using the ACME plugin on the truenas scale box. I am using easydns as provider and decided to go for a script to set the DNS records. after some fiddling I was able to get that working.
#!/bin/sh

# ============================================================
# TrueNAS SCALE ACME Shell Authenticator for easyDNS
#
# Script:
#   /mnt/Pool/Scripts/ACME/acmedns.sh
#
#:
#
# TrueNAS-Format:
#   acmedns.sh set   scale.domain.com _acme-challenge.scale.domain.com TOKEN
#   acmedns.sh unset scale.domain.com _acme-challenge.scale.domain.com TOKEN
#
# Fallback-Format:
#   acmedns.sh set   _acme-challenge.scale.domain.com TOKEN
#   acmedns.sh unset _acme-challenge.scale.domain.com TOKEN
# ============================================================

set -eu

LOG_DIR="/mnt/Pool/Scripts/ACME"
LOG_FILE="${LOG_DIR}/acmedns.log"
MAX_LOG_BYTES=$((1024 * 1024))

API_BASE="https://rest.easydns.net"
EASYDNS_DOMAIN="domain.com"
EASYDNS_TTL=300

EASYDNS_TOKEN_FILE="/mnt/Pool/Scripts/ACME/easydns.token"
EASYDNS_KEY_FILE="/mnt/Pool/Scripts/ACME/easydns.key"

PROPAGATION_SLEEP=60

mkdir -p "$LOG_DIR"

rotate_log_if_needed() {
  if [ -f "$LOG_FILE" ]; then
    size="$(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)"
    if [ "$size" -gt "$MAX_LOG_BYTES" ]; then
      : > "$LOG_FILE"
    fi
  fi
}

log() {
  echo "[$(date '+%F %T')] $*" >> "$LOG_FILE"
}

fail() {
  log "ERROR: $*"
  exit 1
}

rotate_log_if_needed

[ -f "$EASYDNS_TOKEN_FILE" ] || fail "Missing EasyDNS token file: $EASYDNS_TOKEN_FILE"
[ -f "$EASYDNS_KEY_FILE" ] || fail "Missing EasyDNS key file: $EASYDNS_KEY_FILE"

EASYDNS_TOKEN="$(tr -d '\r\n' < "$EASYDNS_TOKEN_FILE")"
EASYDNS_KEY="$(tr -d '\r\n' < "$EASYDNS_KEY_FILE")"

[ -n "$EASYDNS_TOKEN" ] || fail "EasyDNS token file is empty"
[ -n "$EASYDNS_KEY" ] || fail "EasyDNS key file is empty"

record_to_host() {
  record="$1"

  # trailing dot entfernen und lowercase
  record="$(printf '%s' "$record" | sed 's/\.$//' | tr '[:upper:]' '[:lower:]')"

  case "$record" in
    *."$EASYDNS_DOMAIN")
      printf '%s\n' "${record%.$EASYDNS_DOMAIN}"
      ;;
    "$EASYDNS_DOMAIN")
      printf '%s\n' "@"
      ;;
    *)
      fail "Challenge record '$record' is not inside zone '$EASYDNS_DOMAIN'"
      ;;
  esac
}

json_body_for_add() {
  host="$1"
  token="$2"

  python3 - "$host" "$EASYDNS_DOMAIN" "$EASYDNS_TTL" "$token" <<'PY'
import sys, json

host = sys.argv[1]
domain = sys.argv[2]
ttl = int(sys.argv[3])
token = sys.argv[4]

body = {
    "host": host,
    "domain": domain,
    "ttl": ttl,
    "prio": 0,
    "type": "txt",
    "rdata": token,
}

print(json.dumps(body, separators=(",", ":")))
PY
}

api_get_records() {
  curl -fsS \
    -u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
    --connect-timeout 15 \
    --max-time 60 \
    "${API_BASE}/zones/records/all/${EASYDNS_DOMAIN}?format=json"
}

api_add_txt() {
  body="$1"

  curl -fsS \
    -u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
    -X PUT \
    --connect-timeout 15 \
    --max-time 60 \
    -H "Content-Type: application/json" \
    -d "$body" \
    "${API_BASE}/zones/records/add/${EASYDNS_DOMAIN}/txt?format=json"
}

api_delete_record() {
  id="$1"

  log "Trying DELETE with confirm body for id=$id"

  if curl -fsS \
    -u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
    -X DELETE \
    --connect-timeout 15 \
    --max-time 60 \
    -H "Content-Type: application/json" \
    -d '{"confirm":"DELETE"}' \
    "${API_BASE}/zones/records/${EASYDNS_DOMAIN}/${id}?format=json" >> "$LOG_FILE" 2>&1; then
    log "DELETE with confirm body succeeded for id=$id"
    return 0
  fi

  log "DELETE with confirm body failed for id=$id, trying fallback DELETE without body"

  curl -fsS \
    -u "${EASYDNS_TOKEN}:${EASYDNS_KEY}" \
    -X DELETE \
    --connect-timeout 15 \
    --max-time 60 \
    "${API_BASE}/zones/records/${EASYDNS_DOMAIN}/${id}?format=json" >> "$LOG_FILE" 2>&1

  log "Fallback DELETE succeeded for id=$id"
}

find_txt_record_ids() {
  host="$1"
  token="${2:-}"
  records_json="$3"

  printf '%s' "$records_json" | python3 - "$host" "$token" <<'PY'
import sys, json

host = sys.argv[1].lower()
token = sys.argv[2]

try:
    data = json.load(sys.stdin)
except Exception as e:
    print(f"JSON_ERROR:{e}", file=sys.stderr)
    sys.exit(2)

for r in data.get("data", []):
    rtype = str(r.get("type", "")).lower()
    rhost = str(r.get("host", "")).lower()

    rrdata = r.get("rdata", r.get("rData", ""))
    rrdata = str(rrdata).strip()
    rrdata_unquoted = rrdata.strip("\"")

    if rtype == "txt" and rhost == host:
        if not token or rrdata == token or rrdata_unquoted == token:
            rid = r.get("id")
            if rid is not None:
                print(rid)
PY
}

delete_txt_record() {
  host="$1"
  token="${2:-}"

  log "Searching TXT records for host=$host token=${token:-none}"

  records_json="$(api_get_records)"
  log "easyDNS records fetched"

  ids="$(find_txt_record_ids "$host" "$token" "$records_json" || true)"

  if [ -z "$ids" ] && [ -n "$token" ]; then
    log "No TXT record found with exact token. Searching again by host only."
    ids="$(find_txt_record_ids "$host" "" "$records_json" || true)"
  fi

  if [ -z "$ids" ]; then
    log "No matching TXT record found for host=$host"
    return 0
  fi

  echo "$ids" | while IFS= read -r id; do
    [ -z "$id" ] && continue
    log "Deleting TXT record host=$host id=$id"
    api_delete_record "$id"
    log "Delete completed for TXT record id=$id"
    sleep 2
  done
}

set_record() {
  challenge_fqdn="$1"
  token="$2"

  host="$(record_to_host "$challenge_fqdn")"

  log "SET requested"
  log "Challenge FQDN=$challenge_fqdn"
  log "Zone=$EASYDNS_DOMAIN"
  log "Host=$host"

  delete_txt_record "$host" "$token" || true

  body="$(json_body_for_add "$host" "$token")"

  log "Adding TXT record host=$host ttl=$EASYDNS_TTL"
  api_add_txt "$body" >> "$LOG_FILE" 2>&1
  log "TXT record added for host=$host"

  log "Waiting ${PROPAGATION_SLEEP}s for DNS propagation"
  sleep "$PROPAGATION_SLEEP"

  log "SET completed"
}

unset_record() {
  challenge_fqdn="$1"
  token="${2:-}"

  host="$(record_to_host "$challenge_fqdn")"

  log "UNSET requested"
  log "Challenge FQDN=$challenge_fqdn"
  log "Zone=$EASYDNS_DOMAIN"
  log "Host=$host"
  log "Token=${token:-none}"

  delete_txt_record "$host" "$token"

  log "UNSET completed"
}

# ------------------------------------------------------------
# Parameter Parsing
# ------------------------------------------------------------
mode="${1:-}"

arg2="${2:-}"
arg3="${3:-}"
arg4="${4:-}"

domain_fqdn=""
challenge_fqdn=""
txt_token=""

log "============================================================"
log "Raw args: mode='${mode:-}' arg2='${arg2:-}' arg3='${arg3:-}' arg4='${arg4:-}'"

case "$mode" in
  set)
    case "$arg2" in
      _acme-challenge*)
        # Fallback-Format:
        # set challenge token
        challenge_fqdn="$arg2"
        txt_token="$arg3"
        ;;
      *)
        # TrueNAS-Format:
        # set domain challenge token
        domain_fqdn="$arg2"
        challenge_fqdn="$arg3"
        txt_token="$arg4"
        ;;
    esac

    [ -n "$challenge_fqdn" ] || fail "Missing challenge FQDN argument"
    [ -n "$txt_token" ] || fail "Missing TXT token argument"

    set_record "$challenge_fqdn" "$txt_token"
    ;;

  unset)
    case "$arg2" in
      _acme-challenge*)
        # Fallback-Format:
        # unset challenge token
        challenge_fqdn="$arg2"
        txt_token="$arg3"
        ;;
      *)
        # TrueNAS-Format:
        # unset domain challenge token
        domain_fqdn="$arg2"
        challenge_fqdn="$arg3"
        txt_token="$arg4"
        ;;
    esac

    [ -n "$challenge_fqdn" ] || fail "Missing challenge FQDN argument"

    unset_record "$challenge_fqdn" "$txt_token"
    ;;

  *)
    fail "Unknown mode '$mode'. Expected 'set' or 'unset'."
    ;;
esac

exit 0

and then use this script when requesting the certificate. The only thing that is not working is the automatic cleanup of the DNS recored, therefore I created this script:'
#!/bin/sh

set -eu

LOG_DIR="/mnt/Pool/Scripts/ACME"
LOG_FILE="${LOG_DIR}/cleanup-acme-txt.log"

API_BASE="https://rest.easydns.net"
EASYDNS_DOMAIN="domain.com"

EASYDNS_TOKEN_FILE="/mnt/Pool/Scripts/ACME/easydns.token"
EASYDNS_KEY_FILE="/mnt/Pool/Scripts/ACME/easydns.key"

DRY_RUN=0

if [ "${1:-}" = "--dry-run" ]; then
  DRY_RUN=1
fi

mkdir -p "$LOG_DIR"

log() {
  echo "[$(date '+%F %T')] $*" | tee -a "$LOG_FILE"
}

fail() {
  log "ERROR: $*"
  exit 1
}

[ -f "$EASYDNS_TOKEN_FILE" ] || fail "Token file missing: $EASYDNS_TOKEN_FILE"
[ -f "$EASYDNS_KEY_FILE" ] || fail "Key file missing: $EASYDNS_KEY_FILE"

EASYDNS_TOKEN="$(tr -d '\r\n' < "$EASYDNS_TOKEN_FILE")"
EASYDNS_KEY="$(tr -d '\r\n' < "$EASYDNS_KEY_FILE")"

[ -n "$EASYDNS_TOKEN" ] || fail "Token file is empty"
[ -n "$EASYDNS_KEY" ] || fail "Key file is empty"

TMP_RECORDS="$(mktemp)"
TMP_IDS="$(mktemp)"

cleanup_tmp() {
  rm -f "$TMP_RECORDS" "$TMP_IDS"
}

trap cleanup_tmp EXIT INT TERM

log "============================================================"
log "Starting ACME TXT cleanup for zone: $EASYDNS_DOMAIN"

if [ "$DRY_RUN" -eq 1 ]; then
  log "Mode: DRY-RUN - nothing will be deleted"
else
  log "Mode: DELETE - matching records will be deleted"
fi

to run this once a week to clean up the old records. It is not as smart as centralizing the task from opnsense but it does the job.
#4
Looks like an automation rule is not recognized. When you take a look at the automation rules is there one defined for the sftp upload? Has that eventually been removed?
#5
Did you verify the AD replication? Might be that there are some lingering objects and users exist on one DC but not on the other.
#6
I am using a low level option. Have a 5G connection with the ISP Modem in bridge mode. I am using a WLAN Power plug with Tasmota and can then programmatically send a web request to it to turn the Modem on and off (had to refer to IT Crowd) and then get a new IP.
#7
In case you do not want to change the Port the firewall is listening.
I created a VIP (10.1.1.1) and since the FW website should not be available on the WAN I redirected Port 443 on the WAN side to the VIP on Port 40443 (or any other port).
Then all you need to do is to configure the reverse proxy (I use Nginx) to listen on 10.1.1.1:40443 and proxy the bits back to the Webserver in the LAN on Port 443.

This https://github.com/opnsense/plugins/issues/722
redirected me to my solution
#8
Just an Idea,
did you create a rule to allow traffic go through the interface? IIRC per default there isn't any so all traffic will be blocked.
https://docs.opnsense.org/manual/how-tos/wireguard-client.html
#9
In case you run Opnsense on ZFS you could simply create a snapshot of the system before upgrading. Then you should be able to revert to the previous config easily.
I do that and additionally since my Opnsense runs on top of a Proxmox machine I use the backup feature of Proxmox to backup and recover.
#10
I am aware, but fact is that until the upgrade it worked out of the box assigning to the clients the KEA assigned IP as GW and DNS server. And Unbound in my case was listening on those interfaces.
This was then not working after the upgrade.
However I tried the upgrade again and it works now.
Thanks for the help.
#11
After Upgrading to 25.1.11 I realized that Kea DHCP Server still assigns IP Adresses, but DNS is no longer available. I did not add any extra DHCP options so the Gatway and the DNS Server is the IPadress assigned to the KEA interface on that specific VLAN.
Could not test any further as I need the environment up and running and decided to revert the snapshot.
Anyone had similar experiences?
Andreas
#12
Hi,
just to be  on the safe side, did you create rules to allow the traffic between the nets? Per default IIRC the firewall will block al traffic.
#13
I think someone from the team already fixed that.
I just searched for updates and there is a new Postfix release available.
Updated it --> all is fine.

Thank you!
#14
After the upgrade to 25.1.2 postfix does not start anymore.

In the Log I only see:

28cafc05-69bf-4067-8fa6-be5124013484] Script action failed with Command 'postmap /usr/local/etc/postfix/transport ' returned non-zero exit status 1. at Traceback (most recent call last): File "/usr/local/opnsense/service/modules/actions/script_output.py", line 78, in execute subprocess.check_call(script_command, env=self.config_environment, shell=True, File "/usr/local/lib/python3.11/subprocess.py", line 413, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command 'postmap /usr/local/etc/postfix/transport ' returned non-zero exit status 1.


Any help is appreiciated.
#15
Quote from: rudiservo on January 31, 2025, 01:00:31 PMIs it safe for those that have external DB?

I can only share that for me, using an external elastic database it works without problems. But I have to admit I am a home user and I can rebuild the box easily (proxmox snapshot).
So in case you use opnsense on a business relevant machine I would recommend waiting for an official announcement.