Code Monkey home page Code Monkey logo

stouts.openvpn's Introduction

Stouts.openvpn

Build Status Galaxy

Ansible role that installs an openvpn server

  • Install and setup OpenVPN server
  • Setup authentication

Requirements

Previous versions of the role supported generating certificates and keys for the OpenVPN server to use. Since version 3.0.0, such support has been removed and the users of the role are expected to use some other way of generating certificates/keys (eg using another Ansible role). See the example playbook for an example.

An EasyRSA role that was created specifically to compliment this role can be found here.

Supported platforms

  • Ubuntu 14.04
  • Ubuntu 16.04
  • Ubuntu 18.04
  • Debian 8
  • Debian 9
  • Centos 7

Variables

See defaults/main.yml for a full list of variables together with documentation on how to use them to configure this role.

Elastic Beats monitoring

Heartbeat monitor

The role comes bundled with a meta/monitors.yml template that can be used by Heartbeat to check if the OpenVPN server is up and running. The template can be configured via variables (they should be self-explanatory). To use it, you can use some Ansible tasks to upload it to your Heartbeat instance. For example:

- name: Add earth-kibana host
  add_host:
    name: heartbeat_instance
    hostname: "{{ heartbeat.hostname }}"
    ansible_host: "{{ heartbeat.ansible_host }}"
    ansible_password: "{{ heartbeat.ansible_password }}"
    ansible_user: "{{ heartbeat.ansible_user }}"

- name: Upload role monitors
  template:
    src: "{{ item.1 + '/' + item.0 }}/meta/monitors.yml"
    dest: "/etc/heartbeat/monitors.d/{{ inventory_hostname }}.{{ item.0.split('.')[-1] }}.yml"
  when: (item.1 + '/' + item.0 + '/meta/monitors.yml') is file
  loop: "{{ roles | product(lookup('config', 'DEFAULT_ROLES_PATH')) | list }}"
  delegate_to: heartbeat_instance

Filebeat input

The role also includes a filebeat input file that can be uploaded to a filebeat server. The input reads the OpenVPN log and reads the lines that correspond to successful connections. The role includes an Elasticsearch ingest pipeline that can be imported to Elasticsearch to parse and break the log lines into fields. The files can be found under the meta/ folder.

Example playbook

See molecule/default/converge.yml for a working example of how to use this role.

License

Licensed under the MIT License. See the LICENSE file for details.

Feedback, bug-reports, requests, ...

...are welcome!

stouts.openvpn's People

Contributors

ahelal avatar alanmcg avatar conorsch avatar danielkza avatar exeral avatar gaieges avatar guessit-dev avatar hanxhx avatar juju4 avatar klen avatar lejmr avatar mbanton avatar mmalecki avatar mnaser avatar msheiny avatar nemesifier avatar neophiliac avatar nkakouros avatar quvide avatar rockingrolli avatar sbadia avatar slauger avatar tanmayaapyl avatar teadur avatar tkrille avatar vmanyushin avatar waldman avatar wtayyeb avatar zeelax avatar zuccon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stouts.openvpn's Issues

Default use of BF-CBC cipher is affected by SWEET32

https://community.openvpn.net/openvpn/wiki/SWEET32

The best mitigation is to transition away from small-block ciphers. 
This requires editting the cipher setting in all server and client configs 
(or upgrading to our experimental branch, see below).

Of the currently supported ciphers, OpenVPN currently recommends using 
AES-256-CBC or AES-128-CBC. 
OpenVPN 2.4 and newer will also support GCM. 
For 2.4+, we recommend using AES-256-GCM or AES-128-GCM.

Other references:

Default openvpn_use_pam_plugin_distribution variable for Ubuntu

I got a problem with ansible-playbook 2.0.0.2:
looks like it didn't recognize ubuntu trusty and use default value, that produced this error

PLUGIN_INIT: could not load plugin shared object /usr/lib/openvpn/openvpn-auth-pam.so: /usr/lib/openvpn/openvpn-auth-pam.so: cannot open shared object file: No such file or directory

