Cannot access services via Safari or iOS

Hello,

I started setting up SWAG on my Linux box earlier this week and have been stuck trying to fix an issue for the past couple days. SWAG seems to be working fine when I access it through Chrome on my Macbook in my local network and in public via Tailscale. However, when I try to access services via Safari on my Macbook or via any app on my iOS device (Safari, Firefox, caldav, Immich, etc) it doesn’t seem to be able to find the server in my local network regardless of whether I have Tailscale enabled or not.

So far I’ve tried the following but with no success:

  • Restarting the SWAG container
  • Restarting all Docker containers
  • Restarting the Linux box
  • Disabling Tailscale on the Linux box (For context, I’ve set up Tailscale so I don’t have to open up any ports to the public. I think I can rule this out as the source of the error since 1) I can access my services from my Macbook when I’m outside and connected to the internet via Tailscale 2) I still couldn’t access services via Safari or iOS in my local network)
  • Opening port 443 to the public (was literally grasping at straws here but needed to open this to try my next point anyway)
  • Run SSL tests provided by SSL Labs after stumbling across this StackExchange post. I’m not familiar with SSL but handshakes they looked to be successful with Safari and with iOS devices when running the tests.
  • Modify NGINX config based on some of the comments in this StackExchange post. In particular, I removed SSL and HTTP2 and added proxy_hide_header Upgrade; (see my nginx/site-confs/default below)

Here is what my nginx/site-confs/default looks like right now. The reason I listen to port 444 is to distinguish between Tailscale traffic and non-Tailscale traffic. In the future I want to open port 443 but stil want some services to be only accessible via VPN. (Sidenote: is there a better way of doing this?) The ports config for the SWAG container in docker-compose looks like this:

    ports:
      - target: 443
        host_ip: <local_server_ip>
        published: 443
        protocol: tcp
        mode: host
      - target: 444
        host_ip: <tailscale_server_ip>
        published: 443
        protocol: tcp
        mode: host
## Version 2021/04/27 - Changelog: https://github.com/linuxserver/docker-swag/commits/master/root/defaults/default

error_page 502 /502.html;

# redirect all traffic to https
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

