Giter VIP home page Giter VIP logo

Comments (17)

STaRDoGG avatar STaRDoGG commented on August 22, 2024 2

@YouveGotMeowxy This line is the perp:

proxy_set_header X-Forwarded-Proto $scheme;

Comment it out (or delete it) and then mount that file in your docker compose and restart the apprise container:

i.e.

- '/opt/docker/configs/apprise/nginx.conf:/opt/apprise/webapp/etc/nginx.conf:ro'

from apprise-api.

caronc avatar caronc commented on August 22, 2024 1

As a final update, i pushed another Apprise release and rebuilt the Apprise API against it. So :latest will also have you covered now

from apprise-api.

caronc avatar caronc commented on August 22, 2024 1

Perfect, I'm going to close this ticket!🚀

from apprise-api.

caronc avatar caronc commented on August 22, 2024

I'm not going to be too much help here as i've never used swag. But your upstream proto should be http not https.

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

@caronc Thanks. So I should set it to http, and then try to sort out the Contradictory scheme headers error, rather than https and try to sort out the 500 error?

from apprise-api.

caronc avatar caronc commented on August 22, 2024
server {
    listen 80;

    server_name apprise.*;
    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        proxy_pass http://your.server.running.apprise:8000;
    }
}

Get it workign first with http, then start adding more configuration to NginX to secure the hosting.

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

Hi @caronc

That looks almost identical to what I posted with the exceptions of you're listening on 80, and I'm listening on 443, and I have the SSL config included.

Are you using the SWAG container? If not, can you give it a quick try, it's super simple to setup.

from apprise-api.

caronc avatar caronc commented on August 22, 2024

@YouveGotMeowxy i feel a bit stupid now. I didn't realize the whole point was the SSL itself 🤦‍♂️ .

I guess I was thinking that when dealing with a new nginx instance, just star basic and rule out the SSL completely. Just create the proxy and nothing more. SSL adds a lot of overhead and lots more reasons and things to troubleshoot IF setting up for the first time.

Your question is really loaded.... There are lots of things to consider here. First of all the subdomain

    server_name apprise.*;

Unless you have DNS server, you'll need to edit your hosts file and make sure you create an entry like:

# Don't touch the localhost entry but add to it to support the subdomain
# (only required if you don't have DNS)
127.0.0.1 localhost apprise.localhost

Secondly how are you setting up this Nginx Reverse Proxy; it looks like they instruct you to go here

Apprise could be maybe the same as Bazarr (well not really at all). but the Nginx configuration on the link shared above is closed). Here is the direct link to their example.

You would perhaps need to just flip the ports around a bit:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name apprise.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth, fill in ldap details in ldap.conf
    #include /config/nginx/ldap.conf;

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

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

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

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app apprise;
        set $upstream_port 8000;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }

The part that throws me off is the last entry
proxy_pass $upstream_proto://$upstream_app:$upstream_port;

SWAG assumes you have a container set up running as apprise. Unless you do, this won't work.

When you do your docker --create.

Make sure you create a network they can share... so each container you deploy (both the swag and apprise one) add something like --net apprise-swag

then you'll need to make sure you create the Apprise container with --name apprise so that your reference in the swag initialization connects.

The other thing you can do is set up a docker-compose.yml file perhaps and have both containers launch together (i belive docker-compose throws them both in the same network automatically so they can reference one another).

Falling back to the line that throws me off:
proxy_pass $upstream_proto://$upstream_app:$upstream_port;

This translates (as you know) to:
proxy_pass http:/apprise:8000

So make sure you have a container called apprise in your shared --net or it can't link.

At least this is where i think things might be going wrong.

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

i feel a bit stupid now. I didn't realize the whole point was the SSL itself 🤦‍♂️ .

No worries, lol.

I really appreciate you taking this time out to investigate. :)

I've been using SWAG for probably 2-3 years now, and have something like 80 containers running RP'd through it, so I've got all the basics down (container names, networks, DNS (I use CF). etc.); if you compare the example in my OP with the swag RP you pasted from, the Bazarr RP, they're identical (with the exception of container name and port, and comments removed). :)