Today most of all servers use ubuntu >= 14.04, it may be worth to change default variable into new path and leave additional files for previous or add checking that file exists?

OpenVPN with PAM authentication allows multiple passwords

I created an OpenVPN server using this role on my Ubuntu 16.04 machine, with the following variables:

....
openvpn_port: xxxx
openvpn_proto: xxx
openvpn_dev: xxx
openvpn_server: x.x.x.x x.x.x.x
openvpn_comp_lzo: yes
openvpn_cipher: AES-XXXXX
openvpn_tls_auth : yes
openvpn_user: nobody
openvpn_group: nogroup
openvpn_client_to_client: no
openvpn_verb: 4
openvpn_use_pam: yes
openvpn_use_pam_users: "{{ pam_user_array }}"
openvpn_clients:
  - myuser
.....

Because I want both PAM and certs, I removed the client-certs-not-required that is placed in the server.conf when using pam.

The password for myuser was D1$play9!!
I found by accident that I was able to login with that user using:

  • D1$play9!!
  • D1$play99
  • D1$play9999
  • D1$play99999
  • D1$play9090
  • D1$play99!!!!!!!!!

Why is this possible? This is a very serious security issue.

Remove force option from package installations

It is wildly dangerous to force installations/removals in unattended contexts. It will happily magnify a broken dependency into a broken system, which I don't ever find preferable to having the play fail.

Masquerade rule confusion. - Allow NATing outgoing vpn traffic

  when:
    - iptables_nat_rules.stdout.find("vpn_masquerade") == -1
    - not openvpn_server

with the not part in the rule, I can never manage to get the masquerade to be created
as the variable openvpn_server is always set as expected,
should it not be
- openvpn_server != ''
or am i missing something?
or maybe
- openvpn_masquerade == true

fix crl.pem permissions after client revoke

  stat: path={{openvpn_keydir}}/crl.pem
   register: crl_pem_file

+- name: Check crl.pem ACL
+  file: path={{openvpn_keydir}}/crl.pem
+        owner={{ openvpn_user }} mode=400
+
 - name: Generate Clients configurations
   template: src=client.conf.j2 dest={{openvpn_keydir}}/{{item.item.item.name}}.ovpn
   with_items: cert_fp.results

After client revoke crt.pem owner and group is root. Openvpn cannot restart

Use official `ansible_managed` template string

The role templates warn against hand-edits to config files in a non-standard fashion, including a hard-coded block that is not customizable:

# This file was generated by Ansible for {{ ansible_fqdn }}
# Do NOT modify this file by hand!

That's useful, but Ansible already provides a standardized method for such warnings, by setting the ansible_managed config var: http://docs.ansible.com/ansible/intro_configuration.html#ansible-managed The role templates should be updated to use that.

Upload inline scripts fails

When I populate openvpn_inline_scripts like this:

openvpn_inline_scripts:
   - name: my-up-script.sh
     content: |
       #!/usr/bin/env
       echo 'Up!' >> "/var/up.log"

the task Upload inline scripts from the file tasks/scripts.yml fails with the error src and dest are required. Which is also mentioned in the docs of the template-module: https://docs.ansible.com/ansible/latest/modules/template_module.html

Renaming the module template with copy in the task, solves the issue and the inline scripts are created.

.tar.gz not spawning in /etc/openvpn

I only have a zip file, I guess thats an error in the docs?
Also, I only see one key and one cert generated called client
Should the vpn users be added to the openvpn_clients?

Support for Ubuntu 18.04

I'm working through issues using this role on Ubuntu 18.04 (which includes OpenSSL 1.1.0), will do my best to provide an updates directly to the project.

Authentication exclusively through client certs

I need a little more info to guide me in setting up authentication to only use client certs.

I'm assuming that I have to turn off the other authentication methods and populate this var openvpn_clients

