Skip to content

Instantly share code, notes, and snippets.

@hjbotha
Last active April 22, 2024 14:52
Show Gist options
  • Save hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7 to your computer and use it in GitHub Desktop.
Save hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7 to your computer and use it in GitHub Desktop.
Free ports 80 and 443 on Synology NAS
#! /bin/bash
# NEWLY ADDED BACKUP FUNCTIONALITY IS NOT FULLY TESTED YET, USE WITH CARE, ESPECIALLY DELETION
# Developed for DSM 6 - 7.0.1. Not tested on other versions.
# Steps to install
# Save this script in one of your shares
# Edit it according to your requirements
# Backup /usr/syno/share/nginx/ as follows:
# # cd /usr/syno/share/
# # tar cvf ~/nginx.tar nginx
# Run this script as root
# Reboot and ensure everything is still working
# If not, restore the backup and post a comment on this script's gist page
# If it did, schedule it to run as root at boot
# through Control Panel -> Task Scheduler
HTTP_PORT=81
HTTPS_PORT=444
BACKUP_FILES=true # change to false to disable backups
BACKUP_DIR=/volume1/apps/free_ports/backup
DELETE_OLD_BACKUPS=false # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS=30
DATE=$(date +%Y-%m-%d-%H-%M-%S)
CURRENT_BACKUP_DIR="$BACKUP_DIR/$DATE"
if [ "$BACKUP_FILES" == "true" ]; then
mkdir -p "$CURRENT_BACKUP_DIR"
cp /usr/syno/share/nginx/*.mustache "$CURRENT_BACKUP_DIR"
fi
if [ "$DELETE_OLD_BACKUPS" == "true" ]; then
find "$BACKUP_DIR/" -type d -mtime +$KEEP_BACKUP_DAYS -exec rm -r {} \;
fi
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)80\([^0-9]\)/\1$HTTP_PORT\2/" /usr/syno/share/nginx/*.mustache
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)443\([^0-9]\)/\1$HTTPS_PORT\2/" /usr/syno/share/nginx/*.mustache
if which synoservicecfg; then
synoservicecfg --restart nginx
else
synosystemctl restart nginx
fi
echo "Made these changes:"
diff /usr/syno/share/nginx/ $CURRENT_BACKUP_DIR 2>&1 | tee $CURRENT_BACKUP_DIR/changes.log
@agizmo
Copy link

agizmo commented Jan 2, 2022

For some reason my DS220+ running DSM 7.0.1 doesn't like the way the date is being generated. Every time I try to save I get an error saying "Connection failed. Pleased check your network settings." I've had to add single quotes around the date creation like this:
Before: DATE=$(date +%Y-%m-%d-%H-%M-%S)
After: DATE=$(date '+%Y-%m-%d-%H-%M-%S')

I don't know if this affects other DSM 7 users or if making the change would hurt DSM 6 users.

@sebastianseidel
Copy link

sebastianseidel commented Feb 21, 2022

Unfortunately not working on my DS1817+ (current version: DSM 7.0.1-42218 Update 2)
Restarting system didn't help. Script was executed new ports have been take additionally but 80 + 443 still occupied.
sudo netstat -tulpn | grep LISTEN | grep ':80 \|:443 '
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 723/nginx: worker p
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 723/nginx: worker p
tcp6 0 0 :::443 :::* LISTEN 723/nginx: worker p
tcp6 0 0 :::80 :::* LISTEN 723/nginx: worker p
Update: WebStation is installed.

Fixed: Had some "Web service portals" running inside "WebStation" that seem to block the ports from getting free.

@waschinski
Copy link

@sebastianseidel did you use the modified script provided by @flo-mic? I think his fix was taking care of your issue.

@kevindd992002
Copy link

This worked for me! Thanks.

@Synaesthesia0
Copy link

I was able to free up 80, but 443 was still being grabbed by nginx. Took me a long time to figure out the solution, simply had to uncheck the setting:
Control Panel -> Login Portal -> Uncheck/Disable "Automatically redirect HTTP connection to HTTPS for DSM desktop."

Hope this helps someone. And thanks for the original script!

@kevindd992002
Copy link

kevindd992002 commented Feb 27, 2022

@Synaesthesia0 So I applied this same fix a few days ago and I did not have to disable redirection. It just worked.

image

My SWAG listens at port 443 now with that setting enabled. Not sure why it's a different case with yours.

@tsmithscott
Copy link

@Synaesthesia0 I had the same issue, fixed by removing a record in the DSM reverse proxy - forgot it was there lol.

@thatisfree
Copy link

thatisfree commented Mar 3, 2022

it's python version for DSM7

import os
import shutil
import time

print("Start OK")

HTTP_PORT=81
HTTPS_PORT=444

NGINX = "/usr/syno/share/nginx"
MUSTACHE = ["DSM.mustache","server.mustache","WWWService.mustache"]
BACKUP_FILES = True # change to false to disable backups
BACKUP_DIR = "/volume1/sw/nginx/backup"
DELETE_OLD_BACKUPS = True # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS = 30
DATE = time.strftime("%Y-%m-%d_%H-%M-%S")
CURRENT_BACKUP_DIR = os.path.join(BACKUP_DIR,DATE)

for file in MUSTACHE:
    if BACKUP_FILES:
        os.makedirs(CURRENT_BACKUP_DIR, exist_ok=True)
        shutil.copy(os.path.join(NGINX,file),CURRENT_BACKUP_DIR)
        print("Backup Done")
    data = open(os.path.join(NGINX,file), 'rt').read().replace('listen 80', 'listen 81').replace('listen [::]:80','listen [::]:81').replace('listen 443','listen 444').replace('listen [::]:443', 'listen [::]:444')
    open(os.path.join(NGINX,file), 'wt').write(data)
print("Mod Done")

if not DELETE_OLD_BACKUPS:
    for f in os.listdir(BACKUP_DIR):
        f = os.path.join(BACKUP_DIR, f)
        if os.stat(f).st_mtime < time.time() - KEEP_BACKUP_DAYS * 86400:
            if os.path.isdir(f):
                shutil.rmtree(f)

#
# Perform nginx reload if running on DSM 7.X
if open('/etc.defaults/VERSION','r').read().find('majorversion="7"') != -1:
    print("Restart service")
    os.system('systemctl restart nginx')
print("All Done")

It's work for me after reboot DSM

@JVT038
Copy link

JVT038 commented Mar 11, 2022

@thatisfree I changed your code a little bit, by adding 4 variables regarding the ports, so other users can change the values easier.
Besides that, thanks for the code! It worked for me DS918+ DSM 7.0.1-42218 Update 3

import os
import shutil
import time

print("Start OK")

HTTP_PORT=81
HTTPS_PORT=444

NGINX = "/usr/syno/share/nginx"
MUSTACHE = ["DSM.mustache","server.mustache","WWWService.mustache"]
BACKUP_FILES = True # change to false to disable backups
BACKUP_DIR = "/volume1/docker/nginx/backup"
DELETE_OLD_BACKUPS = True # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS = 30
DATE = time.strftime("%Y-%m-%d_%H-%M-%S")
CURRENT_BACKUP_DIR = os.path.join(BACKUP_DIR,DATE)
NEW_HTTP_PORT=79
OLD_HTTP_PORT=80
NEW_HTTPS_PORT=444
OLD_HTTPS_PORT=443

for file in MUSTACHE:
    if BACKUP_FILES:
        os.makedirs(CURRENT_BACKUP_DIR, exist_ok=True)
        shutil.copy(os.path.join(NGINX,file),CURRENT_BACKUP_DIR)
        print("Backup Done")
    data = open(os.path.join(NGINX,file), 'rt').read().replace('listen 80', 'listen 81').replace('listen [::]:80',f'listen [::]:{NEW_HTTP_PORT}').replace('listen 443',f'listen {NEW_HTTPS_PORT}').replace('listen [::]:443', F'listen [::]:{NEW_HTTPS_PORT}')
    open(os.path.join(NGINX,file), 'wt').write(data)
print("Mod Done")

if not DELETE_OLD_BACKUPS:
    for f in os.listdir(BACKUP_DIR):
        f = os.path.join(BACKUP_DIR, f)
        if os.stat(f).st_mtime < time.time() - KEEP_BACKUP_DAYS * 86400:
            if os.path.isdir(f):
                shutil.rmtree(f)

#
# Perform nginx reload if running on DSM 7.X
if open('/etc.defaults/VERSION','r').read().find('majorversion="7"') != -1:
    print("Restart service")
    os.system('systemctl restart nginx')
print("All Done")

@kevindd992002
Copy link

@thatisfree what do you mean by "it's python version" for DSM7? I used the original code on my DS1817+ DSM7 and it seems to be working fine so I want to understand what is wrong with it and what improvements you made?

@JVT038 since you added new variables, you should remove the old ones as they're no longer being used in the code:

HTTP_PORT=81
HTTPS_PORT=444

@JVT038
Copy link

JVT038 commented Mar 12, 2022

Oops yeah, forgot about those 2 vars, my bad

@cocoonkid
Copy link

cocoonkid commented Apr 1, 2022

@thatisfree thanks for the original work.
@JVT038 Thank you so much for producing a python version. You saved me the exercise :)

Works like a charm with python3.8 on my Synology DS916+.

Extremely happy I just needed that today and here it is done just 3 weeks ago! You ROCK!

@inogueira82
Copy link

Hi all!

I've had this script runningin my ds918+ with dsm7 and the drive where it was stored (with the backups) crashed.

Now i Want/need to access DSM at ports 80/433 but they don't work anymore. I can access by ports 5000 and 5011..

Is there anything I can do?

Thank you

@tsmithscott
Copy link

Hi all!

I've had this script runningin my ds918+ with dsm7 and the drive where it was stored (with the backups) crashed.

Now i Want/need to access DSM at ports 80/433 but they don't work anymore. I can access by ports 5000 and 5011..

Is there anything I can do?

Thank you

You could change the values of the port variables in the script so it changes them to 80/443.

@danielstorch
Copy link

The script did not work for me. After executing it there where 3 files that changed: server.mustache, WWWService.mustache, DSM.mustache.
The ports 80 and 443 are still not available. They still redirect to the DSM login page running on port 5000. Reboot didn't work either.

Here my setup:
DS920+
DSM 7.0.1-42218 Update 3

Also why do i need to add the script as a scheduled task which runs at boot-up? After restarting my synology diskstaion, the changes in those files where still there.

@bruvv
Copy link

bruvv commented May 2, 2022

@danielstorch because after an update of DSM those changes will be reverted. Can you try and run this command: sudo systemctl restart nginx this will restart the whole nginx service. Reload did not work for me on DSM 7.1 maybe that also changed on Updated 3 of DSM 7.0

@danielstorch
Copy link

The redirect thing doesn't seem to be true. With firefox or safari the port 80 gives me connection failed. So the Ports seem to be free. But i still can't create a docker container using the ports?
Im trying to create a container in bridge which uses port 80 and 443.

@gertvanantwerpentno
Copy link

The most elegant solution I can imagine is the following. There is no need to change configuration files of the already running nginx server. Use the following commands to redirect incoming traffic on ports 80 and 443:

iptables -t nat -A PREROUTING -i eth+ -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth+ -p tcp --dport 443 -j REDIRECT --to-port 8443

When this is done, you can put your your new webserver on ports 8080 and 8443. The original webserver is still running on 80/443 but the traffic from outside will never reach it anymore.

@danielstorch
Copy link

For anyone who might have the same problem. After running the script the ports where free. But i couldn't create the container with the Synology UI or Portainer. I had to create the nginx container on ports 80 and 443 with Docker cli. Now it works fine.

@ZaxLofful
Copy link

ZaxLofful commented May 16, 2022

I saw, elsewhere, that someone was running this @restart.....Is that good? Should it be run more or less often possibly?

On a related note:

The most elegant solution I can imagine is the following. There is no need to change configuration files of the already running nginx server. Use the following commands to redirect incoming traffic on ports 80 and 443:

iptables -t nat -A PREROUTING -i eth+ -p tcp --dport 80 -j REDIRECT --to-port 8080 iptables -t nat -A PREROUTING -i eth+ -p tcp --dport 443 -j REDIRECT --to-port 8443

When this is done, you can put your your new webserver on ports 8080 and 8443. The original webserver is still running on 80/443 but the traffic from outside will never reach it anymore.

While this does work, for most....I am trying to free the ports up, so that I can have another application take them over. Your solutions would actually make things much worse. (for those out there trying to do the same; e.g. Traefik)

@reclaimer5146
Copy link

@thatisfree I changed your code a little bit, by adding 4 variables regarding the ports, so other users can change the values easier. Besides that, thanks for the code! It worked for me DS918+ DSM 7.0.1-42218 Update 3

import os
import shutil
import time

print("Start OK")

HTTP_PORT=81
HTTPS_PORT=444

NGINX = "/usr/syno/share/nginx"
MUSTACHE = ["DSM.mustache","server.mustache","WWWService.mustache"]
BACKUP_FILES = True # change to false to disable backups
BACKUP_DIR = "/volume1/docker/nginx/backup"
DELETE_OLD_BACKUPS = True # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS = 30
DATE = time.strftime("%Y-%m-%d_%H-%M-%S")
CURRENT_BACKUP_DIR = os.path.join(BACKUP_DIR,DATE)
NEW_HTTP_PORT=79
OLD_HTTP_PORT=80
NEW_HTTPS_PORT=444
OLD_HTTPS_PORT=443

for file in MUSTACHE:
    if BACKUP_FILES:
        os.makedirs(CURRENT_BACKUP_DIR, exist_ok=True)
        shutil.copy(os.path.join(NGINX,file),CURRENT_BACKUP_DIR)
        print("Backup Done")
    data = open(os.path.join(NGINX,file), 'rt').read().replace('listen 80', 'listen 81').replace('listen [::]:80',f'listen [::]:{NEW_HTTP_PORT}').replace('listen 443',f'listen {NEW_HTTPS_PORT}').replace('listen [::]:443', F'listen [::]:{NEW_HTTPS_PORT}')
    open(os.path.join(NGINX,file), 'wt').write(data)
print("Mod Done")

if not DELETE_OLD_BACKUPS:
    for f in os.listdir(BACKUP_DIR):
        f = os.path.join(BACKUP_DIR, f)
        if os.stat(f).st_mtime < time.time() - KEEP_BACKUP_DAYS * 86400:
            if os.path.isdir(f):
                shutil.rmtree(f)

#
# Perform nginx reload if running on DSM 7.X
if open('/etc.defaults/VERSION','r').read().find('majorversion="7"') != -1:
    print("Restart service")
    os.system('systemctl restart nginx')
print("All Done")

This had a hard coded value for replacing 80 with 81 which was causing the files to have 2 different ports in the configuration, port 81 and the NEW_HTTP_PORT value. It was reading "replace('listen 80', 'listen 81')" when it should have read "replace('listen 80',f'listen {NEW_HTTP_PORT}')". You can see it in the quote. Also removed the old HTTP_PORT and HTTPS_PORT values.

Here is the updated python script

import os
import shutil
import time

print("Start OK")

NGINX = "/usr/syno/share/nginx"
MUSTACHE = ["DSM.mustache","server.mustache","WWWService.mustache"]
BACKUP_FILES = True # change to false to disable backups
BACKUP_DIR = "/volume1/docker/nginx/backup"
DELETE_OLD_BACKUPS = True # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS = 30
DATE = time.strftime("%Y-%m-%d_%H-%M-%S")
CURRENT_BACKUP_DIR = os.path.join(BACKUP_DIR,DATE)
NEW_HTTP_PORT=79
OLD_HTTP_PORT=80
NEW_HTTPS_PORT=444
OLD_HTTPS_PORT=443

for file in MUSTACHE:
    if BACKUP_FILES:
        os.makedirs(CURRENT_BACKUP_DIR, exist_ok=True)
        shutil.copy(os.path.join(NGINX,file),CURRENT_BACKUP_DIR)
        print("Backup Done")
    data = open(os.path.join(NGINX,file), 'rt').read().replace('listen 80',f'listen {NEW_HTTP_PORT}').replace('listen [::]:80',f'listen [::]:{NEW_HTTP_PORT}').replace('listen 443',f'listen {NEW_HTTPS_PORT}').replace('listen [::]:443', F'listen [::]:{NEW_HTTPS_PORT}')
    open(os.path.join(NGINX,file), 'wt').write(data)
print("Mod Done")

if not DELETE_OLD_BACKUPS:
    for f in os.listdir(BACKUP_DIR):
        f = os.path.join(BACKUP_DIR, f)
        if os.stat(f).st_mtime < time.time() - KEEP_BACKUP_DAYS * 86400:
            if os.path.isdir(f):
                shutil.rmtree(f)

#
# Perform nginx reload if running on DSM 7.X
if open('/etc.defaults/VERSION','r').read().find('majorversion="7"') != -1:
    print("Restart service")
    os.system('systemctl restart nginx')
print("All Done")

@stevenhaddox
Copy link

stevenhaddox commented Jul 1, 2022

Got bit by the generic system event "Some web pages cannot function properly because of web server error. Please contact Tech support..." with this script running on boot after I updated to DSM 7.1 update 2 this afternoon.

I've tweaked the original script provided by the OP (with a few suggested changes in the comments since it was posted) to enable easily resetting the ports for Nginx back to the defaults expected in addition to supporting changing the defaults to custom ports (as is the default behavior). This allowed me to reset the ports back to defaults, update my packages that were failing within Package Center, and then re-enable my custom ports and free up ports 80 and 443 for Traefik as usual.

In case anyone is interested in it, here's my modified version:

#! /bin/bash
# SRC: https://gist.github.com/hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7

# NEWLY ADDED BACKUP FUNCTIONALITY IS NOT FULLY TESTED YET, USE WITH CARE, ESPECIALLY DELETION
# Developed for DSM 6 - 7.0.1. Not tested on other versions.
# Steps to install
# Save this script in one of your shares
# Edit it according to your requirements
# Backup /usr/syno/share/nginx/ as follows:
# # cd /usr/syno/share/
# # tar cvfz $DOCKER_USER_DIR/.bak/nginx.bak.tar.gz nginx
# Run this script as root
# Reboot and ensure everything is still working
# If not, restore the backup and post a comment on this script's gist page
# If it did, schedule it to run as root at boot
#   through Control Panel -> Task Scheduler

DEFAULT_HTTP_PORT=80
DEFAULT_HTTPS_PORT=443

CUSTOM_HTTP_PORT=5080  # DO NOT USE 5000 as it creates a duplicate server config block in Nginx and pukes
CUSTOM_HTTPS_PORT=5443 # DO NOT USE 5001 as it creates a duplicate server config block in Nginx and pukes

if [ "$RESET_TO_DEFAULTS" == "true" ];  then
  # Reverse the port replacement logic in the mustache files to "reset"
  HTTP_PORT_TO_REPLACE=$CUSTOM_HTTP_PORT
  HTTPS_PORT_TO_REPLACE=$CUSTOM_HTTPS_PORT
  HTTP_NEW_PORT=$DEFAULT_HTTP_PORT
  HTTPS_NEW_PORT=$DEFAULT_HTTPS_PORT
  echo "Resetting ports to default ports..."
else
  # Default behavior is to update Nginx for DSM to use ports 5000 & 50001
  HTTP_PORT_TO_REPLACE=$DEFAULT_HTTP_PORT
  HTTPS_PORT_TO_REPLACE=$DEFAULT_HTTPS_PORT
  HTTP_NEW_PORT=$CUSTOM_HTTP_PORT
  HTTPS_NEW_PORT=$CUSTOM_HTTPS_PORT
  echo "Overriding default ports..."
fi

echo "Replacing port $HTTP_PORT_TO_REPLACE with $HTTP_NEW_PORT"
echo "Replacing port $HTTPS_PORT_TO_REPLACE with $HTTPS_NEW_PORT"
echo " "


if [ "$BACKUP_FILES" == "false" ]; then
  BACKUP_FILES=false
else
  # Default to backing up all modified files
  BACKUP_FILES=true
fi

BACKUP_DIR=${HOME}/.bak/free_ports/
DELETE_OLD_BACKUPS=false # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS=365

DATE=$(date +%Y-%m-%d-%H-%M-%S)
CURRENT_BACKUP_DIR="$BACKUP_DIR/$DATE"

if [ "$BACKUP_FILES" == "true" ]; then
  mkdir -p "$CURRENT_BACKUP_DIR"
  cp -r /usr/syno/share/nginx/ "$CURRENT_BACKUP_DIR"
fi

if [ "$DELETE_OLD_BACKUPS" == "true" ]; then
  find "$BACKUP_DIR/" -type d -mtime +$KEEP_BACKUP_DAYS -exec rm -r {} \;
fi

# Replace ports as desired in mustache config files
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$HTTP_PORT_TO_REPLACE\([^0-9]\)/\1$HTTP_NEW_PORT\2/" /usr/syno/share/nginx/*.mustache
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$HTTPS_PORT_TO_REPLACE\([^0-9]\)/\1$HTTPS_NEW_PORT\2/" /usr/syno/share/nginx/*.mustache

echo "Made these changes:"
diff /usr/syno/share/nginx/ $CURRENT_BACKUP_DIR 2>&1 | tee $CURRENT_BACKUP_DIR/changes.log
echo " "

echo "[ ] Updating Nginx..."
if grep -q 'majorversion="7"' "/etc.defaults/VERSION"; then
  nginx -s reload
  echo "[✔] Nginx reloaded!"
else
  if which synoservicecfg; then
    synoservicecfg --restart nginx
  else
    synosystemctl restart nginx
  fi
  echo "[✔] Nginx restarted!"
fi

exit 0

Then you would simply invoke this with sudo as usual, but pass in an ENV variable to restore the configs to their default ports:
sudo RESET_TO_DEFAULTS=true ./free_ports.sh

@firstrecall
Copy link

Script worked good on DSM 7.0.3
Thank you

@irishj
Copy link

irishj commented Aug 18, 2022

This is exactly what I need to free up port 80/443 on my Synology box.

Thanks to all who contributed !!

@irishj
Copy link

irishj commented Sep 10, 2022

Anyone tried this on DSM 7.1-42661 Update 4 ?

Updated recently and port 443 still seems to be held by nginx

sudo netstat -tulpn | grep LISTEN | grep ':80 \|:443 '
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      15598/nginx: master 
tcp6       0      0 :::443                  :::*                    LISTEN      15598/nginx: master

@irishj
Copy link

irishj commented Sep 11, 2022

Nevermind me, I had a rogue reverse proxy entry in the DSM control panel. Removed and all good now.

@mbonne
Copy link

mbonne commented Oct 7, 2022

works a treat with - DSM 6.2.4-25556 Update 6
added to the end of script

netstat -tulpn | grep LISTEN | grep '80|443'
netstat -tulpn | grep LISTEN | grep '81|444'

@bxlouis
Copy link

bxlouis commented Nov 5, 2022

I used to run a different script which worked as well.
I changed my router from a Synology MR2200ac to a RT2600ac, with the same configuration, using a backup.
Everything works except for my Traefik2 configuration.

Running the script, I get this error which I can't figure out. Any idea? Thanks!
10.0.1.50 is my NAS local IP.

[ ] Updating Nginx...
nginx: [warn] low address bits of 10.0.1.50/24 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:2
nginx: [warn] low address bits of 10.0.1.50/24 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:2

EDIT: After removing "/24" in dsm.sspd.conf:2 the error message disappeared.

Also, my issue with Traefik was that restoring the configuration from backup did not restore the DDNS settings, just a stupid mistake.

@kevindd992002
Copy link

kevindd992002 commented Nov 7, 2022

Got bit by the generic system event "Some web pages cannot function properly because of web server error. Please contact Tech support..." with this script running on boot after I updated to DSM 7.1 update 2 this afternoon.

I've tweaked the original script provided by the OP (with a few suggested changes in the comments since it was posted) to enable easily resetting the ports for Nginx back to the defaults expected in addition to supporting changing the defaults to custom ports (as is the default behavior). This allowed me to reset the ports back to defaults, update my packages that were failing within Package Center, and then re-enable my custom ports and free up ports 80 and 443 for Traefik as usual.

In case anyone is interested in it, here's my modified version:

#! /bin/bash
# SRC: https://gist.github.com/hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7

# NEWLY ADDED BACKUP FUNCTIONALITY IS NOT FULLY TESTED YET, USE WITH CARE, ESPECIALLY DELETION
# Developed for DSM 6 - 7.0.1. Not tested on other versions.
# Steps to install
# Save this script in one of your shares
# Edit it according to your requirements
# Backup /usr/syno/share/nginx/ as follows:
# # cd /usr/syno/share/
# # tar cvfz $DOCKER_USER_DIR/.bak/nginx.bak.tar.gz nginx
# Run this script as root
# Reboot and ensure everything is still working
# If not, restore the backup and post a comment on this script's gist page
# If it did, schedule it to run as root at boot
#   through Control Panel -> Task Scheduler

DEFAULT_HTTP_PORT=80
DEFAULT_HTTPS_PORT=443

CUSTOM_HTTP_PORT=5080  # DO NOT USE 5000 as it creates a duplicate server config block in Nginx and pukes
CUSTOM_HTTPS_PORT=5443 # DO NOT USE 5001 as it creates a duplicate server config block in Nginx and pukes

if [ "$RESET_TO_DEFAULTS" == "true" ];  then
  # Reverse the port replacement logic in the mustache files to "reset"
  HTTP_PORT_TO_REPLACE=$CUSTOM_HTTP_PORT
  HTTPS_PORT_TO_REPLACE=$CUSTOM_HTTPS_PORT
  HTTP_NEW_PORT=$DEFAULT_HTTP_PORT
  HTTPS_NEW_PORT=$DEFAULT_HTTPS_PORT
  echo "Resetting ports to default ports..."
else
  # Default behavior is to update Nginx for DSM to use ports 5000 & 50001
  HTTP_PORT_TO_REPLACE=$DEFAULT_HTTP_PORT
  HTTPS_PORT_TO_REPLACE=$DEFAULT_HTTPS_PORT
  HTTP_NEW_PORT=$CUSTOM_HTTP_PORT
  HTTPS_NEW_PORT=$CUSTOM_HTTPS_PORT
  echo "Overriding default ports..."
fi

echo "Replacing port $HTTP_PORT_TO_REPLACE with $HTTP_NEW_PORT"
echo "Replacing port $HTTPS_PORT_TO_REPLACE with $HTTPS_NEW_PORT"
echo " "


if [ "$BACKUP_FILES" == "false" ]; then
  BACKUP_FILES=false
else
  # Default to backing up all modified files
  BACKUP_FILES=true
fi

BACKUP_DIR=${HOME}/.bak/free_ports/
DELETE_OLD_BACKUPS=false # change to true to automatically delete old backups.
KEEP_BACKUP_DAYS=365

DATE=$(date +%Y-%m-%d-%H-%M-%S)
CURRENT_BACKUP_DIR="$BACKUP_DIR/$DATE"

if [ "$BACKUP_FILES" == "true" ]; then
  mkdir -p "$CURRENT_BACKUP_DIR"
  cp -r /usr/syno/share/nginx/ "$CURRENT_BACKUP_DIR"
fi

if [ "$DELETE_OLD_BACKUPS" == "true" ]; then
  find "$BACKUP_DIR/" -type d -mtime +$KEEP_BACKUP_DAYS -exec rm -r {} \;
fi

# Replace ports as desired in mustache config files
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$HTTP_PORT_TO_REPLACE\([^0-9]\)/\1$HTTP_NEW_PORT\2/" /usr/syno/share/nginx/*.mustache
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$HTTPS_PORT_TO_REPLACE\([^0-9]\)/\1$HTTPS_NEW_PORT\2/" /usr/syno/share/nginx/*.mustache

echo "Made these changes:"
diff /usr/syno/share/nginx/ $CURRENT_BACKUP_DIR 2>&1 | tee $CURRENT_BACKUP_DIR/changes.log
echo " "

echo "[ ] Updating Nginx..."
if grep -q 'majorversion="7"' "/etc.defaults/VERSION"; then
  nginx -s reload
  echo "[✔] Nginx reloaded!"
else
  if which synoservicecfg; then
    synoservicecfg --restart nginx
  else
    synosystemctl restart nginx
  fi
  echo "[✔] Nginx restarted!"
fi

exit 0

Then you would simply invoke this with sudo as usual, but pass in an ENV variable to restore the configs to their default ports: sudo RESET_TO_DEFAULTS=true ./free_ports.sh

So I wanted to reset everything back to the default ports because I'm not using SWAG in this Synology anymore. I run your script (which I assume is the "latest" version) and I got this result:

root@synology:~# RESET_TO_DEFAULTS=true /volume1/system/scripts/free-ports.sh
Resetting ports to default ports...
Replacing port 5080 with 80
Replacing port 5443 with 443

Made these changes:
Only in /usr/syno/share/nginx/: acl.mustache
Only in /usr/syno/share/nginx/: acl_rule.mustache
Only in /usr/syno/share/nginx/: Alias_v2.mustache
Only in /usr/syno/share/nginx/: cgi.mustache
Only in /usr/syno/share/nginx/: cgi.pass.mustache
Only in /usr/syno/share/nginx/: conf.d
Only in /usr/syno/share/nginx/: default_redirect.html
Only in /usr/syno/share/nginx/: deny.mustache
Only in /usr/syno/share/nginx/: deny.PhotoStation.mustache
Only in /usr/syno/share/nginx/: deny.synoman.mustache
Only in /usr/syno/share/nginx/: DSM_Main.mustache
Only in /usr/syno/share/nginx/: DSM.mustache
Only in /usr/syno/share/nginx/: error.html
Only in /usr/syno/share/nginx/: error_page.mustache
Only in /usr/syno/share/nginx/: Firewall.mustache
Only in /usr/syno/share/nginx/: gzip.mustache
Only in /usr/syno/share/nginx/: HSTS.mustache
Only in /usr/syno/share/nginx/: https.mustache
Only in /usr/syno/share/nginx/: LetsEncrypt.mustache
Only in /usr/syno/share/nginx/: logo.jpg
Only in /root/.bak/free_ports//2022-11-07-22-40-11: nginx
Only in /usr/syno/share/nginx/: nginx.mustache
Only in /usr/syno/share/nginx/: open_file_cache.mustache
Only in /usr/syno/share/nginx/: optimization.mustache
Only in /usr/syno/share/nginx/: Portal.mustache
Only in /usr/syno/share/nginx/: redirect_html.mustache
Only in /usr/syno/share/nginx/: server.mustache
Only in /usr/syno/share/nginx/: synoscgi.sock.pass.mustache
Only in /usr/syno/share/nginx/: SynoSharing.mustache
Only in /usr/syno/share/nginx/: TLSProfile.mustache
Only in /usr/syno/share/nginx/: WWW_Main.mustache
Only in /usr/syno/share/nginx/: WWWService.mustache
Only in /usr/syno/share/nginx/: X-Accel.mustache

[ ] Updating Nginx...
nginx: [warn] low address bits of 192.168.10.10/24 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:2
nginx: [warn] low address bits of 169.254.226.13/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:3
nginx: [warn] low address bits of 169.254.191.90/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:4
nginx: [warn] low address bits of 169.254.120.175/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:5
nginx: [warn] low address bits of 192.168.10.10/24 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:2
nginx: [warn] low address bits of 169.254.226.13/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:3
nginx: [warn] low address bits of 169.254.191.90/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:4
nginx: [warn] low address bits of 169.254.120.175/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:5
nginx: [warn] low address bits of 192.168.10.10/24 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:2
nginx: [warn] low address bits of 169.254.226.13/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:3
nginx: [warn] low address bits of 169.254.191.90/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:4
nginx: [warn] low address bits of 169.254.120.175/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:5
nginx: [warn] low address bits of 192.168.10.10/24 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:2
nginx: [warn] low address bits of 169.254.226.13/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:3
nginx: [warn] low address bits of 169.254.191.90/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:4
nginx: [warn] low address bits of 169.254.120.175/16 are meaningless in /etc/nginx/conf.d/dsm.ssdp.conf:5
[✔] Nginx reloaded!

All good even with those warnings?

@julichan
Copy link

julichan commented Nov 11, 2022

If you have a domain, you can reverse proxy with synology dsm without any scripts....
just set Config Panel > External Access > Advanced to the following:

  • Hostname: intranet.mydomain,com (any subdomain will do actually)
  • DSM Http: something else than 80 (5080 for exemple)
  • DSM Https: something else than 443 (5043 for exemple)

Then the reverse proxy will allow you to reverse proxy on port 80/443 as long as you specify a domain other than the one specified above, including the root domain,

@apearson
Copy link

Tested on 7.1.1-42962 Update 1: Works

@kevindd992002
Copy link

If you have a domain, you can reverse proxy with synology dsm without any scripts.... just set Config Panel > External Access > Advanced to the following:

* Hostname: intranet.mydomain,com (any subdomain will do actually)

* DSM Http: something else than 80 (5080 for exemple)

* DSM Https: something else than 443 (5043 for exemple)

Then the reverse proxy will allow you to reverse proxy on port 80/443 as long as you specify a domain other than the one specified above, including the root domain,

Can you clarify what you mean here? I have synology.me domain specified in Control Panel -> Externl Access -> Advanced and ports other than 80/443, but when I create a SWAG container with ports 80/443 it still won't let me because the Syno's nginx reverse proxy is still listening on ports 80 and 443.

@kevindd992002
Copy link

Tested on 7.1.1-42962 Update 1: Works

Which version of the script did you exactly use?

@julichan
Copy link

julichan commented Jan 1, 2023

If you have a domain, you can reverse proxy with synology dsm without any scripts.... just set Config Panel > External Access > Advanced to the following:

* Hostname: intranet.mydomain,com (any subdomain will do actually)

* DSM Http: something else than 80 (5080 for exemple)

* DSM Https: something else than 443 (5043 for exemple)

Then the reverse proxy will allow you to reverse proxy on port 80/443 as long as you specify a domain other than the one specified above, including the root domain,

Can you clarify what you mean here? I have synology.me domain specified in Control Panel -> Externl Access -> Advanced and ports other than 80/443, but when I create a SWAG container with ports 80/443 it still won't let me because the Syno's nginx reverse proxy is still listening on ports 80 and 443.

I am not sure that's what you meant with settings a SWAG container with port 80/443 but I don't recomend you to open the port 80 and 443 in your containers. as you know a docker container that can open a port below 1024 has host admin rights or something has been tempered with the container during build. This is not basically a docker feature but a linux kernel feature that is also present in dsm. That means a hacker who gets access to your container may freely do what they want with your docker host in that state.

That aside, the dns reverse proxy is not litteraly blocking port 80/443 as people suggest here. your DSM can be configured through the configuration panel to use ports other than 80/443 with the three settings mentioned above. Beyond that, the web station package can also blocking port 80/443 but it can be uninstalled if that is the case for you. I personally made the reverse proxy accept port 80/443 without a fuss without touching the web station package in the least and that resulted in having the web station package as a fallover of the reverse proxy when no entry match the request, I think that's pretty well designed. so well, the web station package is a problem only if you want to open the port 80/443 directory to your host network interface and not inside docker.

Please take a look at theses screenshots

All you need is to set the settings i mentioned above from the control panel to use ports other and 80/443 and ensure your synology server is accessed via a specified FQDN (synology doesn't explain that very well in its documentation) so if you have myserver.synology.me (i use a paid domain and not synology ddns so i required to setup a dns server with the dns package but it should be the same nonetheless since you have unlimited subdomains on your domain). So set your synology server configuration to be accessible through a subdomain, let's say dsm.myserver.synology.me and then the reverse proxy allows you to use anything else than that as an entry. For exemple you could setup swag.myserver.synology.me on port 80/443.

You container will not have port 80/443 (it shouldn't anyway) but the reverse proxy will forward the requests to your containers using port 80/443 for each subdomains you have an entry for in it.

@apearson
Copy link

apearson commented Jan 2, 2023

Tested on 7.1.1-42962 Update 1: Works

Which version of the script did you exactly use?

Used the bash script in gist (rev 14)

@centra3oz
Copy link

Tried Rev 14 of free_ports.sh on DSM 7.1.1-42962 Update 4.

Got the following errors
sed: no input files
./free-ports.sh: line 72: /usr/syno/share/nginx/Alias_v2.mustache: Permission denied
sed: no input files
./free-ports.sh: line 74: /usr/syno/share/nginx/Alias_v2.mustache: Permission denied

Everything else seemed to work.

@centra3oz
Copy link

Fixed some nano clitches

@p-riebs
Copy link

p-riebs commented Mar 24, 2023

Just to follow up on https://gist.github.com/hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7?permalink_comment_id=4420595#gistcomment-4420595

I ultimately went with this approach because I want to set it and forget it (without worrying that the next DSM update will break the script). The one draw back being that it uses the reverse proxy on the Synology NAS instead of changing the reverse proxies port so it's one more more hop for clients to go through.

@thatisfree
Copy link

Yes, best way to use reverse proxy settings.

@knilde
Copy link

knilde commented Apr 12, 2023

Hello everybody,

thanks to @hjbotha and you guys for this solution!
I modified the script and it does the job for DSM 6.2.4-25556 Update 6 !
Yeaaaah!

You may want to use my modified script.
I did NOT change the replacements themselve, so the core of the original script is still the same.

Here is what I changed:

  • removed option fo disable backups - WE WANT BACKUPS IF CHANGES ARE DONE!
  • ... but if the script did NO changes, the backup of this run will be removed. Normally this is the case, if former modifications are still in place.
  • only if changes were made they get reported
  • only if changes were made NGINX gets restarted
  • removed funcionallity to "restore" former changes

Why the "restore"-part was removed and how to restore then?
If someone modifies multiple times with different new ports it would be tricky to fiddle the right settings into the script, set the environment-vars and track the resulting changes. So I removed that completely.
If you need to restore just look in your backup-folder and restore the version you like manually. Because your backup-folder does not contain "useless" backups it's very easy to see the changes (changes.log) and replace files in /usr/syno/share/nginx/ with backups.

#! /bin/bash
# Script-source and discussion: https://gist.github.com/hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7

# Developed for DSM 6 - 7.0.1. Not tested on other versions.
# run as root at boot through Control Panel -> Task Scheduler

# Ports to free - blocked by nginx on Synology
DEFAULT_HTTP_PORT=80
DEFAULT_HTTPS_PORT=443

# New ports to set instead
CUSTOM_HTTP_PORT=5080  # DO NOT USE 5000 
CUSTOM_HTTPS_PORT=5443 # DO NOT USE 5001 

# Backup-settings
BACKUP_DIR=/volume2/Backups/Settings/DSM-nginx
DELETE_OLD_BACKUPS=true
KEEP_BACKUP_DAYS=90

echo "Replacing port $DEFAULT_HTTP_PORT with $CUSTOM_HTTP_PORT"
echo -e "Replacing port $DEFAULT_HTTPS_PORT with $CUSTOM_HTTPS_PORT\n"

# Always backup...
BACKUP_DIR="$BACKUP_DIR/$(date +%Y%m%d-%H%M%S)"
echo "Backup Dir: "$BACKUP_DIR
mkdir -p "$BACKUP_DIR"
cp -r /usr/syno/share/nginx/* "$BACKUP_DIR"

if [ "$DELETE_OLD_BACKUPS" == "true" ]; then
  find "$BACKUP_DIR/" -type d -mtime +$KEEP_BACKUP_DAYS -exec rm -r {} \;
fi

# Replace ports as desired in mustache config files
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$DEFAULT_HTTP_PORT\([^0-9]\)/\1$CUSTOM_HTTP_PORT\2/" /usr/syno/share/nginx/*.mustache
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$DEFAULT_HTTPS_PORT\([^0-9]\)/\1$CUSTOM_HTTPS_PORT\2/" /usr/syno/share/nginx/*.mustache

# create changes.log
diff -r --exclude=changes.log /usr/syno/share/nginx/ "$BACKUP_DIR" > "$BACKUP_DIR/changes.log"

# remove backup if NO changes were made - else restart nginx
if [ $(stat -c%s "$BACKUP_DIR/changes.log") -eq 0 ]; then
	rm -f -r "$BACKUP_DIR"
	echo No changes detected, backup removed.
else
	echo "Made these changes:"
	cat "$BACKUP_DIR/changes.log"
	echo -e "\n[ ] Restarting Nginx..."
	if grep -q 'majorversion="7"' "/etc.defaults/VERSION"; then
		nginx -s reload
		echo "[✔] Nginx reloaded!"
	else
		if which synoservicecfg; then
			synoservicecfg --restart nginx
		else
			synosystemctl restart nginx
		fi
		echo "[✔] Nginx restarted!"
	fi
fi

@falkheiland
Copy link

falkheiland commented May 1, 2023

@knilde i had to manually execute synosystemctl restart nginx for the settings to take effect. the script "only" did nginx -s reload.

sh-4.4# cat /etc.defaults/VERSION
majorversion="7"
minorversion="1"
major="7"
minor="1"
micro="1"
productversion="7.1.1"
buildphase="GM"
buildnumber="42962"
smallfixnumber="5"
nano="5"
base="42962"
builddate="2023/04/08"
buildtime="20:01:57"

@pyrothebearded1
Copy link

If you have a domain, you can reverse proxy with synology dsm without any scripts.... just set Config Panel > External Access > Advanced to the following:

* Hostname: intranet.mydomain,com (any subdomain will do actually)

* DSM Http: something else than 80 (5080 for exemple)

* DSM Https: something else than 443 (5043 for exemple)

Then the reverse proxy will allow you to reverse proxy on port 80/443 as long as you specify a domain other than the one specified above, including the root domain,

Can you clarify what you mean here? I have synology.me domain specified in Control Panel -> Externl Access -> Advanced and ports other than 80/443, but when I create a SWAG container with ports 80/443 it still won't let me because the Syno's nginx reverse proxy is still listening on ports 80 and 443.

I am not sure that's what you meant with settings a SWAG container with port 80/443 but I don't recomend you to open the port 80 and 443 in your containers. as you know a docker container that can open a port below 1024 has host admin rights or something has been tempered with the container during build. This is not basically a docker feature but a linux kernel feature that is also present in dsm. That means a hacker who gets access to your container may freely do what they want with your docker host in that state.

That aside, the dns reverse proxy is not litteraly blocking port 80/443 as people suggest here. your DSM can be configured through the configuration panel to use ports other than 80/443 with the three settings mentioned above. Beyond that, the web station package can also blocking port 80/443 but it can be uninstalled if that is the case for you. I personally made the reverse proxy accept port 80/443 without a fuss without touching the web station package in the least and that resulted in having the web station package as a fallover of the reverse proxy when no entry match the request, I think that's pretty well designed. so well, the web station package is a problem only if you want to open the port 80/443 directory to your host network interface and not inside docker.

Please take a look at theses screenshots

All you need is to set the settings i mentioned above from the control panel to use ports other and 80/443 and ensure your synology server is accessed via a specified FQDN (synology doesn't explain that very well in its documentation) so if you have myserver.synology.me (i use a paid domain and not synology ddns so i required to setup a dns server with the dns package but it should be the same nonetheless since you have unlimited subdomains on your domain). So set your synology server configuration to be accessible through a subdomain, let's say dsm.myserver.synology.me and then the reverse proxy allows you to use anything else than that as an entry. For exemple you could setup swag.myserver.synology.me on port 80/443.

You container will not have port 80/443 (it shouldn't anyway) but the reverse proxy will forward the requests to your containers using port 80/443 for each subdomains you have an entry for in it.

@julichan Hello! Thank you for your very in-depth explanation for how to setup the ports and reverse proxy settings. You shed some light on a much better way to think of the ports and keeping it all safe. I can completely understand the red lines blocking the the specifics for your setup, but it leaves me wondering what subdomains you were exactly referencing. Would you please show your Synology reverse proxy with just the domain name changed to like domain? I already have SWAG running in Docker and have a working reverse proxy setup. I am not necessarily trying to abandon that in exchange for the built in one.

I was hoping I could pick your mind for the first reason that I found this post. I am trying to do something that I would think would be simple enough but is eluding me. Perhaps your knowledge can point me in the right direction. I realized when my internet was having an outage that my reverse proxy setup had broken. It proved that when I am interacting with my i.e. sonarr.domain.com, I am going out to to the net and back when I am accessing a service on my DS that's on the same switch as my PC. Could you shed some light on any ideas on how to locally access my docker services directly in same subnet, while keeping the same google domain DDNS working.

Thank you so much for any help you can offer with all this. You're explanations were awesome!

@julichan
Copy link

julichan commented May 30, 2023

@pyrothebearded1, hello,
Indeed, your synology should still be accessible even if your internet went out from your lan as long as hubs and potential intermediate routers connecting your pc to your nas are still powered on. It might be pointing to a possible unwanted access to your nas from outside. You should check this out carefully.

In anyway, as i imagine your configuration, it was your gateway that was turned off and you couldn't access your nas anymore. You don't have a local dns server overriding the google dns or a similar configuration in your lan. Right? Check this with a simple ping or tracert on your url to ensure it's a lan ip and not your internet ip. If it's your internet ip, that means your network machines are resolving the dns entries from google. That means all your lan computers go through your gateway to access your nas when using the dns url. If your gateway use a lan loopback, your nas server may still be secure and just forward the requests to your nas allowing you access. If there is no loopback, that means you are accessing your nas as if going through the wan port of your gateway meaning it's accessible from outside. That possibility is highly dangerous for your nas. Either way, going through your gateway also remove all benefits from using dual port ethernet from your nas if you use that.

In my case, i have two dns configurations:

  • one from google domain with pointing to my internet ip (both root domain and wildcard domain)
  • one on my synology router is overriding the google domain one for my local network that point to the internal network ip of my nas. (You can also configure your router to point to dsm dns as a replacement and use the same dns server package)

I recently made a much more secure setup with 2 reverse proxies:

  • the one from dsm is now used only to access private applications localy from my network and is still set to use ports 80/443
  • i created a traeffik reverse proxy and bound ports 8080 and 8443 on my nas for public access. This reverse proxy is in a docker container and can only access docker containers on the same docker network.
    With those settings, my router is now forwarding external ports 80/443 to internal port of the nas 8080 and 8443 and apps accessible to both the public and private realm are configured in both reverse proxies.

If you want, you may just use one reverse proxy, the synology's one and point your router ports 80/443 to 80/443 but that means your nas and the private apps are only protected by access profiles and firewall. In my case, i consider safer a reverse proxy with no private app knowledge than one with filters that could be misconfigured.

So now for the dsm config, let's say my root domain is domain.net, my dsm is configured as nas.domain.net with port 5080 and 5443.
The synology reverse proxy is still listening to port 80/443 without any domaon restriction but i can add an entry for my app, let's use photoprism as an exemple, with the following settings:

  • source: photoprism.domain.net
  • port: 443
  • hsts enabled (i'm not sure this has any effect unless you also setup port 80 but since it's internal use, it doesn't matter in this case)
  • destination: localhost
  • port: 3443 (in docker i bound the host port as 3443 with docker-compose ports directive for exemple)

Since the docker container has been configured to be bound to the host port, the destination localhost means to use the nas' port but localhost isn't filtered by the firewall since it s a nas loopback so you don't need to open the port 3443 on it. It can't be accessed by the port from outside the nas.

In the internal dns you create, you need to correctly reference the urls set to the nas ip to make sure you have access but in any case, you should still be able to access your nas via ip:5443 if you messed up your config.

I set up traefik reverse proxy in a similar way except it's bound on host port 8080/8443 of my nas but instead of targetting the entry to localhost:3443, I set its target to the container name and its internal port since it is in the same container network: http://photoprism-containter-name:internal-port

For this kind of setup its much easier to keep containers internal and host ports with identical values or it becomes a nightmare to manage.

Sometimes images are configured to use ports below 1024 and require admin rights which is docker default behaviour but most of the time this can be changed via a setting file or an environment variable.

Make sure to use the docker user directive with a userid and a groupid of 1000+ for very secure containers without any access to the nas. And especially those accessible from internet otherwise your nas is in serious danger. Your path volumes if you use any will however require same access rights. Please note that the user and group does not need to exist in your host system (your synology nas) which is how it becomes secure.
It's not always possible off course. If you have a portainer container and it needs access to /var/run/docker.pid file, this file requires root access anyway... Just don't expose that container to internet!
In the case of photoprism, you may want to manage your photos in a dsm share too, in this case, you ll need a dsm user and group set on this share and bind its ids to the docker user instead of using a non existant user.

On your reverse proxies, be it synology's or traeffik's or any other's you can also set access profiles to limit the source of access such as an internal ip or ip of specific countries which is very useful to increase the security of your device.

I hope that was a clear enough answer. My config is enterily set via docker-compose, ansible and ansible-semaphore rather than dsm and portainer. That gives more control but it's so insanely time consuming...

@ZaxLofful
Copy link

Hello everybody,

thanks to @hjbotha and you guys for this solution! I modified the script and it does the job for DSM 6.2.4-25556 Update 6 ! Yeaaaah!

You may want to use my modified script. I did NOT change the replacements themselve, so the core of the original script is still the same.

Here is what I changed:

* removed option fo disable backups - WE WANT BACKUPS IF CHANGES ARE DONE!

* ... but if the script did NO changes, the backup of this run will be removed. Normally this is the case, if former modifications are still in place.

* only if changes were made they get reported

* only if changes were made NGINX gets restarted

* removed funcionallity to "restore" former changes

Why the "restore"-part was removed and how to restore then? If someone modifies multiple times with different new ports it would be tricky to fiddle the right settings into the script, set the environment-vars and track the resulting changes. So I removed that completely. If you need to restore just look in your backup-folder and restore the version you like manually. Because your backup-folder does not contain "useless" backups it's very easy to see the changes (changes.log) and replace files in /usr/syno/share/nginx/ with backups.

#! /bin/bash
# Script-source and discussion: https://gist.github.com/hjbotha/f64ef2e0cd1e8ba5ec526dcd6e937dd7

# Developed for DSM 6 - 7.0.1. Not tested on other versions.
# run as root at boot through Control Panel -> Task Scheduler

# Ports to free - blocked by nginx on Synology
DEFAULT_HTTP_PORT=80
DEFAULT_HTTPS_PORT=443

# New ports to set instead
CUSTOM_HTTP_PORT=5080  # DO NOT USE 5000 
CUSTOM_HTTPS_PORT=5443 # DO NOT USE 5001 

# Backup-settings
BACKUP_DIR=/volume2/Backups/Settings/DSM-nginx
DELETE_OLD_BACKUPS=true
KEEP_BACKUP_DAYS=90

echo "Replacing port $DEFAULT_HTTP_PORT with $CUSTOM_HTTP_PORT"
echo -e "Replacing port $DEFAULT_HTTPS_PORT with $CUSTOM_HTTPS_PORT\n"

# Always backup...
BACKUP_DIR="$BACKUP_DIR/$(date +%Y%m%d-%H%M%S)"
echo "Backup Dir: "$BACKUP_DIR
mkdir -p "$BACKUP_DIR"
cp -r /usr/syno/share/nginx/* "$BACKUP_DIR"

if [ "$DELETE_OLD_BACKUPS" == "true" ]; then
  find "$BACKUP_DIR/" -type d -mtime +$KEEP_BACKUP_DAYS -exec rm -r {} \;
fi

# Replace ports as desired in mustache config files
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$DEFAULT_HTTP_PORT\([^0-9]\)/\1$CUSTOM_HTTP_PORT\2/" /usr/syno/share/nginx/*.mustache
sed -i "s/^\([ \t]\+listen[ \t]\+[]:[]*\)$DEFAULT_HTTPS_PORT\([^0-9]\)/\1$CUSTOM_HTTPS_PORT\2/" /usr/syno/share/nginx/*.mustache

# create changes.log
diff -r --exclude=changes.log /usr/syno/share/nginx/ "$BACKUP_DIR" > "$BACKUP_DIR/changes.log"

# remove backup if NO changes were made - else restart nginx
if [ $(stat -c%s "$BACKUP_DIR/changes.log") -eq 0 ]; then
	rm -f -r "$BACKUP_DIR"
	echo No changes detected, backup removed.
else
	echo "Made these changes:"
	cat "$BACKUP_DIR/changes.log"
	echo -e "\n[ ] Restarting Nginx..."
	if grep -q 'majorversion="7"' "/etc.defaults/VERSION"; then
		nginx -s reload
		echo "[✔] Nginx reloaded!"
	else
		if which synoservicecfg; then
			synoservicecfg --restart nginx
		else
			synosystemctl restart nginx
		fi
		echo "[✔] Nginx restarted!"
	fi
fi

Why can't we use 5000/5001?

@KComrade53
Copy link

This no longer works as of DSM 7.2. There's still a process remaining for nginx that uses port 443.

@apearson
Copy link

apearson commented Jan 7, 2024

@KComrade53 I'm running 7.2.1. Have you made sure to double check all the DSM settings to make sure nothing is proxied or enabled? Have you tried to restart nginx / the nas?

@KComrade53
Copy link

@apearson I changed no settings, I just updated my synology to 7.2.1. I run the free_ports command as a scheduled task on boot and before the update it worked fine, but now netstat shows port 443 in use by nginx

@knilde
Copy link

knilde commented Jan 20, 2024

I just wanted to let you know:

I have updated my Synology DS918+ with my modified Script from 6.2 to 7.1.

I had nothing to do to make the dockerizes NGNIX working after the updates.
Just installed the DSM Updates, reboot, still working! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment