standardnotes / syncing-server

[Deprecated: Use our new Node server: https://github.com/standardnotes/syncing-server-js]
https://standardnotes.org
GNU Affero General Public License v3.0
209 stars 48 forks source link

Reverse Proxy does not work #194

Open mind-overflow opened 3 years ago

mind-overflow commented 3 years ago

Context

Hello, I have tried setting up a self-hosted instance of syncing-server. I followed your instructions, which are pretty straightforward:

Since this instance is in a remote server, I have no way to test it by visiting http://localhost:3000/. What I did instead, was to create an Apache2 reverse proxy. I tried it both with and without SSL, with no difference. This is the setup:

<VirtualHost *:443>
        ServerName sync.example.org

        <Location />
                ProxyPass http://127.0.0.1:3000/
                ProxyPassReverse http://127.0.0.1:3000/
        </Location>

        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateFile /etc/letsencrypt/live/example.org/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem

</VirtualHost>

The issue

However, when I try to visit sync.example.org, I get a 404 error:

Not Found

If I type ./server.sh logs, this is what pops up:

api-gateway_1               | {"level":"debug","message":"Calling legacy syncing server on: /"}
api-gateway_1               | {"message":"Calling [GET] http://syncing-server-js:3000/,\n        headers: {\"host\":\"127.0.0.1:3000\",\"cache-control\":\"max-age=0\",\"dnt\":\"1\",\"upgrade-insecure-requests\":\"1\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36\",\"accept\":\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\",\"sec-gpc\":\"1\",\"sec-fetch-site\":\"none\",\"sec-fetch-mode\":\"navigate\",\"sec-fetch-user\":\"?1\",\"sec-fetch-dest\":\"document\",\"accept-encoding\":\"gzip, deflate, br\",\"accept-language\":\"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7\",\"cookie\":\"mybbuser=1_QI0AGpsc7iCVepZ3phhwgo5MeKaEqPjQqvk1SDhOkpFHe7TwPr; sid=fc5d81d754395a54426f893616a4a6ab; PHPSESSID=pq8loagorqi77fgb58a5grpqio; rememberme=1%3Ab7f5e7e4997a79aa99eccb6a9103407923a8ec9b20b5480b497e8d9d50e8fb33%3A93dafe779d1e92d1fe736380253a40e33c0cdc1f7b6fa73e2dca1958d30f5d0f\",\"x-forwarded-for\":\"87.2.42.126\",\"x-forwarded-host\":\"sync.example.org\",\"x-forwarded-server\":\"sync.example.org\",\"connection\":\"Keep-Alive\"},\n        query: {},\n        payload: {}","level":"debug"}
syncing-server-js_1         | {"meta":{"req":{"url":"/","headers":{"host":"syncing-server-js:3000","accept-encoding":"gzip, deflate, br","cache-control":"max-age=0","dnt":"1","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36","accept":"application/json","sec-gpc":"1","sec-fetch-site":"none","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","accept-language":"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7","cookie":"mybbuser=1_QI0AGpsc7iCVepZ3phhwgo5MeKaEqPjQqvk1SDhOkpFHe7TwPr; sid=fc5d81d754395a54426f893616a4a6ab; PHPSESSID=pq8loagorqi77fgb58a5grpqio; rememberme=1%3Ab7f5e7e4997a79aa99eccb6a9103407923a8ec9b20b5480b497e8d9d50e8fb33%3A93dafe779d1e92d1fe736380253a40e33c0cdc1f7b6fa73e2dca1958d30f5d0f","x-forwarded-for":"87.2.42.126","x-forwarded-host":"sync.example.org","x-forwarded-server":"sync.example.org","connection":"Keep-Alive","content-type":"application/json","content-length":"2"},"method":"GET","httpVersion":"1.1","originalUrl":"/","query":{}},"res":{"statusCode":404},"responseTime":0},"level":"info","message":"HTTP GET /"}
api-gateway_1               | {"meta":{"req":{"url":"/","headers":{"cache-control":"max-age=0","dnt":"1","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9","sec-gpc":"1","sec-fetch-site":"none","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","accept-encoding":"gzip, deflate, br","accept-language":"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7","cookie":"mybbuser=1_QI0AGpsc7iCVepZ3phhwgo5MeKaEqPjQqvk1SDhOkpFHe7TwPr; sid=fc5d81d754395a54426f893616a4a6ab; PHPSESSID=pq8loagorqi77fgb58a5grpqio; rememberme=1%3Ab7f5e7e4997a79aa99eccb6a9103407923a8ec9b20b5480b497e8d9d50e8fb33%3A93dafe779d1e92d1fe736380253a40e33c0cdc1f7b6fa73e2dca1958d30f5d0f","x-forwarded-for":"87.2.42.126","x-forwarded-host":"sync.example.org","x-forwarded-server":"sync.example.org","connection":"Keep-Alive"},"method":"GET","httpVersion":"1.1","originalUrl":"/","query":{}},"res":{"statusCode":404},"responseTime":8},"level":"info","message":"HTTP GET /"}
api-gateway_1               | Error: Not Found
api-gateway_1               |     at Request.callback (/var/www/node_modules/superagent/lib/node/index.js:883:15)
api-gateway_1               |     at IncomingMessage.<anonymous> (/var/www/node_modules/superagent/lib/node/index.js:1127:20)
api-gateway_1               |     at IncomingMessage.emit (events.js:327:22)
api-gateway_1               |     at endReadableNT (_stream_readable.js:1327:12)
api-gateway_1               |     at processTicksAndRejections (internal/process/task_queues.js:80:21)

Temporary fix

I found a temporary fix, that however is not how it's supposed to work. If I modify my Apache configuration and use the docker container's IP instead of 127.0.0.1, it works.

Find the docker container ID

docker ps -a  | grep sync

Result:

77bbca3e17a0        standardnotes/auth                 "./wait-for.sh synci…"   8 minutes ago       Up 7 minutes                                                                                                                                                           syncing-server_auth_1
3024c4a0ee11        standardnotes/syncing-server-js    "./wait-for.sh synci…"   8 minutes ago       Up 7 minutes                                                                                                                                                           syncing-server_syncing-server-js-worker_1
9fb6d0263ed8        standardnotes/api-gateway          "./wait-for.sh synci…"   8 minutes ago       Up 7 minutes              0.0.0.0:3000->3000/tcp                                                                                                                       syncing-server_api-gateway_1
090590aa093c        standardnotes/syncing-server-js    "./wait-for.sh synci…"   8 minutes ago       Up 7 minutes                                                                                                                                                           syncing-server_syncing-server-js_1
06f874d2b544        redis:6.0-alpine                   "docker-entrypoint.s…"   8 minutes ago       Up 7 minutes              0.0.0.0:32851->6379/tcp                                                                                                                      syncing-server_cache_1
cf9e18522cbe        syncing-server_syncing-server      "./wait-for.sh db 33…"   8 minutes ago       Up 7 minutes                                                                                                                                                           syncing-server_syncing-server_1
9bbba9543007        mysql:5.6                          "docker-entrypoint.s…"   8 minutes ago       Up 7 minutes              0.0.0.0:32850->3306/tcp                                                                                                                      syncing-server_db_1

Find the docker container IP

docker inspect cf9e18522cbe

Result:

<...>
"syncing_server": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "syncing-server",
                        "cf9e18522cbe"
                    ],
                    "NetworkID": "<...>",
                    "EndpointID": "<...>",
                    "Gateway": "172.30.0.1",
                    "IPAddress": "172.30.0.8",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "<...>",
                    "DriverOpts": null
                }
