├── VERSION ├── Dockerfile ├── release.sh ├── exec.sh ├── README.md └── openssl.cnf /VERSION: -------------------------------------------------------------------------------- 1 | 1.2.5 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:8 2 | LABEL Description="ztncui (a ZeroTier network controller user interface) + Zerotier One" Vendor="Key Networks (https://key-networks.com)" 3 | ADD VERSION . 4 | 5 | COPY build.sh /usr/bin/ 6 | RUN build.sh 7 | 8 | EXPOSE 8000/tcp 9 | EXPOSE 3443/tcp 10 | 11 | COPY exec.sh /usr/sbin/ 12 | ENTRYPOINT ["/usr/sbin/exec.sh"] 13 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Derived from https://medium.com/travis-on-docker/how-to-version-your-docker-images-1d5c577ebf54 3 | 4 | set -ex 5 | 6 | USERNAME=keynetworks 7 | IMAGE=ztncui 8 | 9 | # bump version 10 | docker run --rm -v "$PWD":/app treeder/bump patch 11 | version=`cat VERSION` 12 | echo "version: $version" 13 | # run build 14 | docker build -t $USERNAME/$IMAGE:latest . 15 | 16 | # tag it 17 | git add -A 18 | git commit -m "version $version" 19 | git tag -a "$version" -m "version $version" 20 | #git push 21 | #git push --tags 22 | docker tag $USERNAME/$IMAGE:latest $USERNAME/$IMAGE:$version 23 | # push it 24 | docker login --username=$USERNAME 25 | docker push $USERNAME/$IMAGE:latest 26 | docker push $USERNAME/$IMAGE:$version 27 | -------------------------------------------------------------------------------- /exec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HTTP_ALL_INTERFACES=${HTTP_ALL_INTERFACES} 4 | HTTP_PORT=${HTTP_PORT:-3000} 5 | HTTPS_PORT=${HTTPS_PORT:-3443} 6 | 7 | /usr/sbin/zerotier-one & 8 | 9 | while [ ! -f /var/lib/zerotier-one/authtoken.secret ]; do 10 | sleep 1 11 | done 12 | chown zerotier-one.zerotier-one /var/lib/zerotier-one/authtoken.secret 13 | chmod 640 /var/lib/zerotier-one/authtoken.secret 14 | 15 | cd /opt/key-networks/ztncui 16 | 17 | echo "HTTP_PORT=$HTTP_PORT" > /opt/key-networks/ztncui/.env 18 | if [ ! -z $HTTP_ALL_INTERFACES ]; then 19 | echo "HTTP_ALL_INTERFACES=$HTTP_ALL_INTERFACES" >> /opt/key-networks/ztncui/.env 20 | else 21 | [ ! -z $HTTPS_PORT ] && echo "HTTPS_PORT=$HTTPS_PORT" >> /opt/key-networks/ztncui/.env 22 | fi 23 | 24 | exec sudo -u ztncui /opt/key-networks/ztncui/ztncui 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ztncui-containerized 2 | ## ZeroTier network controller user interface in a Docker container 3 | 4 | This is a Docker image that contains **[ZeroTier One](https://www.zerotier.com/download.shtml)** and **[ztncui](https://key-networks.com/ztncui)** to set up a **standalone ZeroTier network controller** with a web user interface in a container. 5 | 6 | Follow us on [![alt @key_networks on Twitter](https://i.imgur.com/wWzX9uB.png)](https://twitter.com/key_networks) 7 | 8 | ## Note 9 | The keynetworks/ztncui Docker image is now being build with https://github.com/key-networks/ztncui-aio - this repo is just being maintained for reference to documentation. 10 | 11 | ## Docker run 12 | ```shell 13 | docker run --name ztncui -dp 3443:3443 keynetworks/ztncui 14 | ``` 15 | See below for a more secure way of running the container. 16 | 17 | ## Connect to the user interface 18 | Open a web browser to `https://docker_host:3443` where docker_host is the hostname or IP address of the machine running the container. 19 | 20 | ## Password 21 | The default username is **admin** and default password is **password**. It would be best practice to restrict access to port 3443 of docker_host to the IP address of your machine before running the container, so that nobody else can login before you do. You can do this as follows: 22 | 23 | First assign your IP address to an environment variable, for example: 24 | ```shell 25 | MYADDR=12.34.56.78 26 | ``` 27 | This is to allow you to execute the following two commands in one shot to minimise the chance of some nefarious character getting in before you do: 28 | ```shell 29 | docker run --name ztncui -dp 3443:3443 keynetworks/ztncui && \ 30 | docker exec ztncui iptables -I INPUT -i eth0+ ! -s $MYADDR -p tcp --dport 3443 -j DROP 31 | ``` 32 | 33 | ## Persist Data in volumes 34 | If you want to persist the ZeroTier and ztncui data in volumes outside of the container, then use this approach: 35 | 36 | First assign your IP address to an environment variable, for example: 37 | ```shell 38 | MYADDR=12.34.56.78 39 | ``` 40 | Then, execute in one shot: 41 | ```shell 42 | docker run -dp 3443:3443 --name ztncui --volume ztncui:/opt/key-networks/ztncui/etc/ \ 43 | --volume zt1:/var/lib/zerotier-one/ keynetworks/ztncui && \ 44 | docker exec ztncui iptables -I INPUT -i eth0+ ! -s $MYADDR -p tcp --dport 3443 -j DROP 45 | ``` 46 | 47 | ## Copy volumes to another Docker host 48 | For various reasons (controller backup, redundancy, etc), it is useful to be able to copy the zt1 and ztncui volumes from one Docker host to another. 49 | To copy the volumes from host1 to host2, first stop the ztncui container on host1: 50 | ```shell 51 | docker stop ztncui 52 | ``` 53 | To copy the ztncui volume from host1 to host2, execute the following on host1: 54 | ```shell 55 | docker run --rm --volume ztncui:/from alpine ash -c "cd /from ; tar -cf - . " | ssh user@host2 'docker run --rm -i --volume ztncui:/to alpine ash -c "cd /to ; tar -xpvf - " ' 56 | ``` 57 | To copy the zt1 volume from host1 to host2, execute the following on host1: 58 | ```shell 59 | docker run --rm --volume zt1:/from alpine ash -c "cd /from ; tar -cf - . " | ssh user@host2 'docker run --rm -i --volume zt1:/to alpine ash -c "cd /to ; tar -xpvf - " ' 60 | ``` 61 | To run the container on host2: 62 | ```shell 63 | docker run -dp 3443:3443 --name ztncui --volume ztncui:/opt/key-networks/ztncui/etc/ \ 64 | --volume zt1:/var/lib/zerotier-one/ keynetworks/ztncui 65 | ``` 66 | 67 | ## Pass environment variables 68 | As per https://github.com/key-networks/ztncui#summary-of-listening-states, environment variables can be passed with --env as of ztncui:1.2.2. Note that as of version 1.2.3 of the Docker image, passing `HTTP_ALL_INTERFACES=yes` will cause `HTTPS_PORT` to be ignored. Here is an example of how to pass environment variables: 69 | ```shell 70 | docker run --env HTTP_PORT=8000 --env HTTP_ALL_INTERFACES=yes -dp 8000:8000 --name ztncui keynetworks/ztncui 71 | ``` 72 | Note that the above will expose HTTP on the docker host. This can be useful for offloading TLS to a proxy, but you should not expose HTTP directly to the Internet. 73 | 74 | ## Screenshots 75 | Screenshots can be found at https://key-networks.com/ztncui#screenshots 76 | 77 | ## Usage 78 | Usage is describe in `README.md` displayed at https://github.com/key-networks/ztncui 79 | 80 | ## Source Code 81 | The source code for ztncui is at https://github.com/key-networks/ztncui 82 | 83 | The source code for the docker image is in this repository. 84 | 85 | ## Feedback 86 | Please give us your feedback. Please use the contact form at [key-networks.com](https://key-networks.com/). 87 | 88 | ## Bug and Vulnerability Reporting 89 | Problems can be reported using the GitHub issue tracking system. Please use the contact form at [key-networks.com](https://key-networks.com/) to privately report potential vulnerabilities. Thank you. 90 | 91 | ## License 92 | This is open source code, licensed under the GNU GPLv3, and is free to use on those terms. If you are interested in commercial licensing, please contact us via the contact form at [key-networks.com](https://key-networks.com) . 93 | 94 | ## Thanks 95 | @flantel for contributing "Update exec.sh to allow override of HTTP_ variables from environment". 96 | 97 | https://www.guidodiepen.nl/2016/05/transfer-docker-data-volume-to-another-host/ for command line for copying Docker volumes between machines. 98 | 99 | @mark-stopka for contributing "Modify to enable TLS offload using Traefik". 100 | 101 | @mdPlusPlus for clues on removing the requirement for --cap-add=NET_ADMIN and avoiding clashes with Ubuntu UIDs and GIDs. 102 | -------------------------------------------------------------------------------- /openssl.cnf: -------------------------------------------------------------------------------- 1 | # 2 | # OpenSSL example configuration file. 3 | # This is mostly being used for generation of certificate requests. 4 | # 5 | 6 | # This definition stops the following lines choking if HOME isn't 7 | # defined. 8 | HOME = . 9 | RANDFILE = $ENV::HOME/.rnd 10 | 11 | # Extra OBJECT IDENTIFIER info: 12 | #oid_file = $ENV::HOME/.oid 13 | oid_section = new_oids 14 | 15 | # To use this configuration file with the "-extfile" option of the 16 | # "openssl x509" utility, name here the section containing the 17 | # X.509v3 extensions to use: 18 | # extensions = 19 | # (Alternatively, use a configuration file that has only 20 | # X.509v3 extensions in its main [= default] section.) 21 | 22 | [ new_oids ] 23 | 24 | # We can add new OIDs in here for use by 'ca', 'req' and 'ts'. 25 | # Add a simple OID like this: 26 | # testoid1=1.2.3.4 27 | # Or use config file substitution like this: 28 | # testoid2=${testoid1}.5.6 29 | 30 | # Policies used by the TSA examples. 31 | tsa_policy1 = 1.2.3.4.1 32 | tsa_policy2 = 1.2.3.4.5.6 33 | tsa_policy3 = 1.2.3.4.5.7 34 | 35 | #################################################################### 36 | [ ca ] 37 | default_ca = CA_default # The default ca section 38 | 39 | #################################################################### 40 | [ CA_default ] 41 | 42 | dir = /etc/pki/CA # Where everything is kept 43 | certs = $dir/certs # Where the issued certs are kept 44 | crl_dir = $dir/crl # Where the issued crl are kept 45 | database = $dir/index.txt # database index file. 46 | #unique_subject = no # Set to 'no' to allow creation of 47 | # several certs with same subject. 48 | new_certs_dir = $dir/newcerts # default place for new certs. 49 | 50 | certificate = $dir/cacert.pem # The CA certificate 51 | serial = $dir/serial # The current serial number 52 | crlnumber = $dir/crlnumber # the current crl number 53 | # must be commented out to leave a V1 CRL 54 | crl = $dir/crl.pem # The current CRL 55 | private_key = $dir/private/cakey.pem# The private key 56 | RANDFILE = $dir/private/.rand # private random number file 57 | 58 | x509_extensions = usr_cert # The extensions to add to the cert 59 | 60 | # Comment out the following two lines for the "traditional" 61 | # (and highly broken) format. 62 | name_opt = ca_default # Subject Name options 63 | cert_opt = ca_default # Certificate field options 64 | 65 | # Extension copying option: use with caution. 66 | # copy_extensions = copy 67 | 68 | # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs 69 | # so this is commented out by default to leave a V1 CRL. 70 | # crlnumber must also be commented out to leave a V1 CRL. 71 | # crl_extensions = crl_ext 72 | 73 | default_days = 365 # how long to certify for 74 | default_crl_days= 30 # how long before next CRL 75 | default_md = sha256 # use SHA-256 by default 76 | preserve = no # keep passed DN ordering 77 | 78 | # A few difference way of specifying how similar the request should look 79 | # For type CA, the listed attributes must be the same, and the optional 80 | # and supplied fields are just that :-) 81 | policy = policy_match 82 | 83 | # For the CA policy 84 | [ policy_match ] 85 | countryName = match 86 | stateOrProvinceName = match 87 | organizationName = match 88 | organizationalUnitName = optional 89 | commonName = supplied 90 | emailAddress = optional 91 | 92 | # For the 'anything' policy 93 | # At this point in time, you must list all acceptable 'object' 94 | # types. 95 | [ policy_anything ] 96 | countryName = optional 97 | stateOrProvinceName = optional 98 | localityName = optional 99 | organizationName = optional 100 | organizationalUnitName = optional 101 | commonName = supplied 102 | emailAddress = optional 103 | 104 | #################################################################### 105 | [ req ] 106 | prompt = no 107 | default_bits = 2048 108 | default_md = sha256 109 | default_keyfile = privkey.pem 110 | distinguished_name = req_distinguished_name 111 | attributes = req_attributes 112 | x509_extensions = v3_ca # The extensions to add to the self signed cert 113 | 114 | # Passwords for private keys if not present they will be prompted for 115 | # input_password = secret 116 | # output_password = secret 117 | 118 | # This sets a mask for permitted string types. There are several options. 119 | # default: PrintableString, T61String, BMPString. 120 | # pkix : PrintableString, BMPString (PKIX recommendation before 2004) 121 | # utf8only: only UTF8Strings (PKIX recommendation after 2004). 122 | # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). 123 | # MASK:XXXX a literal mask value. 124 | # WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. 125 | string_mask = utf8only 126 | 127 | # req_extensions = v3_req # The extensions to add to a certificate request 128 | 129 | [ req_distinguished_name ] 130 | countryName = AU 131 | 132 | stateOrProvinceName = Western Australia 133 | #stateOrProvinceName_default = Default Province 134 | 135 | localityName = Perth 136 | 137 | 0.organizationName = Key Networks (https://key-networks.com) 138 | 139 | # we can do this but it is not needed normally :-) 140 | #1.organizationName = Second Organization Name (eg, company) 141 | #1.organizationName_default = World Wide Web Pty Ltd 142 | 143 | organizationalUnitName = Engineering 144 | #organizationalUnitName_default = 145 | 146 | commonName = localhost 147 | 148 | emailAddress = noreply@key-networks.com 149 | 150 | # SET-ex3 = SET extension number 3 151 | 152 | [ req_attributes ] 153 | challengePassword = A challenge password 154 | challengePassword_min = 4 155 | challengePassword_max = 20 156 | 157 | unstructuredName = An optional company name 158 | 159 | [ usr_cert ] 160 | 161 | # These extensions are added when 'ca' signs a request. 162 | 163 | # This goes against PKIX guidelines but some CAs do it and some software 164 | # requires this to avoid interpreting an end user certificate as a CA. 165 | 166 | basicConstraints=CA:FALSE 167 | 168 | # Here are some examples of the usage of nsCertType. If it is omitted 169 | # the certificate can be used for anything *except* object signing. 170 | 171 | # This is OK for an SSL server. 172 | # nsCertType = server 173 | 174 | # For an object signing certificate this would be used. 175 | # nsCertType = objsign 176 | 177 | # For normal client use this is typical 178 | # nsCertType = client, email 179 | 180 | # and for everything including object signing: 181 | # nsCertType = client, email, objsign 182 | 183 | # This is typical in keyUsage for a client certificate. 184 | # keyUsage = nonRepudiation, digitalSignature, keyEncipherment 185 | 186 | # This will be displayed in Netscape's comment listbox. 187 | nsComment = "OpenSSL Generated Certificate" 188 | 189 | # PKIX recommendations harmless if included in all certificates. 190 | subjectKeyIdentifier=hash 191 | authorityKeyIdentifier=keyid,issuer 192 | 193 | # This stuff is for subjectAltName and issuerAltname. 194 | # Import the email address. 195 | # subjectAltName=email:copy 196 | # An alternative to produce certificates that aren't 197 | # deprecated according to PKIX. 198 | # subjectAltName=email:move 199 | 200 | # Copy subject details 201 | # issuerAltName=issuer:copy 202 | 203 | #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem 204 | #nsBaseUrl 205 | #nsRevocationUrl 206 | #nsRenewalUrl 207 | #nsCaPolicyUrl 208 | #nsSslServerName 209 | 210 | # This is required for TSA certificates. 211 | # extendedKeyUsage = critical,timeStamping 212 | 213 | [ v3_req ] 214 | 215 | # Extensions to add to a certificate request 216 | 217 | basicConstraints = CA:FALSE 218 | keyUsage = nonRepudiation, digitalSignature, keyEncipherment 219 | 220 | [ v3_ca ] 221 | 222 | 223 | # Extensions for a typical CA 224 | 225 | 226 | # PKIX recommendation. 227 | 228 | subjectKeyIdentifier=hash 229 | 230 | authorityKeyIdentifier=keyid:always,issuer 231 | 232 | basicConstraints = critical,CA:true 233 | 234 | # Key usage: this is typical for a CA certificate. However since it will 235 | # prevent it being used as an test self-signed certificate it is best 236 | # left out by default. 237 | # keyUsage = cRLSign, keyCertSign 238 | 239 | # Some might want this also 240 | # nsCertType = sslCA, emailCA 241 | 242 | # Include email address in subject alt name: another PKIX recommendation 243 | # subjectAltName=email:copy 244 | # Copy issuer details 245 | # issuerAltName=issuer:copy 246 | 247 | # DER hex encoding of an extension: beware experts only! 248 | # obj=DER:02:03 249 | # Where 'obj' is a standard or added object 250 | # You can even override a supported extension: 251 | # basicConstraints= critical, DER:30:03:01:01:FF 252 | 253 | [ crl_ext ] 254 | 255 | # CRL extensions. 256 | # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. 257 | 258 | # issuerAltName=issuer:copy 259 | authorityKeyIdentifier=keyid:always 260 | 261 | [ proxy_cert_ext ] 262 | # These extensions should be added when creating a proxy certificate 263 | 264 | # This goes against PKIX guidelines but some CAs do it and some software 265 | # requires this to avoid interpreting an end user certificate as a CA. 266 | 267 | basicConstraints=CA:FALSE 268 | 269 | # Here are some examples of the usage of nsCertType. If it is omitted 270 | # the certificate can be used for anything *except* object signing. 271 | 272 | # This is OK for an SSL server. 273 | # nsCertType = server 274 | 275 | # For an object signing certificate this would be used. 276 | # nsCertType = objsign 277 | 278 | # For normal client use this is typical 279 | # nsCertType = client, email 280 | 281 | # and for everything including object signing: 282 | # nsCertType = client, email, objsign 283 | 284 | # This is typical in keyUsage for a client certificate. 285 | # keyUsage = nonRepudiation, digitalSignature, keyEncipherment 286 | 287 | # This will be displayed in Netscape's comment listbox. 288 | nsComment = "OpenSSL Generated Certificate" 289 | 290 | # PKIX recommendations harmless if included in all certificates. 291 | subjectKeyIdentifier=hash 292 | authorityKeyIdentifier=keyid,issuer 293 | 294 | # This stuff is for subjectAltName and issuerAltname. 295 | # Import the email address. 296 | # subjectAltName=email:copy 297 | # An alternative to produce certificates that aren't 298 | # deprecated according to PKIX. 299 | # subjectAltName=email:move 300 | 301 | # Copy subject details 302 | # issuerAltName=issuer:copy 303 | 304 | #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem 305 | #nsBaseUrl 306 | #nsRevocationUrl 307 | #nsRenewalUrl 308 | #nsCaPolicyUrl 309 | #nsSslServerName 310 | 311 | # This really needs to be in place for it to be a proxy certificate. 312 | proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo 313 | 314 | #################################################################### 315 | [ tsa ] 316 | 317 | default_tsa = tsa_config1 # the default TSA section 318 | 319 | [ tsa_config1 ] 320 | 321 | # These are used by the TSA reply generation only. 322 | dir = ./demoCA # TSA root directory 323 | serial = $dir/tsaserial # The current serial number (mandatory) 324 | crypto_device = builtin # OpenSSL engine to use for signing 325 | signer_cert = $dir/tsacert.pem # The TSA signing certificate 326 | # (optional) 327 | certs = $dir/cacert.pem # Certificate chain to include in reply 328 | # (optional) 329 | signer_key = $dir/private/tsakey.pem # The TSA private key (optional) 330 | signer_digest = sha256 # Signing digest to use. (Optional) 331 | default_policy = tsa_policy1 # Policy if request did not specify it 332 | # (optional) 333 | other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) 334 | digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) 335 | accuracy = secs:1, millisecs:500, microsecs:100 # (optional) 336 | clock_precision_digits = 0 # number of digits after dot. (optional) 337 | ordering = yes # Is ordering defined for timestamps? 338 | # (optional, default: no) 339 | tsa_name = yes # Must the TSA name be included in the reply? 340 | # (optional, default: no) 341 | ess_cert_id_chain = no # Must the ESS cert id chain be included? 342 | # (optional, default: no) 343 | --------------------------------------------------------------------------------