Then, setup
openvpn_unified_client_profiles=true
openvpn_tls_auth=true

At some point, I need to retrieve the certs and install them on my devices to finalize everything.

Conditional check fails

Getting the following error since yesterdays commits ( bc31cca )

fatal: [openvpn]: FAILED! => {"msg": "The conditional check 'iptables_rules.stdout.find(\"incoming_openvpn\") == -1' failed. The error was: error while evaluating conditional (iptables_rules.stdout.find(\"incoming_openvpn\") == -1): 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/home/user/.ansible/roles/openvpn/tasks/system/firewall-open.yml': line 2, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n---\n- name: Allow connections to the OpenVPN server\n ^ here\n"}

Had a look but can't see the direct cause.

CRL defaults to 30 days

The default value for CRL expiration is set to 30 days only in easyrsa/openssl-1.0.0.cnf in the provided easy_rsa.tar.gz from files:

default_crl_days= 30                  # how long before next CRL

This leaves no clients to be able to connect 30 days after one client was revoked.

I think updating the value to 3065 for example would be fine.
Providing a setting to override this value would be also an option.

Certificate password

Hi there! What do you think about using password for certificates?
Also on whom are you aim usage? I did some development to make passwords, it works fine for me. But also I aim configuration to WIndows users, so I included fingerprint into client config to let clients use WIndows Cert Store as it is way more secure than keep cert as a file in the system

If you're interested I can make precise pull request with some of these features

The task includes an option with an undefined variable

After change openvpn_unified_client_profiles from no to yes got error

TASK [Stouts.openvpn : Set client cert and CA info as fact.] *******************
fatal: [xxx]: FAILED! => {"failed": true, "msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'content'\n\nThe error appears to have been in '/home/user/.ansible/roles/Stouts.openvpn/tasks/read-client-files.yml': line 30, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Set client cert and CA info as fact.\n  ^ here\n\nexception type: <class 'ansible.errors.AnsibleUndefinedVariable'>\nexception: 'dict object' has no attribute 'content'"}

Local machine

Linux netbook 4.8.0-53-generic #56~16.04.1-Ubuntu SMP Tue May 16 01:14:44 UTC 2017 i686 i686 i686 GNU/Linux
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]

Server

Ubuntu 16.04.3 LTS
Python 3.5.2

comp-lzo option deprecated

The server option comp-lzo is deprecated in favor of --compression

--compress [algorithm]
Enable a compression algorithm.

The algorithm parameter may be "lzo", "lz4", or empty. LZO and LZ4 are different compression algorithms, with LZ4 generally offering the best performance with least CPU usage. For backwards compatibility with OpenVPN versions before v2.4, use "lzo" (which is identical to the older option "--comp-lzo yes").

If the algorithm parameter is empty, compression will be turned off, but the packet framing for compression will still be enabled, allowing a different setting to be pushed later. 

No package matching 'module-init-tools' is available (debian10)

Hi,

I just pulled new changes. including 4bcda3c
this adds tasks/system/firewall.yml
which tries to install module-init-tools on Debian

This package is only available on jessie (oldoldstable) : https://packages.debian.org/search?keywords=module-init-tools&searchon=names&suite=all&section=all

This break compatibility with many other Debian versions.
in my case it's Buster(10):

TASK [openvpn : Install firewall dependencies (Debian)] *************************************************************************************************************************************************************************************
fatal: [hostname]: FAILED! => {"changed": false, "msg": "No package matching 'module-init-tools' is available"}

Systemd service not created/started

Hi,

i have this configuration

- hosts: router
  roles: ['Stouts.openvpn']
  vars:
    openvpn_use_pam: no
    openvpn_clients: [scw]
    openvpn_unified_client_profiles: yes
    openvpn_tls_auth: yes

It executed without errors, i can see generated scw.ovpn in /etc/openvpn/keys/.
But actually it not works

