Coder Social home page Coder Social logo

acme-ca-server's Introduction

Hi there ๐Ÿ‘‹

My blog and current projects:

acme-ca-server's People

Contributors

dependabot[bot] avatar knrdl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

acme-ca-server's Issues

Requested URL does not match with actually called URL

Hello,

I have setup acme ca server with this docker-compose:

version: '2.4'
services:
  acme-ca-server:
    image: knrdl/acme-ca-server:0.2.3
    restart: always
    environment:
      EXTERNAL_URL: http://192.168.221.10:8080
      DB_DSN: postgresql://postgres:secret@db/postgres
      CA_ENCRYPTION_KEY: U0PgnP9rqlOsw1P5Z9Lj0BDVcRZEatA8OcomQSR9vLw=
      WEB_ENABLE_PUBLIC_LOG: true
      WEB_APP_TITLE: ACME CA Test
    networks:
      - net
    volumes:
      - ./ca.key:/import/ca.key:ro # needed once to import new ca
      - ./ca.pem:/import/ca.pem:ro # needed once to import new ca
    mem_limit: 250m

  db:
    image: postgres:15-alpine
    restart: always
    environment:
      POSTGRES_PASSWORD: secret
    networks:
      - net
    volumes:
      - ./db:/var/lib/postgresql/data
    mem_limit: 250m

  acme_proxy:
    image: nginx:1.22.1-alpine
    restart: always
    ports:
      - "8080:8080"
    networks:
      - net
    environment:
      - NGINX_HOST=acme.com
      - ACME_SERVER_NAME=acme-acme-ca-server-1
      - ACME_SERVER_PORT=8080
    volumes:
      - ./nginx/templates:/etc/nginx/templates

networks:
  net:

Basically acme_proxy acts as a reverse proxy for acme-ca-server. I know it's HTTP, it's just for testing purposes, will configure nginx to server HTTPS after.

The problem i have is that i can't get it to work, i've tried with certbot and also with acme.sh clients:

certbot docker (as in README.md):

root@ng-test1:/opt# docker run -it --rm certbot/certbot certonly --server http://192.168.221.10:8080/acme/directory --standalone --no-eff-email --email [email protected] -v --domains www.some-domain.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Unable to register an account with ACME server. Error returned by the ACME server: Requested URL does not match with actually called URL
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

certbot client:

root@ng-test1/opt# certbot certonly -n --standalone -d www.some-domain.com --server http://192.168.221.10:8080/acme/directory --agree-tos --email [email protected]
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Unable to register an account with ACME server. Error returned by the ACME server: Requested URL does not match with actually called URL
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

certbot logs:

2023-08-03 13:24:08,768:DEBUG:urllib3.connectionpool:http://localhost:None "GET /v2/connections?snap=certbot&interface=content HTTP/1.1" 200 97
2023-08-03 13:24:09,011:DEBUG:certbot._internal.main:certbot version: 2.6.0
2023-08-03 13:24:09,011:DEBUG:certbot._internal.main:Location of certbot entry point: /snap/certbot/3024/bin/certbot
2023-08-03 13:24:09,011:DEBUG:certbot._internal.main:Arguments: ['-n', '--standalone', '-d', 'www.some-domain.com', '--server', 'http://192.168.221.10:8080/acme/directory', '--agree-tos', '--email', '[email protected]', '--preconfigured-renewal']
2023-08-03 13:24:09,012:DEBUG:certbot._internal.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#apache,PluginEntryPoint#manual,PluginEntryPoint#nginx,PluginEntryPoint#null,PluginEntryPoint#standalone,PluginEntryPoint#webroot)
2023-08-03 13:24:09,022:DEBUG:certbot._internal.log:Root logging level set at 30
2023-08-03 13:24:09,022:DEBUG:certbot._internal.plugins.selection:Requested authenticator standalone and installer None
2023-08-03 13:24:09,024:DEBUG:certbot._internal.plugins.selection:Single candidate plugin: * standalone
Description: Runs an HTTP server locally which serves the necessary validation files under the /.well-known/acme-challenge/ request path. Suitable if there is no HTTP server already running. HTTP challenge only (wildcards not supported).
Interfaces: Authenticator, Plugin
Entry point: standalone = certbot._internal.plugins.standalone:Authenticator
Initialized: <certbot._internal.plugins.standalone.Authenticator object at 0x7f7ee39d6dc0>
Prep: True
2023-08-03 13:24:09,024:DEBUG:certbot._internal.plugins.selection:Selected authenticator <certbot._internal.plugins.standalone.Authenticator object at 0x7f7ee39d6dc0> and installer None
2023-08-03 13:24:09,024:INFO:certbot._internal.plugins.selection:Plugins selected: Authenticator standalone, Installer None
2023-08-03 13:24:09,092:DEBUG:acme.client:Sending GET request to http://192.168.221.10:8080/acme/directory.
2023-08-03 13:24:09,094:DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 192.168.221.10:8080
2023-08-03 13:24:09,099:DEBUG:urllib3.connectionpool:http://192.168.221.10:8080 "GET /acme/directory HTTP/1.1" 200 334
2023-08-03 13:24:09,099:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx/1.22.1
Date: Thu, 03 Aug 2023 13:24:09 GMT
Content-Type: application/json
Content-Length: 334
Connection: keep-alive
cross-origin-opener-policy: same-origin
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
strict-transport-security: max-age=31536000
content-security-policy: base-uri 'self'; default-src 'none';