<...>

So, the IP address is 172.30.0.8.

Point Apache2 to the container IP

<VirtualHost *:443>
        ServerName sync.example.org

        <Location />
                ProxyPass http://172.30.0.8:3000/
                ProxyPassReverse http://172.30.0.8:3000/
        </Location>

        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateFile /etc/letsencrypt/live/example.org/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem

</VirtualHost>

Conclusion

By applying the temporary fix, when I visit the page, I get the expected result:

{"message":"Hi! You're not supposed to be here."}

However, the fix is clearly temporary, as the IP docker assigns to its containers is not static. Besides, this is not how it's supposed to work anyway, so I wouldn't feel comfortable leaving it like that anyway.

Any suggestion on how to fix this? If this is not an issue related to syncing-server itself. I'm always available to provide more logs and info if needed. Thanks!

PS: .env and docker-compose.yml are left untouched.

PPS: My server is on Ubuntu Server 20.04, running Apache 2.4.41. Any firewall has been disabled for those tests.

karolsojko commented 3 years ago

Hmm not sure why the use of Apache in here. Maybe change the env files to run the docker setup not at port 3000 but 80 so that you can acess your remote host directly?

mind-overflow commented 3 years ago

@karolsojko The use of Apache is mandatory, because it is the webserver for that machine. It is handling multiple websites and subdomains, while syncing-server is running in a docker container. So, Apache is running as a reverse proxy, tunneling traffic to the docker container, and thus, running the container directly on port 80/443 is not possible as it would conflict with Apache and block access to all the other services.

In theory, as pointed out by this blog post, making a nginx reverse proxy to syncing-server is straightforward and only requires a few lines of config. This is obviously not the case with Apache, as the standard proxy configuration does not work.

Edit: here's the nginx config, to avoid opening the linked url:

server {
    listen 80;
    listen [::]:80;
    server_name notes.example.org;

    location / {
        proxy_pass http://127.0.0.1:3000; # syncing-server address
    }
}
karolsojko commented 3 years ago

We have a new documentation suite out. Please give a try and re-check if it helps with your issue: https://docs.standardnotes.org/self-hosting/getting-started/