# main server block
server {
    # I've tried removing `ssl http2`
    # I've tried only listening one one port at a time
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    listen 444 ssl http2 default_server;
    listen [::]:444 ssl http2 default_server;

    root /config/www;
    index index.html index.htm index.php;

    server_name _;

    # enable subfolder method reverse proxy confs
    include /config/nginx/proxy-confs/*.subfolder.conf;

    # all ssl related config moved to ssl.conf
    include /config/nginx/ssl.conf;

    # enable for ldap auth
    #include /config/nginx/ldap.conf;

    # enable for Authelia
    #include /config/nginx/authelia-server.conf;

    client_max_body_size 0;

    # to try and fix Safari/iOS issue
    proxy_hide_header Upgrade;

    location / {
        # enable the next two lines for http auth
        #auth_basic "Restricted";
        #auth_basic_user_file /config/nginx/.htpasswd;

        # enable the next two lines for ldap auth
        #auth_request /auth;
        #error_page 401 =200 /ldaplogin;

        # enable for Authelia
        #include /config/nginx/authelia-location.conf;

        # I added this so it doesn't fall back to SWAG splash screen on random URL paths
        deny all;

        # to try and fix Safari/iOS issue
        #proxy_hide_header Upgrade;

        try_files $uri $uri/ /index.html /index.php?$args =404;
    }

    location ~ \.php$ {
        # I added this so it doesn't fall back to SWAG splash screen on random URL paths
        deny all;

        # to try and fix Safari/iOS issue
        #proxy_hide_header Upgrade;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include /etc/nginx/fastcgi_params;
    }
}



# enable subdomain method reverse proxy confs
include /config/nginx/proxy-confs/*.subdomain.conf;
# enable proxy cache for auth
proxy_cache_path cache/ keys_zone=auth_cache:10m;

Here are the logs from the SWAG container

-------------------------------------
          _         ()
         | |  ___   _    __
         | | / __| | |  /  \
         | | \__ \ | | | () |
         |_| |___/ |_|  \__/


Brought to you by linuxserver.io
-------------------------------------

To support the app dev(s) visit:
Certbot: https://supporters.eff.org/donate/support-work-on-certbot

To support LSIO projects visit:
https://www.linuxserver.io/donate/
-------------------------------------
GID/UID
-------------------------------------

User uid:    1000
User gid:    1000
-------------------------------------

cont-init: info: /etc/cont-init.d/10-adduser exited 0
cont-init: info: running /etc/cont-init.d/20-config
cont-init: info: /etc/cont-init.d/20-config exited 0
cont-init: info: running /etc/cont-init.d/30-keygen
using keys found in /config/keys
cont-init: info: /etc/cont-init.d/30-keygen exited 0
cont-init: info: running /etc/cont-init.d/50-config
Variables set:
PUID=1000
PGID=1000
TZ=
URL=<my_domain>.com
SUBDOMAINS=wildcard
EXTRA_DOMAINS=
ONLY_SUBDOMAINS=false
VALIDATION=dns
CERTPROVIDER=
DNSPLUGIN=cloudflare
EMAIL=
STAGING=

Using Let's Encrypt as the cert provider
SUBDOMAINS entered, processing
Wildcard cert for <my_domain>.com will be requested
No e-mail address entered or address invalid
dns validation via cloudflare plugin is selected
Certificate exists; parameters unchanged; starting nginx
cont-init: info: /etc/cont-init.d/50-config exited 0
cont-init: info: running /etc/cont-init.d/60-renew
The cert does not expire within the next day. Letting the cron script handle the renewal attempts overnight (2:08am).
cont-init: info: /etc/cont-init.d/60-renew exited 0
cont-init: info: running /etc/cont-init.d/70-templates
cont-init: info: /etc/cont-init.d/70-templates exited 0
cont-init: info: running /etc/cont-init.d/90-custom-folders
cont-init: info: /etc/cont-init.d/90-custom-folders exited 0
cont-init: info: running /etc/cont-init.d/98-dashboard-config
Applying the SWAG dashboard mod...
**** Goaccess already installed and up to date ****
fetch http://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
OK: 257 MiB in 228 packages
Applied the SWAG dashboard mod
cont-init: info: /etc/cont-init.d/98-dashboard-config exited 0
cont-init: info: running /etc/cont-init.d/99-custom-files
[custom-init] no custom files found exiting...
cont-init: info: /etc/cont-init.d/99-custom-files exited 0
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service init-mods: starting
s6-rc: info: service init-mods successfully started
s6-rc: info: service init-mods-package-install: starting
s6-rc: info: service init-mods-package-install successfully started
s6-rc: info: service init-mods-end: starting
s6-rc: info: service init-mods-end successfully started
s6-rc: info: service init-services: starting
s6-rc: info: service init-services successfully started
s6-rc: info: service legacy-services: starting
services-up: info: copying legacy longrun cron (no readiness notification)
services-up: info: copying legacy longrun fail2ban (no readiness notification)
services-up: info: copying legacy longrun nginx (no readiness notification)
services-up: info: copying legacy longrun php-fpm (no readiness notification)
s6-rc: info: service legacy-services successfully started
s6-rc: info: service 99-ci-service-check: starting
[ls.io-init] done.
s6-rc: info: service 99-ci-service-check successfully started
Server ready

Here are the last 20 lines of the error logs at log/nginx/error.log.

2022/08/25 06:39:37 [crit] 314#314: connect() to [2600:140b:1600::173b:fcba]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:1600::173b:fcba]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/25 06:39:37 [crit] 314#314: connect() to [2600:140b:1600::173b:fcb8]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:1600::173b:fcb8]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/25 07:45:26 [crit] 314#314: connect() to [2600:140b:400::1721:20fa]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:400::1721:20fa]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/25 07:45:26 [crit] 314#314: connect() to [2600:140b:400::1721:20d1]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:400::1721:20d1]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/25 08:42:52 [error] 314#314: *138 access forbidden by rule, client: 172.30.0.1, server: _, request: "GET / HTTP/2.0", host: "whoami.<my_domain>.com"
2022/08/25 12:41:21 [error] 314#314: *246 access forbidden by rule, client: 192.168.68.122, server: _, request: "GET / HTTP/2.0", host: "dashboard.<my_domain>.com"
2022/08/25 12:41:22 [error] 314#314: *246 access forbidden by rule, client: 192.168.68.122, server: _, request: "GET /favicon.ico HTTP/2.0", host: "dashboard.<my_domain>.com", referrer: "https://dashboard.<my_domain>.com/"
2022/08/25 13:43:39 [crit] 314#314: connect() to [2600:140b:2600:3::6007:e589]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:2600:3::6007:e589]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/26 07:45:43 [crit] 314#314: connect() to [2600:140b:400::1721:20fa]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:400::1721:20fa]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/26 07:45:43 [crit] 314#314: connect() to [2600:140b:400::1721:20d1]:80 failed (99: Address not available) while requesting certificate status, responder: r3.o.lencr.org, peer: [2600:140b:400::1721:20d1]:80, certificate: "/config/keys/letsencrypt/fullchain.pem"
2022/08/26 07:47:19 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:19 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:21 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:21 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:23 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:23 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:28 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:28 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:37 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"
2022/08/26 07:47:37 [error] 314#314: *1 caldav could not be resolved (3: Host not found), client: 172.30.0.1, server: caldav.*, request: "PROPFIND /dav.php/calendars/username_here/ HTTP/1.1", host: "caldav.<my_domain>.com:443"

Other bit of info that might be helpful:

  • The access logs at log/nginx/access.log don’t show any requests from iOS devices or Safari, only the working requests from Chrome.
  • I also run a DNS server to resolve my domain name on the same Linux box. I have custom DNS configs on iOS and my MacBook to use that DNS server if in the local network and configured Tailscale to use the Linux box as the first DNS server too.

Please let me know if I can provide any other information. Thanks!

Update: I poked around the actual packets being exchanged with Wireshark and noticed that with Chrome, the destination port for packets being sent to the Linux box were 443 but with Safari they were 80. I manually prepended the urls in Safari with https:// and the services are loading now both on macOS Safari and iOS. I’m going to mark this as resolved for now and open port 80 in my docker-compose file so SWAG can redirect without me having to do it client-side.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.