{"newNonce":"http://192.168.221.10:8080/acme/new-nonce","newAccount":"http://192.168.221.10:8080/acme/new-account","newOrder":"http://192.168.221.10:8080/acme/new-order","revokeCert":"http://192.168.221.10:8080/acme/revoke-cert","keyChange":"http://192.168.221.10:8080/acme/key-change","meta":{"website":"http://192.168.221.10:8080"}}
2023-08-03 13:24:09,099:DEBUG:acme.client:Requesting fresh nonce
2023-08-03 13:24:09,099:DEBUG:acme.client:Sending HEAD request to http://192.168.221.10:8080/acme/new-nonce.
2023-08-03 13:24:09,105:DEBUG:urllib3.connectionpool:http://192.168.221.10:8080 "HEAD /acme/new-nonce HTTP/1.1" 200 0
2023-08-03 13:24:09,105:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx/1.22.1
Date: Thu, 03 Aug 2023 13:24:09 GMT
Content-Type: application/json
Content-Length: 4
Connection: keep-alive
replay-nonce: BxaxxrvV4xzsDYalW6zBMz8oSN4wy2cWQIRjVGnvYAQ
cache-control: no-store
link: <http://192.168.221.10:8080/acme/directory>;rel="index"
cross-origin-opener-policy: same-origin
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
strict-transport-security: max-age=31536000
content-security-policy: base-uri 'self'; default-src 'none';