> ps aux | grep open
root     10118  0.0  0.0  12948   936 pts/0    S+   11:36   0:00 grep --color=auto open
> ss -ln | grep 1194
> systemctl status | grep openvpn
└─10122 grep --color=auto openvpn

What i missed? (i don't want use PAM, i need simple connection)

Generates Certs In the Future

When certs are generated they are for 1 day in the future. Generated on Ubuntu 18.04 dest, with Centos 8 ansible host. Also crl file isn't generating but still included in directives.

Task 'Setup bridge' not executed when 'openvpn_bridge' is populated

I have set the following options for my bridge based setup:

"openvpn_bridge": {
        "address": "192.168.10.254",
        "broadcast": "192.168.10.255",
        "dhcp_end": "192.168.10.100",
        "dhcp_start": "192.168.10.20",
        "netmask": "255.255.255.0",
        "network": "192.168.10.0"
    }

From my expectation the task Setup bridge from the the file tasks/system/bridge/Debian.yml should be executed. I am on a Debian system and the file is included, however the filter openvpn_bridge | bool is evaluated to false. I have checked this with a debug statement in my playbook where I echo the var openvpn_bridge and openvpn_bridge | bool.

I would expect something like

when: openvpn_bridge is defined and openvpn_bridge|length > 0

would be a valid filter to check if the dictionary is popolated.

Or do I misunderstand the meaning of the variable openvpn_bridge?
Is there a working example for bridged based setups then?

Client configuration managment

Hi,

Really nice job for this role (like your other ones ;-) ). It would be good to be able to manage clients with previously generated certs. What do you think about it ?

Thanks

easy-rsa auditability

I audited the package in files/easy-rsa.tar.gz file against the source offered by openvpn. It looks like there are a few lines that are different, so I still do not know the entire audit trail for this file.

https://github.com/OpenVPN/easy-rsa/tree/release/2.x

This would take much less effort to audit if there was some versioning method available such as the git commit or version number or sha hash for whatever version this easy-rsa.tar.gz file is.

Even better would be a sub repository.

openssl.cnf file could be found

I've included Stdouts.openvpn role in the site.yml:

- hosts: bridges
  roles:
    - Stouts.openvpn
  vars:
    openvpn_server: 10.100.0.0 255.255.255.0
    openvpn_max_clients: 128
    openvpn_keepalive: "10 120"
    openvpn_server_options: # Additional server options
      - "client-to-client"
      - "dev-type tap"
      - "tls-server"
    openvpn_client_options: # Additional client options
      - client-to-client

    openvpn_key_size: 1024

    openvpn_clients: [asd]
    openvpn_clients_revoke: []

    # Use PAM authentication
    openvpn_use_pam: yes
    openvpn_use_pam_users:
      - { name: foo, password: password1 }

    # Whether to embed CA, cert, and key info inside client OVPN config file
    openvpn_unified_client_profiles: yes

When I try to run:

ansible-playbook -i inventory.yml site.yml

I get the following error:

TASK [Stouts.openvpn : Generate Clients keys] *********************************************
failed: [b1.cl-ops.it] (item=b1-cl-ops) => {"changed": true, "cmd": ["/etc/openvpn/build-client.sh", "b1-cl-ops"], "delta": "0:00:00.066120", "end": "2018-10-15 14:52:03.733415", "item": "b1-cl-ops", "msg": "non-zero return code", "rc": 1, "start": "2018-10-15 14:52:03.667295", "stderr": "**************************************************************\n  No /etc/openvpn/easy-rsa/openssl.cnf file could be found\n  Further invocations will fail\n**************************************************************\ngrep: /etc/openvpn/easy-rsa/openssl.cnf: No such file or directory", "stderr_lines": ["**************************************************************", "  No /etc/openvpn/easy-rsa/openssl.cnf file could be found", "  Further invocations will fail", "**************************************************************", "grep: /etc/openvpn/easy-rsa/openssl.cnf: No such file or directory"], "stdout": "NOTE: If you run ./clean-all, I will be doing a rm -rf on /etc/openvpn/keys\npkitool: KEY_CONFIG (set by the ./vars script) is pointing to the wrong\nversion of openssl.cnf: /etc/openvpn/easy-rsa/openssl.cnf\nThe correct version should have a comment that says: easy-rsa version 2.x", "stdout_lines": ["NOTE: If you run ./clean-all, I will be doing a rm -rf on /etc/openvpn/keys", "pkitool: KEY_CONFIG (set by the ./vars script) is pointing to the wrong", "version of openssl.cnf: /etc/openvpn/easy-rsa/openssl.cnf", "The correct version should have a comment that says: easy-rsa version 2.x"]}