SWAG makes it easy to just add new containers by giving you the samples, then you normally just need to change the container name and port in the RP, and restart SWAG, and about 90% of the time works right out of the box. That's one of the great things about it. For apprise, I just grabbed this: https://github.com/linuxserver/reverse-proxy-confs/blob/master/_template.subdomain.conf.sample

added "apprise" for the container name (which matches the container name I created), added port 8000, and then have been stuck trying to get either http or https working at line 39.

It seems like it should be working, but I get the errors originally mentioned in the OP. :/

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

To be complete, here's my current non-working apprise RP, named apprise.subdomain.conf:

## Version 2022/04/07
# make sure that your dns has a cname set for apprise and that your apprise container is not using a base url

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name apprise.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth, fill in ldap details in ldap.conf
    #include /config/nginx/ldap.conf;

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

    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;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app apprise;
        set $upstream_port 8000;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }

    # REMOVE THIS LINE BEFORE SUBMITTING: Some proxies require one or more additional location blocks for things like API or RPC endpoints.
    # REMOVE THIS LINE BEFORE SUBMITTING: If the proxy you are making a sample for does not require an additional location block please remove the commented out section below.
    # location ~ (/apprise)?/api {
    #     include /config/nginx/proxy.conf;
    #     include /config/nginx/resolver.conf;
    #     set $upstream_app apprise;
    #     set $upstream_port <port_number>;
    #     set $upstream_proto <http or https>;
    #     proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    #
    #     # REMOVE THIS LINE BEFORE SUBMITTING: Additional proxy settings such as headers go below this line, leave the blank line above.
    # }
}

Then when going to: https://apprise.redacted.com using http for the set $upstream_proto http; line, I get:

image

and changing the http tp https (normally http is the one to use for most containers), gives this:

image

The apprise container log shows this (note that I was testing with both a browser, and curl, and both http and https during this):