2023-08-03 13:24:09,106:DEBUG:acme.client:Storing nonce: BxaxxrvV4xzsDYalW6zBMz8oSN4wy2cWQIRjVGnvYAQ
2023-08-03 13:24:09,106:DEBUG:acme.client:JWS payload:
b'{\n  "contact": [\n    "mailto:[email protected]"\n  ],\n  "termsOfServiceAgreed": true\n}'
2023-08-03 13:24:09,112:DEBUG:acme.client:Sending POST request to http://192.168.221.10:8080/acme/new-account:
{
  "protected": "eyJhbGciOiAiUlMyNTYiLCAiandrIjogeyJuIjogIjJXSWNrSFZSNVFxNm5uY281VEtWaDJIWmp5S2ZSTmtZNFpsQ01VSGx1dUJ0ajhEdUVEalVtM1pWWTBkdjd0ZTNyblNmd0dCWVpDYV9OdW13VXJHaERKaHZtdlpUck5aUWRFdDNDNWdtTXFJeC1NQjNmZkFmM2JpUDVYN3FJU2s4bEJhNlNqQmpkWHplZXhVMTEyLUhKc2VVLV9XYm12RHJHa0pTVk00cU96czM5VlRxOVdBb3BvelFlSVBEaUszTmlmX0JTUmp3WW8zT2xueGxXTkhWX1BxODAzYldSbnlVZ0tXS0hrRjdQZElCR0xjUG1HanpmLXZaZnlBakRyV01vb2hmd3ptN18zMC1vbEs4SXRZQTEzZ0pZQnhNVlBBcll3MWpOelI0elY5QllTbV9KMXppSHN4YmlXQXBQUENzQnk3ZnBGdjJEbThTQzZXVjBGUlR6USIsICJlIjogIkFRQUIiLCAia3R5IjogIlJTQSJ9LCAibm9uY2UiOiAiQnhheHhydlY0eHpzRFlhbFc2ekJNejhvU040d3kyY1dRSVJqVkdudllBUSIsICJ1cmwiOiAiaHR0cDovLzE5Mi4xNjguMjIxLjEwOjgwODAvYWNtZS9uZXctYWNjb3VudCJ9",
  "signature": "NqOaHEpkrHMOatyvw_G_VDSQfv-rKIE4diIYcwAhP-T_97A7E_xBOr0xuwIy-spn4kdQ2sWzWZE3RNgc3O8QcS-3GCZ6HUk1OzD0rVWsnwjkynlfkVsZLzHzai_1F6IREFR034vyKPNwpPP258tIGIcLmmoiAfAE1QSdCsIVztf6keVB8YVDwtK6fEAjvIEnYtEpTLaOl1DQVe1nD9PAhJzHIj5IcHXyNgjC2EOkm-ZczE2rv-T479lVXeAjmQjOU0PlHvh1EPWZZOSn-au7M_T0iBJUAb0yO6cPUg8qMdQ_cNixTt6qNO33n9ekLBYlFfsyvzcKmoKN3OSAum1onw",
  "payload": "ewogICJjb250YWN0IjogWwogICAgIm1haWx0bzptbUB5YWhvby5jb20iCiAgXSwKICAidGVybXNPZlNlcnZpY2VBZ3JlZWQiOiB0cnVlCn0"
}
2023-08-03 13:24:09,116:DEBUG:urllib3.connectionpool:http://192.168.221.10:8080 "POST /acme/new-account HTTP/1.1" 400 115
2023-08-03 13:24:09,117:DEBUG:acme.client:Received response:
HTTP 400
Server: nginx/1.22.1
Date: Thu, 03 Aug 2023 13:24:09 GMT
Content-Type: application/problem+json
Content-Length: 115
Connection: keep-alive
cross-origin-opener-policy: same-origin
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
strict-transport-security: max-age=31536000
content-security-policy: base-uri 'self'; default-src 'none';