In fact this is the content of /etc/openvpn/easy-rsa:
screenshot-2018-54-15 16 54 35 107

The installed openssl version is 1.1.0 which doesn't have a specific configuration file and isn't considered by easy-rsa.

make ldap URI configurable

ldaps (LDAP over SSL) support is missing since ldap uri scheme is hardcoded:
URL ldap://{{ openvpn_ldap_server }}

making uri scheme configurable would allow to use ldaps.

I can do a PR,
I would have done this by putting the whole string in {{ openvpn_ldap_server }} but this will break backward compatibility.
so,
create another parameter {{ openvpn_ldap_scheme }} ?

Client setup?

  • hosts: test
    become: "{{ become | default('yes') }}"
    roles:
    • Stouts.openvpn
      vars:
      openvpn_dev: vpnbas
      openvpn_max_clients: 256
      openvpn_key_country: IT
      openvpn_key_province: MT
      openvpn_key_city: Matera
      openvpn_key_org: Ninux Basilicata
      openvpn_key_email: [email protected]
      openvpn_key_size: 2048
      openvpn_use_pam: no
      openvpn_cipher: none
      openvpn_keepalive: "5 60"
      openvpn_topology: subnet
      openvpn_server: 10.27.253.0 255.255.255.0
      openvpn_clients: []
      openvpn_simple_auth: yes
      openvpn_simple_auth_password: passtestpass
      openvpn_bridge:
      address: 10.27.253.1
      netmask: 255.255.255.0
      network: 10.27.253.0
      broadcast: 10.27.253.255
      dhcp_start: 10.27.253.2
      dhcp_end: 10.27.253.254
      openvpn_server_options:
      • "dev-type tap"
      • "client-to-client"
      • "username-as-common-name"
      • "client-cert-not-required"
      • "tls-server"
      • "fast-io"

for esport config client?

Role must be run as root

Since there are no become=yes in tasks that requires sudo privileges, the whole role must be run as a superuser.

Is it possible to make it so that an unprivileged user could run this role.

Tharks !

when: open_vpn_pam_users fails when using variables for user credentials

v2.0.0

This config:

openvpn_use_pam_users:
- name: "{{ vpn_user }}"
  password: "{{ vpn_password }}"

...triggers this bug in ansible: ansible/ansible#9568

...resulting in this error:

TASK: [Stouts.openvpn | Install dependencies (Debian)] ************************
fatal: [10.8.2.176] => template error while templating string: expected token ',', got 'string'

This can be solved with this workaround, at https://github.com/Stouts/Stouts.openvpn/blob/develop/tasks/install.deb.yml#L9

when: openvpn_use_pam_users | default(false)

Failure during "Set Client cert and CA info as fact"

Ansible version: 2.2.0.0

Installed role via git.

TASK [Stouts.openvpn : Set client cert and CA info as fact.] *******************
fatal: [vpn1]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: Unable to look up a name or access an attribute in template string ({{ openvpn_read_tlsauth_file_results['content'] | b64decode | default('') }}).\nMake sure your variable name does not contain invalid characters like '-': a2b_base64() argument 1 must be convertible to a buffer, not StrictUndefined\n\nThe error appears to have been in '/usr/local/etc/ansible/roles/Stouts.openvpn/tasks/read-client-files.yml': line 30, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Set client cert and CA info as fact.\n  ^ here\n"}

