trafex / docker-php-nginx Goto Github PK
View Code? Open in Web Editor NEWDocker image with PHP-FPM 8.3 & Nginx 1.26 on Alpine Linux
Home Page: https://hub.docker.com/r/trafex/php-nginx
License: MIT License
Docker image with PHP-FPM 8.3 & Nginx 1.26 on Alpine Linux
Home Page: https://hub.docker.com/r/trafex/php-nginx
License: MIT License
When i try add in Dockerfile
COPY opencensus/* /tmp/opencensus/
RUN cd /tmp/opencensus \
&& phpize \
&& ./configure --enable-opencensus \
&& make -j "$(nproc)" \
&& make install \
&& cd ~ \
&& rm -r /tmp/opencensus \
&& docker-php-ext-enable opencensus
i get an error saying docker-php-ext-enable
is not found. I expected it to be part of php installed in this image.
How can i make docker-php-ext-enable
available ?
in the latest php8 update php cli commands are not working
/var/www/html $ php -v
/bin/sh: php: not found
/var/www/html $ php8 -v
PHP 8.0.2 (cli) (built: Feb 5 2021 00:39:11) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.2, Copyright (c) Zend Technologies
with Zend OPcache v8.0.2, Copyright (c), by Zend Technologies
/var/www/html $
Due to this wp cli is not working - https://make.wordpress.org/cli/handbook/guides/installing/
=> ERROR [11/11] RUN wp core download --version=5.7.1 --locale=en_US 0.3s
------
> [11/11] RUN wp core download --version=5.7.1 --locale=en_US:
#16 0.264 env: can't execute 'php': No such file or directory
This makes sense when you have nginx and php-fpm in the same container.
Using this Dockerfile, i added another needed package by my application called opencensus-alpha
. The package is installed using pecl
.
So by adding the following line of code in the already existing Dockerfile
RUN pecl install opencensus-alpha
an error was thrown
Step 4/18 : RUN pecl install opencensus-alpha
---> Running in 4d0f464fb79c
/bin/sh: pecl: not found
The command '/bin/sh -c pecl install opencensus-alpha' returned a non-zero code: 127
How can i install pecl
or packages installed through it with this Dockerfile
Hi guys.
Thank you for the great Image!
I'm trying to use in the local environment with docker-compose, but after container starts I cant run command inside.
The user became 1000 inside container when I bind the volume local x container.
When I try execute any command, like touch/mkdir on the /var/www/html, I get Permission Denied.
Can you guys help me?
I'm looking for a replacement to webdevops images that runs both php and nginx and found these which looks promising. However, I have also come across the problem with Apple M1 computers, which run arm64 architecture and a lot of docker images fails to run there.
It would be preferable to find a docker image that is built for multi-arch, and useful both on Mac for development, and also for Linux when deploying into production.
Have you looked into this? Alpine base image is "tagged" with ARM 64, but it only seems to contain images for arm/v6 which I find odd...
thank u for your image.
how to change upload limit.
thanks
When attempting to build from this image and use composer as the documentation suggests, you'll come up short and discover that the vendor folder created by composer will never be written into /var/www/html
This is broken because of the VOLUME /var/www/html in the base image, IE this repository.
Removing the VOLUME declaration from the base image will fix this issue.
I tried switching to root user, and change the ownership of directories and files to the root user, but when running a php file, get 403. any ideas ?
When we use VS Code Remote Explorer it throws permission denied error since changing the user to nobody
I had some issues using the alias directive on the nginx config files and loading php files. Turns out it was an issue with the SCRIPT_FILENAME attribute used in this repo. This post explains more and recommends an alternative that fixed it for me.
https://serverfault.com/a/922596
Posting here as a proposed change but for smarter people than I to work out any implications I may have missed.
I installed a wordpress site, but when I open the homepage I see that the response is not gzipped. It has Content-Type: text/html; charset=UTF-8
Looking at the nginx config I think text/html
should be added to the gzip_types?
What will be the configuration of php-fpm for 10000 users (Realtime Users)
I have tried to launch WordPress on Google Cloud Run (Memory 4GiB and 4 vCPU), but It's very slow, about more than 10 seconds on each request.
Hi
I'm trying to use your image as a base for building my application image. However, I noticed that the way permissions of /var/www/html
are setup it is impossible to interact with the contents of that folder with user nobody
.
Here's a simple example of a custom Dockerfile
:
FROM trafex/alpine-nginx-php7:1.3.0
RUN echo "Hello" > hello.html
This fails with /bin/sh: can't create hello.html: Permission denied
.
Is this desired behaviour?
I see a bunch of the config files, such as supervisor point to /dev/stdout for logs and php's sub processes. My understanding was that these are not symlinked in docker containers by default, they only channel the processes launched through the CMD command in the dockerfile? Perhaps I'm wrong here, but not sure how the logs from these processes are captured or channeled, are they all just echoed up through the running process, and if so what is the reference in the various configs?
The container can manually echo to it's logs:
/proc/11/fd/1
/proc/11/fd/2
But an echo to /dev/stderr won't appear in the container logs.
hy can you create php 7.4 support?
https://github.com/docker-library/repo-info/blob/master/repos/php/remote/7.4-fpm-alpine.md
Any idea of how to run cron in supervisord in this dockerfile? I'm hitting a wall here...
Tried this with no success:
[program:cron]
command = /usr/sbin/crond -f -l 15
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
Thanks
If you create a standard laravel project, only the project/public/
sub-directory should be exposed, while it's index.php will reference content from the projects sibling directories via the php process.
What's the advised way for handling this? Modifying the root in the nginx.conf
? Or is there some other way to be more flexible with the the project path?
I suppose I could mount the volume to /var/www
and change /public
to /html
on the host filesystem?
I have a problem configuring nginx to work in a local domain (test environment).
Everything works fine for html files, while for files with a php extension the file download action occurs. What am I doing wrong?
My ngix.conf file looks like this:
error_log stderr warn;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $pipe $upstream_cache_status';
access_log /dev/stdout main_timed;
error_log /dev/stderr notice;
keepalive_timeout 65;
server {
listen [::]:8080 default_server;
listen 8080 default_server;
server_name ~^(www\.)?(.+).local$;
sendfile off;
root /var/www/html/$2/public;
index index.php index.html index.htm;
add_header X-uri "$uri";
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.php
try_files $uri $uri/ /index.php?q=$uri&$args;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/lib/nginx/html;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
}
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
expires 5d;
}
# deny access to . files, for security
#
location ~ /\. {
log_not_found off;
deny all;
}
# allow fpm ping and status from localhost
#
location ~ ^/(fpm-status|fpm-ping)$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
}
}
ERROR: unsatisfiable constraints: php7-mongodb (missing): required by: world[php7-mongodb] The command '/bin/sh -c apk --no-cache add php7 php7-fpm php7-mysqli php7-json php7-openssl php7-curl php7-zlib php7-xml php7-phar php7-intl php7-dom php7-xmlreader php7-ctype php7-mbstring php7-gd php7-mongodb nginx supervisor curl' returned a non-zero code: 1
So I've tried to set up docker-php-nginx an I've finally given up for today.
In my case, I am not able to simply to COPY
files from the host to the container.
So my first issue was:
RUN cp -R /some/where /var/www/html
won't actually copy anything into /var/www/html
.
So I've moved forward and tried to decrypt all the things that are new to me. I tried to switch to a custom server.conf
file, which looks like this:
server {
listen [::]:9090 default_server;
listen 9090 default_server;
server_name _;
sendfile off;
root /var/src/build;
index index.php index.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.php
try_files $uri $uri/ /index.php?q=$uri&$args;
}
# Redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.ht2ml {
root /var/lib/nginx/html;
}
# Pass the PHP scripts to PHP-FPM listening on 127.0.0.1:9000
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
}
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
expires 5d;
}
# Deny access to . files, for security
location ~ /\. {
log_not_found off;
deny all;
}
# Allow fpm ping and status from localhost
location ~ ^/(fpm-status|fpm-ping)$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
}
It's basically just a copy of the server
section, just using port 9090
(yes, I expose and bind it to 9999
on the host) and a different root
(Note that I do not know anything about nginx right now, so no, I don't really know what I'm doing here, to be honest). The container seems to recognize this, since requests to localhost:9999
at least result in 502 Bad Gateway
.
Why is that? I do notice several log messages on starting the cocker container:
ALERT: [pool www] user has not been defined
ERROR: failed to post process the configuration
ERROR: FPM initialization failed
INFO exited: php-fpm (exit status 78; not expected)
I do not use any custom FPM. My dockerfile looks like this:
FROM trafex/alpine-nginx-php7
USER root
RUN apk --no-cache add npm
RUN mkdir /var/src
WORKDIR /var/src
COPY . ./
RUN npm install
RUN npx gulp
EXPOSE 9090
I'd appreciate any help you guys are able to provide!
Hi,
Im currently testing your image with the rss feed aggregator sefloss.
There are selfoss images available but these are quite old and i wanted to run the latest nightly builds.
Anyway i got everything working (had to tweek settings and add a few modules tho) but i have one last issue.
the full debug logs of selfoss are piped into the docker logs and these are getting huge quite fast.
I have configured the log level for selfoss to error only but this seems to be ignored for the container logs and only apply to its own log files.
Is there a way to custimize the logging for the php application and where would i configure this.
Sorry if this is more of a general question and maybe not really related to your image.
gzip on;
is a nice recent addition to the NGINX config file. There seems to be quite a broad consensus though that setting the gzip_min_length higher than its default is makes it more effectives, as compression of smaller files can sometimes make them bigger.
NGINX's own documentation provides some example configurations which seem to be quite widely held to be more suitable:
gzip_min_length 1000;
http://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_vary
https://docs.nginx.com/nginx/admin-guide/web-server/compression/
Something to explore and consider.
Hello,
i need php7.4.
Is there a way ?
Your sincerly
Stephan
Should be great if root directive on nginx.conf could be customized by an ENV var in the Dockerfile.
In my case, my Symfony applications must have a root to /var/www/html/public
when i run
docker run -p 80:8080 -v ~/xxx/app-src:/var/www/html trafex/alpine-nginx-php7
stay attached for log (and isnt good)
how i can run your docker image and attach after?
would you like to tell me how to add ENV variables to nginx.conf?
i wanna add APP_URL where value is my domain address, so my php can read these vars.
it work if i ran with php:7.3-alpine (without nginx).
thanks
Missing location in nginx file causes curl for ping to be answered by index.php, not fpm-status / fpm-ping
Hi!
I am encountering the following issue in the container:
2020/09/08 20:41:14 [crit] 9#9: *1 connect() to unix:/var/run/php7.3-fpm.sock failed (2: No such file or directory) while connecting to upstream, client: 172.17.0.1, server: , request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/php7.3-fpm.sock:", host: "127.0.0.1"
This error is surprising since all the configs seem to point through localhost:9000 and not a socket.
Did you already encountered this error?
Hello,
i'm a beginner in docker.
I will include my own scripts.
I start the container:
docker run -p 80:8080 -v c:/xampp1/htdocs/test/:/var/www/html trafex/alpine-nginx-php7
In my directory 'test' is the index.php.
When i call 'http://localhost/index.php' i get the error '404 Not Found'.
172.17.0.1 - - [13/Jul/2020:12:52:52 +0000] "GET /index.php HTTP/1.1" 404 125 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0" "-" 0.000 - . -
Anybody a idea ?
Your sincerly
Stephan
Add tzdata
package to enable timezone definition via environment variable (TZ).
edit: update php.ini from env too.
Would be possible to add a volume so we could interact with the contents of /var/www/html
on the host, and also persist it between machines?
Example, I have a php script where you run install.php
, and then after that you are supposed to remove the file from /var/www/html
and also change permission of other files to make it more secure.
This image work wonderfully for fully static php scripts, but even for them, you still need to fork this repo, add your own files to /scr
and then create a container in hubdocker to make it work. You may not want to have this public.
With persistent storage, all you'd need to do is to map something like /opt/website
to /var/www/html
inside of the container, and it would work out of the box.
This is a start for a dockerfile, thanks.
It should however include more stuff from https://wiki.alpinelinux.org/wiki/Nginx_with_PHP
Trying to get running Symfony Demo app and getting 403 Forbidden.
wget -c https://github.com/symfony/demo/archive/refs/tags/v1.7.1.tar.gz -O - | tar -xz
cd demo-1.7.1 && composer install
docker run -p 8080:8080 -v ~/demo-1.7.1:/var/www/html trafex/php-nginx
http://localhost:8080/ returns 403 Forbidden
In logs I see:
2021-07-12 21:56:07,419 INFO supervisord started with pid 1
2021-07-12 21:56:08,422 INFO spawned: 'nginx' with pid 7
2021-07-12 21:56:08,423 INFO spawned: 'php-fpm' with pid 8
[12-Jul-2021 21:56:08] NOTICE: fpm is running, pid 8
[12-Jul-2021 21:56:08] NOTICE: ready to handle connections
2021-07-12 21:56:09,441 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2021-07-12 21:56:09,441 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2021/07/12 21:56:14 [error] 9#9: *1 directory index of "/var/www/html/" is forbidden, client: 172.17.0.1, server: _, request: "GET / HTTP/1.1", host: "localhost:8080"
172.17.0.1 - - [12/Jul/2021:21:56:14 +0000] "GET / HTTP/1.1" 403 186 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" "-" 0.000 - . -
Hi @TrafeX
According to the docs at readme file, the image size if ought to be -/+35MB, although when i clone and run docker build -t trafex .
, the image builds successful but with a whopping 110MB.
Very small Docker image size (+/-35MB)
How can the image size be reduced to 35MB
and still be able to run a Laravel/Lumen application ?
Thanks
Composer could not find a composer.json file in /var/www/html
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
The command '/bin/sh -c composer install --optimize-autoloader --no-interaction --no-progress' returned a non-zero code: 1
Hello,
I want to add xdebug to php. Does Alpine have an xdebug package?
Best regards
Stephan
Hi all,
I'm struggling to get SQLite to work I'm using this code:
<?php
$db = new SQLite3('/var/private/anmeldungen.db');
$db->close();
and get this error:
[error] 9#9: *33 FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught Error: Class "SQLite3" not found in /var/www/html/phpinfo.php:3
in my compose file the /var/private folder is linked to a folder on the host system.
volumes:
- ./data/public:/var/www/html
- ./data/data:/var/private
Dockerfile
FROM trafex/php-nginx:latest
USER root
RUN apk add php8-pdo_sqlite
USER nobody
When I call phpinfo I see that sqlite is loaded:
Can anyone spot my error?
Regards
White
Hi,
Any idea on how to include some instructions on how to add imageick extension using this dockerfile.
Many thanks
Bill
The worker_processes auto;
setting in the NGINX config file aims to identify the number of CPU cores on the device and start a worker process for each. One process per CPU core is recommended: https://www.nginx.com/blog/tuning-nginx/
The jury was out for a while on whether this works in docker, but a quick test on my system, running without any worker_process setting starts 1 as expected, running on auto starts 4 as per the number of cores so seems to be doing its job.
Something to consider including.
Is there currently an easy way to change the UID and GID of user nobody in runtime? What I wanna achieve is ability to change its IDs to match host using environment variables rather than having to build the image itself in order to change it.
Does everything run under the nobody user? so php should be able to run mkdir in the html folder?
php-fpm run as nobody aswell?
Sorry about "noob" question.
I (noob) am trying to password protect a subdirectory. What would be an appropriate way to do this? I would like to extend the existing server config with a corresponding entry and tried with a custom .conf-file, but without success:
server {
location /private {
auth_basic "Private";
auth_basic_user_file /private/.htpasswd;
}
}
And I tried to copy the existing /etc/nginx/nginx.conf
from the image to my local ./nginx/
directory, but it doesn't override the existing configuration:
frontend:
image: trafex/alpine-nginx-php7:latest
volumes:
- ./app/frontend:/var/www/html
- ./nginx:/etc/nginx/conf.d
ports:
- "80:8080"
Any help appreciated. ๐
Dear Trafex,
i am build the dockerfile taking reference of your files and some changes on config file but when i start the docker first error i got is this one
and after committing the COPY --chown=nobody src/ /usr/share/nginx/html/ this line i am able to build the docker
but when i run the same it is getting the unhealthly state and from logs it giving me
2020-06-02 12:01:00,764 INFO supervisord started with pid 1
2020-06-02 12:01:01,769 INFO spawned: 'nginx' with pid 7
2020-06-02 12:01:01,772 INFO spawned: 'php-fpm' with pid 8
2020-06-02 12:01:01,782 INFO exited: nginx (exit status 1; not expected)
2020-06-02 12:01:01,783 INFO gave up: nginx entered FATAL state, too many start retries too quickly
nginx: [emerg] "root" directive is duplicate in /etc/nginx/nginx.conf:40
[02-Jun-2020 12:01:01] NOTICE: fpm is running, pid 8
[02-Jun-2020 12:01:01] NOTICE: ready to handle connections
2020-06-02 12:01:02,815 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
docker-php-nginx.zip
apart from that after doing some tweeks also getting this error
2020/06/02 12:31:41 [error] 9#9: *9 directory index of "/var/www/html/" is forbidden, client: 14.141.24.158, server: _, request: "GET / HTTP/1.1", host: "13.234.213.90"
14.141.24.158 - - [02/Jun/2020:12:31:41 +0000] "GET / HTTP/1.1" 403 186 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" "-" 0.000 - . -
i have attached the files for the ref. please help on the same.
Just updated this image which was installed some time ago(2017-2018?), there seems to be an issue with nginx failing to run because it cannot create the client_body
dir, /var/tmp/nginx
does exist as an empty dir though.
I came across this issue which seems to be the same problem encountered in 2018. The linked issue comment points out that it's likely due to the kernel. The server is running 4.4 kernel(which has been updated earlier this year).
A comment later on in the issue then suggests pointing nginx tmp paths to a different location instead. Though I'm not sure where a list of all those are. It appears there is only the 5(all grouped together on that page, see --http-client-body-temp-path=path
).
I also came across this response on the nginx forums which state it could be due to permissions issue from a parent directory. /var/tmp/nginx
is nobody:nobody
but parent /var/tmp
is root:root
, perhaps that's somehow the cause? I see that the switch to a nobody
user/group was about 7 months ago.
I tried to serve a website with this docker but I got this error:
Site error: the ionCube PHP Loader needs to be installed. This is a widely used PHP extension for running ionCube protected PHP code, website security and malware blocking.
Please visit get-loader.ioncube.com for install assistance.
I can do a pull request if you wish so.
After running the container by docker run -p 8001:8080 trafex/alpine-nginx-php7:1.10.0
and running localhost page, I get an error:
NOTICE: PHP message: PHP Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0
ERROR: Unable to open primary script: /var/www/html/index.php (Permission denied)
2021/05/18 12:26:26 [error] 11#11: *2 FastCGI sent in stderr: "PHP message: PHP Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0Unable to open primary script: /var/www/html/index.php (Permission denied)" while reading response header from upstream, client: 172.17.0.1, server: _, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost:8001"
In the case of the php8 image I am also getting a "Permission denied" related error:
2021-05-18 12:32:56,375 INFO supervisord started with pid 1
2021-05-18 12:32:57,379 INFO spawned: 'nginx' with pid 9
2021-05-18 12:32:57,384 INFO spawned: 'php-fpm' with pid 10
[18-May-2021 12:32:57] ERROR: failed to open configuration file '/etc/php8/php-fpm.conf': Permission denied (13)
[18-May-2021 12:32:57] ERROR: failed to load configuration file '/etc/php8/php-fpm.conf'
[18-May-2021 12:32:57] ERROR: FPM initialization failed
2021-05-18 12:32:57,465 INFO exited: php-fpm (exit status 78; not expected)
2021-05-18 12:32:58,466 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2021-05-18 12:32:58,467 INFO gave up: php-fpm entered FATAL state, too many start retries too quickly
2021/05/18 12:33:03 [error] 12#12: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.17.0.1, server: _, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost:8001"
172.17.0.1 - - [18/May/2021:12:33:03 +0000] "GET / HTTP/1.1" 502 494 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.214 Safari/537.36" "-" 0.003 0.003 . -
Any idea for that?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.