{"type":"urn:ietf:params:acme:error:unauthorized","detail":"Requested URL does not match with actually called URL"}
2023-08-03 13:24:09,117:DEBUG:certbot._internal.main:
Traceback (most recent call last):
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/main.py", line 738, in _determine_account
    acc, acme = client.register(
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/client.py", line 209, in register
    regr = perform_registration(acme, config, tos_cb)
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/client.py", line 255, in perform_registration
    return acme.new_account(messages.NewRegistration.from_data(
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 62, in new_account
    response = self._post(self.directory['newAccount'], new_account)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 366, in _post
    return self.net.post(*args, **kwargs)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 739, in post
    return self._post_once(*args, **kwargs)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 752, in _post_once
    response = self._check_response(response, content_type=content_type)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 603, in _check_response
    raise messages.Error.from_json(jobj)
acme.messages.Error: urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Requested URL does not match with actually called URL
2023-08-03 13:24:09,118:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/main.py", line 738, in _determine_account
    acc, acme = client.register(
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/client.py", line 209, in register
    regr = perform_registration(acme, config, tos_cb)
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/client.py", line 255, in perform_registration
    return acme.new_account(messages.NewRegistration.from_data(
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 62, in new_account
    response = self._post(self.directory['newAccount'], new_account)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 366, in _post
    return self.net.post(*args, **kwargs)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 739, in post
    return self._post_once(*args, **kwargs)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 752, in _post_once
    response = self._check_response(response, content_type=content_type)
  File "/snap/certbot/3024/lib/python3.8/site-packages/acme/client.py", line 603, in _check_response
    raise messages.Error.from_json(jobj)
acme.messages.Error: urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Requested URL does not match with actually called URL

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/certbot/3024/bin/certbot", line 8, in <module>
    sys.exit(main())
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/main.py", line 19, in main
    return internal_main.main(cli_args)
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/main.py", line 1864, in main
    return config.func(config, plugins)
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/main.py", line 1579, in certonly
    le_client = _init_le_client(config, auth, installer)
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/main.py", line 830, in _init_le_client
    acc, acme = _determine_account(config)
  File "/snap/certbot/3024/lib/python3.8/site-packages/certbot/_internal/main.py", line 751, in _determine_account
    raise errors.Error(
certbot.errors.Error: Unable to register an account with ACME server. Error returned by the ACME server: Requested URL does not match with actually called URL
2023-08-03 13:24:09,118:ERROR:certbot._internal.log:Unable to register an account with ACME server. Error returned by the ACME server: Requested URL does not match with actually called URL

acme.sh with debug:

root@ng-test1:/opt# /root/.acme.sh/acme.sh --debug --issue -d www.some-domain.com -w /opt/certtest --days 2 --server http://192.168.221.10:8080/acme/directory --insecure
[Thu Aug  3 13:42:28 UTC 2023] Lets find script dir.
[Thu Aug  3 13:42:28 UTC 2023] _SCRIPT_='/root/.acme.sh/acme.sh'
[Thu Aug  3 13:42:28 UTC 2023] _script='/root/.acme.sh/acme.sh'
[Thu Aug  3 13:42:28 UTC 2023] _script_home='/root/.acme.sh'
[Thu Aug  3 13:42:28 UTC 2023] Using default home:/root/.acme.sh
[Thu Aug  3 13:42:28 UTC 2023] Using config home:/root/.acme.sh
https://github.com/acmesh-official/acme.sh
v3.0.7
[Thu Aug  3 13:42:28 UTC 2023] Using server: http://192.168.221.10:8080/acme/directory
[Thu Aug  3 13:42:28 UTC 2023] Running cmd: issue
[Thu Aug  3 13:42:28 UTC 2023] _main_domain='www.some-domain.com'
[Thu Aug  3 13:42:28 UTC 2023] _alt_domains='no'
[Thu Aug  3 13:42:28 UTC 2023] Using config home:/root/.acme.sh
[Thu Aug  3 13:42:28 UTC 2023] ACME_DIRECTORY='http://192.168.221.10:8080/acme/directory'
[Thu Aug  3 13:42:28 UTC 2023] DOMAIN_PATH='/root/.acme.sh/www.some-domain.com_ecc'
[Thu Aug  3 13:42:28 UTC 2023] Le_NextRenewTime
[Thu Aug  3 13:42:28 UTC 2023] Using ACME_DIRECTORY: http://192.168.221.10:8080/acme/directory
[Thu Aug  3 13:42:28 UTC 2023] _init api for server: http://192.168.221.10:8080/acme/directory
[Thu Aug  3 13:42:28 UTC 2023] GET
[Thu Aug  3 13:42:28 UTC 2023] url='http://192.168.221.10:8080/acme/directory'
[Thu Aug  3 13:42:28 UTC 2023] timeout=
[Thu Aug  3 13:42:28 UTC 2023] _CURL='curl --silent --dump-header /root/.acme.sh/http.header  -L  -g  --insecure  '
[Thu Aug  3 13:42:28 UTC 2023] ret='0'
[Thu Aug  3 13:42:28 UTC 2023] ACME_KEY_CHANGE='http://192.168.221.10:8080/acme/key-change'
[Thu Aug  3 13:42:28 UTC 2023] ACME_NEW_AUTHZ
[Thu Aug  3 13:42:28 UTC 2023] ACME_NEW_ORDER='http://192.168.221.10:8080/acme/new-order'
[Thu Aug  3 13:42:28 UTC 2023] ACME_NEW_ACCOUNT='http://192.168.221.10:8080/acme/new-account'
[Thu Aug  3 13:42:28 UTC 2023] ACME_REVOKE_CERT='http://192.168.221.10:8080/acme/revoke-cert'
[Thu Aug  3 13:42:28 UTC 2023] ACME_AGREEMENT
[Thu Aug  3 13:42:28 UTC 2023] ACME_NEW_NONCE='http://192.168.221.10:8080/acme/new-nonce'
[Thu Aug  3 13:42:29 UTC 2023] Using CA: http://192.168.221.10:8080/acme/directory
[Thu Aug  3 13:42:29 UTC 2023] _on_before_issue
[Thu Aug  3 13:42:29 UTC 2023] _chk_main_domain='www.some-domain.com'
[Thu Aug  3 13:42:29 UTC 2023] _chk_alt_domains
[Thu Aug  3 13:42:29 UTC 2023] Le_LocalAddress
[Thu Aug  3 13:42:29 UTC 2023] d='www.some-domain.com'
[Thu Aug  3 13:42:29 UTC 2023] Check for domain='www.some-domain.com'
[Thu Aug  3 13:42:29 UTC 2023] _currentRoot='/opt/certtest'
[Thu Aug  3 13:42:29 UTC 2023] d
[Thu Aug  3 13:42:29 UTC 2023] Using config home:/root/.acme.sh
[Thu Aug  3 13:42:29 UTC 2023] ACME_DIRECTORY='http://192.168.221.10:8080/acme/directory'
[Thu Aug  3 13:42:29 UTC 2023] _init api for server: http://192.168.221.10:8080/acme/directory
[Thu Aug  3 13:42:29 UTC 2023] EC key
[Thu Aug  3 13:42:29 UTC 2023] Registering account: http://192.168.221.10:8080/acme/directory
[Thu Aug  3 13:42:29 UTC 2023] =======Begin Send Signed Request=======
[Thu Aug  3 13:42:29 UTC 2023] url='http://192.168.221.10:8080/acme/new-account'
[Thu Aug  3 13:42:29 UTC 2023] payload='{"contact": ["mailto:[email protected]"], "termsOfServiceAgreed": true}'
[Thu Aug  3 13:42:29 UTC 2023] HEAD
[Thu Aug  3 13:42:29 UTC 2023] _post_url='http://192.168.221.10:8080/acme/new-nonce'
[Thu Aug  3 13:42:29 UTC 2023] _CURL='curl --silent --dump-header /root/.acme.sh/http.header  -L  -g  --insecure   -I  '
[Thu Aug  3 13:42:29 UTC 2023] _ret='0'
[Thu Aug  3 13:42:29 UTC 2023] POST
[Thu Aug  3 13:42:29 UTC 2023] _post_url='http://192.168.221.10:8080/acme/new-account'
[Thu Aug  3 13:42:29 UTC 2023] _CURL='curl --silent --dump-header /root/.acme.sh/http.header  -L  -g  --insecure  '
[Thu Aug  3 13:42:29 UTC 2023] _ret='0'
[Thu Aug  3 13:42:29 UTC 2023] code='400'
[Thu Aug  3 13:42:29 UTC 2023] Register account Error: {"type":"urn:ietf:params:acme:error:unauthorized","detail":"Requested URL does not match with actually called URL"}
[Thu Aug  3 13:42:29 UTC 2023] _on_issue_err
[Thu Aug  3 13:42:29 UTC 2023] Please add '--debug' or '--log' to check more details.
[Thu Aug  3 13:42:29 UTC 2023] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
[Thu Aug  3 13:42:29 UTC 2023] Diagnosis versions: 
openssl:openssl
OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
apache:
apache doesn't exist.
nginx:
nginx doesn't exist.
socat:
socat by Gerhard Rieger and contributors - see www.dest-unreach.org
socat version 1.7.4.1 on Mar 25 2022 09:51:32
   running on Linux version #85-Ubuntu SMP Fri Jul 7 15:25:09 UTC 2023, release 5.15.0-78-generic, machine x86_64
features:
  #define WITH_STDIO 1
  #define WITH_FDNUM 1
  #define WITH_FILE 1
  #define WITH_CREAT 1
  #define WITH_GOPEN 1
  #define WITH_TERMIOS 1
  #define WITH_PIPE 1
  #define WITH_UNIX 1
  #define WITH_ABSTRACT_UNIXSOCKET 1
  #define WITH_IP4 1
  #define WITH_IP6 1
  #define WITH_RAWIP 1
  #define WITH_GENERICSOCKET 1
  #define WITH_INTERFACE 1
  #define WITH_TCP 1
  #define WITH_UDP 1
  #define WITH_SCTP 1
  #define WITH_LISTEN 1
  #define WITH_SOCKS4 1
  #define WITH_SOCKS4A 1
  #define WITH_VSOCK 1
  #define WITH_PROXY 1
  #define WITH_SYSTEM 1
  #define WITH_EXEC 1
  #undef WITH_READLINE
  #define WITH_TUN 1
  #define WITH_PTY 1
  #define WITH_OPENSSL 1
  #undef WITH_FIPS
  #define WITH_LIBWRAP 1
  #define WITH_SYCLS 1
  #define WITH_FILAN 1
  #define WITH_RETRY 1
  #define WITH_MSGLEVEL 0 /*debug*/

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.