Support for client traffic routing?

Does this role support client traffic routing via openvpn server?

In other words: I connect to the openvpn server and all my traffic (to the internet) gets routed through the server.

systemctl and service name on Debian Jessie

On Debian Jessie, it seems that when enabling, starting, restarting, etc openvpn with service or systemctl, the you have do specify he service name as openvpn@server. That's assuming that server is your config file.

I've tested out a fix and can send you a pull request. For that, do you want me to branch off of master or develop?

Thanks - David

More test coverage

The tests now run with the default variables.

TODO

Add more tests that explore non-default paths in role execution.

dh1024.pem

Hi

Just a little bug report ...

I was playing with this module, and I noticed that if I set the keysize to 2048, the openvpn-service wouldnt start as it was looking for dh1024.pem but the file that had been created was dh2048.pem

Im guessing line 44 in templates/server.conf.j2 need to have the hard-coded 1024 part replaced

Many thanks for the module, Im busy making it work with yum (as Im a Fedora user)

openvpn client

Is there an easy way to configure a new client.ovpn to use with the same openvpn server?
thanks

Interested in bridged mode?

I added support for bridged mode on my fork.

Are you interested in a patch? If yes I'll look into it.

Federico

Update galaxy

Latest version in galaxy is 2.0.5 and the current version is 2.2.0.

Stouts.openvpn doesn't work on debian stretch

Hello,

I just want to leave a note that role fails on debian stretch at "Read CA cert" task - there's openssl from 1.1 branch and whichopenssl fails to locate appropriate config file.

It was easier for me to use debian jessie at the moment, however maybe just creating simple symlink to openssl.cnf(which is default choice if openssl 1.0.x or 9.x is not found) would be satisfactory solution in this case.

masquerade firewall rule

apparently this role does not add the masquerade firewall rule. This caused my VPN connection to lose internet access when connected

Settle on how to treat openvpn options

The way openvpn config options are supported is a bit messy. It is a long list of possible values with no real cohesion. Many PRs have to do with adding this or that option. There are two ways to move forward:

  1. Support directly options that are 100% essential (by essential I mean options without which the config file will be invalid) and options that need special handling. The rest will be supported only via openvpn_server_options.

  2. Support all options via some logic. Instead of including every option in defaults/main.yml, the approach could be like in this or this role, ie have some kind of logic that checks/generates options either via some role tasks or via a shell script.

Though option 2 would feel nice to have in terms of completeness, openvpn is quite complex and option 1 seems the more sane approach.

Waiting for feedback by anyone interested.

Update Ansible galaxy

Hi,

Can you please update your Ansible galaxy role to be able to get latest available version.

Thanks

management option ?

Thinking in adding management option ?
It's just a line in the config: management 127.0.0.1 5555
Found this only thing missing from my perspective

Don't pack single files in tar

Hi!

Really great role. We use it a lot. Some Linux users have complained that the generated tar archive contains only files and not a folder containing files. So it would be nice to put the files in folder named like the archive and then create an archive of the folder. Just a detail.

Thanks!

zip files not produced.

set these and the playbook wont produce zip files. with only openvpn_clients and openvpn_use_pam set, it does. the goal was to have a server behind dhcp and nat that could reliably be reached from the outside.
the full Vagrantfile, playbooks, and a script session log are at the gist below.

role is at commit 1d08b23 Tue Feb 14 09:05:23 2017 -0800

    openvpn_use_pam: no
    openvpn_server: 
    openvpn_clients: [server,client]
    openvpn_server_options:
      - mode server
      - ifconfig 10.8.0.1 255.255.255.0
      - push "route-gateway 10.8.0.1"
      - ifconfig-pool 10.8.0.128 10.8.0.250 255.255.255.0
      - client_config_dir /etc/openvpn/ccd

https://gist.github.com/xahare/390e5f4645cdaee2f90011e26b9c5c50

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.