today at 4:43:27 PM2022-06-01 16:43:27,098 INFO Set uid to user 33 succeeded
today at 4:43:27 PM2022-06-01 16:43:27,102 INFO supervisord started with pid 1
today at 4:43:28 PM2022-06-01 16:43:28,106 INFO spawned: 'gunicorn' with pid 7
today at 4:43:28 PM2022-06-01 16:43:28,110 INFO spawned: 'nginx' with pid 8
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [7] [INFO] Starting gunicorn 20.1.0
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [7] [INFO] Listening at: http://0.0.0.0:8080 (7)
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [7] [INFO] Using worker: sync
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [22] [INFO] Booting worker with pid: 22
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [23] [INFO] Booting worker with pid: 23
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [24] [INFO] Booting worker with pid: 24
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [25] [INFO] Booting worker with pid: 25
today at 4:43:28 PM[2022-06-01 16:43:28 -0500] [26] [INFO] Booting worker with pid: 26
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [27] [INFO] Booting worker with pid: 27
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [28] [INFO] Booting worker with pid: 28
today at 4:43:29 PM2022-06-01 16:43:29,120 INFO success: gunicorn entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
today at 4:43:29 PM2022-06-01 16:43:29,120 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [29] [INFO] Booting worker with pid: 29
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [30] [INFO] Booting worker with pid: 30
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [31] [INFO] Booting worker with pid: 31
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [32] [INFO] Booting worker with pid: 32
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [33] [INFO] Booting worker with pid: 33
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [34] [INFO] Booting worker with pid: 34
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [35] [INFO] Booting worker with pid: 35
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [36] [INFO] Booting worker with pid: 36
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [37] [INFO] Booting worker with pid: 37
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [38] [INFO] Booting worker with pid: 38
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [39] [INFO] Booting worker with pid: 39
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [40] [INFO] Booting worker with pid: 40
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [41] [INFO] Booting worker with pid: 41
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [42] [INFO] Booting worker with pid: 42
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [43] [INFO] Booting worker with pid: 43
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [44] [INFO] Booting worker with pid: 44
today at 4:43:29 PM[2022-06-01 16:43:29 -0500] [45] [INFO] Booting worker with pid: 45
today at 4:43:30 PM[2022-06-01 16:43:30 -0500] [46] [INFO] Booting worker with pid: 46
today at 4:43:30 PM[2022-06-01 16:43:30 -0500] [46] [INFO] Booting worker with pid: 46
today at 4:43:30 PM[2022-06-01 16:43:30 -0500] [46] [INFO] Booting worker with pid: 46
today at 4:54:01 PM10.0.2.5 - - [01/Jun/2022:16:54:01 -0500] "GET / HTTP/1.1" 400 149 "-" "curl/7.81.0"
today at 4:55:14 PM10.0.2.52 - - [01/Jun/2022:16:55:14 -0500] "GET /?error=502 HTTP/1.1" 400 149 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
today at 4:55:14 PM10.0.2.5 - - [01/Jun/2022:16:55:14 -0500] "GET /favicon.ico HTTP/1.1" 400 149 "https://apprise.redacted.com/?error=502" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
today at 4:56:00 PM10.0.2.52 - - [01/Jun/2022:16:56:00 -0500] "GET / HTTP/1.1" 400 149 "-" "curl/7.81.0"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *9 client sent invalid method while reading client request line, client: 10.0.2.52, server: , request: "���������Szvd��<켳~�K�4��K����@[_>���138�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.52 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\xC7Szvd\xB2\xE7<\xEC\xBC\xB3~\x04K\xEE4\x98\x14K\x06\x0B\x9D\xA8@[_>\xE3\xF2\xC613\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *10 client sent invalid method while reading client request line, client: 10.0.2.5, server: , request: "��������H��`�Ǭֻ�0�����v&�cr.���)�WSa��8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.5 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03H\xF5\xDB`\x8F\xC7\xAC\xD6\xBB\xFF0\x07\xB6\xEA\xC7\xFEv&\xE8cr.\xFA\x06\x8A)\xB1WSa\xEA\x9A\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *11 client sent invalid method while reading client request line, client: 10.0.2.5, server: , request: "�������������zzV*����#.�����_��h����p���8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.5 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\xCA\xDD\xCF\xEE\xBBzzV*\xFF\x02\x86\x8B#.\xFC\xCD\xE0\x99\xC1_\x1D\xCAh\x1F\x10\xE7\xA3p\x85\xFF\x04\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *12 client sent invalid method while reading client request line, client: 10.0.2.52, server: , request: "���������F���F.�����0�}�z}Ţ��o���6I�@8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.52 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\xCCF\x82\xD4\xEBF.\xA7\xFC\x18\xA2\xD50\x90}\x0C\xACz}\xC5\xA2\x7F\x17o\xE8\x08\xD0\x056I\x96@\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *13 client sent invalid method while reading client request line, client: 10.0.2.5, server: , request: "���������$��>D����Iέ�e]"e��(�Hr�����ص)8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.5 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\x1E$\x8E\x18>D\x89\x85\x8C\x05I\xCE\xAD\x8Ce]\x22e\x0F\x90(\x1AHr\xD8\xE7\x9C\x17\xEA\xD8\xB5)\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *14 client sent invalid method while reading client request line, client: 10.0.2.52, server: , request: "���������5V���0Nib�Aے���T'���c�B����ॠ8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.52 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\x195V\xE0\x8B\xF70Nib\x82A\xDB\x92\x11\xF8\xFBT'\x91\xB5\xA2c\xE3B\x83\xEB\xC1\x9D\xE0\xA5\xA0\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *15 client sent invalid method while reading client request line, client: 10.0.2.52, server: , request: "���������\���4���������C,�ǘ)RU�(y���ZF8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.52 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\x93\x5C\xA0\x1F\xE64\xD7\xC8\x08\x0E\x04\x91\xF3\x95\xBF\x17C,\xED\xC7\x98)RU\x88(y\xBB\xF9\x1AZF\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"
today at 4:59:09 PM2022/06/01 16:59:09 [info] 9#9: *16 client sent invalid method while reading client request line, client: 10.0.2.5, server: , request: "���������-�M•����!�����8�r������0����`E8�,�0�̨̩̪�+�/��$�(k�#�'g�"
today at 4:59:09 PM10.0.2.5 - - [01/Jun/2022:16:59:09 -0500] "\x16\x03\x01\x00\xBD\x01\x00\x00\xB9\x03\x03\x8D-\x9AM\xC2\x95\x18\xE0\xC8\xD4!\xCB\xFF\xA3\xB2\xD48\x1Ar\x9C\x9E\x95\x06\x03\xB20\x1C\x9D\xD3\xF9`E\x00\x008\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-"

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

Just poking around at that error at the bottom of the log, and not knowing much about coding, but was wondering if apprise uses websockets and/or node? https://stackoverflow.com/a/36522199/553663

from apprise-api.

caronc avatar caronc commented on August 22, 2024

Just poking around at that error at the bottom of the log, and not knowing much about coding, but was wondering if apprise uses websockets and/or node?

Nah, it uses neither.

What happens if you reference port 8080?

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

What happens if you reference port 8080?

aha! We're making progress! :) port 8080 loads the page, but the css is broken, and I get a lot of path 404's in the inspector.

today at 5:31:20 PM2022-06-01 17:31:20,349 [WARNING] django.request: Not Found: /s/js/highlight.pack.js
today at 5:31:20 PM2022-06-01 17:31:20,364 [WARNING] django.request: Not Found: /s/css/highlight.min.css
today at 5:31:20 PM2022-06-01 17:31:20,381 [WARNING] django.request: Not Found: /s/iconfont/material-icons.css
today at 5:31:20 PM2022-06-01 17:31:20,384 [WARNING] django.request: Not Found: /s/css/base.css
today at 5:31:20 PM2022-06-01 17:31:20,385 [WARNING] django.request: Not Found: /s/js/sweetalert2.all.min.js
today at 5:31:20 PM2022-06-01 17:31:20,401 [WARNING] django.request: Not Found: /s/css/materialize.min.css
today at 5:31:20 PM2022-06-01 17:31:20,407 [WARNING] django.request: Not Found: /s/js/materialize.min.js
today at 5:31:20 PM2022-06-01 17:31:20,748 [WARNING] django.request: Not Found: /s/logo.png
today at 5:31:20 PM2022-06-01 17:31:20,775 [WARNING] django.request: Not Found: /s/favicon.ico
today at 5:31:37 PM2022-06-01 17:31:37,141 [WARNING] django.request: Not Found: /s/css/base.css
today at 5:31:37 PM2022-06-01 17:31:37,141 [WARNING] django.request: Not Found: /s/iconfont/material-icons.css
today at 5:31:37 PM2022-06-01 17:31:37,513 [WARNING] django.request: Not Found: /s/css/highlight.min.css
today at 5:31:37 PM2022-06-01 17:31:37,514 [WARNING] django.request: Not Found: /s/css/materialize.min.css

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

Strangely, when I use port 8000 w/out the RP and go directly to the IP, i get all the css. As a test when I set that to port 8080 and go to the direct ip I get the same result as when using a RP (no css).

from apprise-api.

caronc avatar caronc commented on August 22, 2024

Well the good news from your test is you're routing correctly to the right service. Port 8080 is the Django web instance. Port 8000 is the small nginx server in front of it to serve static files.

So perhaps something in my nginx configuration is breaking things for you: https://github.com/caronc/apprise-api/blob/master/apprise_api/etc/nginx.conf

from apprise-api.

caronc avatar caronc commented on August 22, 2024

I updated the master branch; so you should be able to use :edge with Docker soon (it's building things now i believe).

from apprise-api.

YouveGotMeowxy avatar YouveGotMeowxy commented on August 22, 2024

It worked! Thank you so much @STaRDoGG ! And Thank you @caronc for also helping to diagnose ! :D

from apprise-api.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.