{"id":2245,"date":"2019-02-06T07:52:43","date_gmt":"2019-02-06T05:52:43","guid":{"rendered":"https:\/\/upcloud.com\/global\/us\/resources\/tutorials\/nictool-dns-setup\/"},"modified":"2019-02-06T07:52:43","modified_gmt":"2019-02-06T05:52:43","slug":"nictool-dns-setup","status":"publish","type":"tutorial","link":"https:\/\/upcloud.com\/global\/resources\/tutorials\/nictool-dns-setup\/","title":{"rendered":"How to use NicTool to set up your own domain name server"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This article describes instructions and configuration examples for setting up two DNS servers and an administrative web interface with NicTool.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/signup.upcloud.com\/\">Test hosting on UpCloud!<\/a><\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Setting up a very basic DNS infrastructure for oneself isn\u2019t really that hard. There are a lot of complete guides on the net for setting up a few BIND servers and making the first server notify and update the others. Also, the overall documentation on DNS server software is pretty good.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One thing outside of the basic setting, however, is the consolidated administration of every name server from a single place. Because a DNS zone (e.g. a domain name) needs two or more separate name servers, upon adding or removing a zone from the name server system there are configuration parameters that need to be updated on each of the domain\u2019s name servers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a very basic setup, setting an administrator can make the changes to each of their servers\u2019 configs by hand. Nowadays modern name servers can do zone transfers and update their zone information automatically from the master server in which case changes to config files by hand are not necessary unless adding or removing a zone. This method is the most straightforward to set up, has the smallest overhead, and works well for small and quite static setups.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On the other hand, if there are several administrators, many servers, or numerous zones which are added, modified, or removed often, the burden of making changes by hand becomes very pronounced. It\u2019s also easy to make mistakes when editing configs by hand. To ease this administration routine, there exists a tool called NicTool which presents itself as a web interface to manage the data on a predefined set of name servers. The tool\u2019s backend syncs all config and changes to the name servers and there is no need to touch anything other than the web UI.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Description of the setup<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This document describes setting up two DNS name servers onto two separate hosts and the installation of DNS server administration tool NicTool. The article\u2019s example was curated on CentOS 7 servers but you can, of course, use any Unix-like system of your liking.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The infrastructure is going to be as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ns1 (10.234.44.55) as a master NS with ISC BIND and the NicTool, and<\/li>\n\n\n\n<li>ns2 (10.234.55.66) as a slave NS with NSD.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">NicTool itself is divided into two components:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the client provides the web interface and manages the data in a MariaDB database which holds all information of managed zones and their data<\/li>\n\n\n\n<li>the server generates specific config files according to the current database and takes care of exporting them to each name server.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The article assumes the reader has the basic skills of administering their server machines.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setup procedure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The setup will go along the following procedure:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>install and configure BIND named on ns1 <sup><a href=\"https:\/\/github.com\/msimerson\/NicTool\/wiki\/Install-BIND-on-CentOS-6\" target=\"_blank\" rel=\"noopener\">[1]<\/a><\/sup><\/li>\n\n\n\n<li>prepare for NicTool on ns1: install and configure MariaDB, Apache and SSL<\/li>\n\n\n\n<li>install NicTool itself on ns1 <sup><a href=\"https:\/\/github.com\/msimerson\/NicTool\/wiki\/Install-NicToolClient\" target=\"_blank\" rel=\"noopener\">[2]<\/a><a href=\"https:\/\/github.com\/msimerson\/NicTool\/wiki\/Install-NicToolServer\" target=\"_blank\" rel=\"noopener\">[3]<\/a><\/sup><\/li>\n\n\n\n<li>configure configuration exports to other nameservers on ns1 <sup><a href=\"https:\/\/github.com\/msimerson\/NicTool\/wiki\/Export-to-BIND\" target=\"_blank\" rel=\"noopener\">[4]<\/a><\/sup><\/li>\n\n\n\n<li>install NSD on ns2 <sup><a href=\"https:\/\/github.com\/NLnetLabs\/nsd\" target=\"_blank\" rel=\"noopener\">[5]<\/a><\/sup><\/li>\n\n\n\n<li>configure exports to ns2 <sup><a href=\"https:\/\/www.linux.com\/news\/making-secure-remote-backups-rsync\" target=\"_blank\" rel=\"noopener\">[6]<\/a><\/sup><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Install ns1 named<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Everything begins by installing BIND on ns1:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">yum install bind bind-utils<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then, <tt>\/etc\/named.conf<\/tt> should have at least the following sections. Replace the IP address shown in red with the private IP of your slave nameserver, ns2:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">acl \"trusted\" {\n <span style=\"color: #ff0000;\">10.234.55.66<\/span>;\n};\n\noptions {\n listen-on port 53 { any; };\n listen-on-v6 port 53 { any; };\n allow-query { any; };\n allow-transfer { trusted; };\n version \"hmmm\";\n\n recursion no;\n};\n\ninclude \"\/opt\/nictool\/ns1\/named.conf.nictool\";\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A significant configuration directive is <tt>include<\/tt> with which we will feed the NicTool-generated configuration to BIND.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because we are running an authoritative name server it\u2019s important to ensure we are as widely reachable as possible (<tt>listen-on<\/tt> and <tt>allow-query<\/tt>). Equally important is not to allow recursion for unknown clients because of the amplification attack risk (<a href=\"https:\/\/www.us-cert.gov\/ncas\/alerts\/TA13-088A\" target=\"_blank\" rel=\"noopener\">US-CERT<\/a>). Enabling <tt>allow-transfer<\/tt> only to trusted hosts limits potentially needlessly big transfers of data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It\u2019s recommended in many sources as a best practice to hide name server version information to hinder easy harvesting of exploitable systems in case vulnerabilities are found from the name server software. However, as of writing this article, at least querying several root servers for such information (<tt>CHAOS bind.version<\/tt>) gives mixed results; some servers seem to reveal their version and some others don\u2019t. So far I haven\u2019t encountered any proper research which would state if obscurity is actually beneficial from the viewpoint of server administration. That said, was the version info hidden or not, the most critical part is obviously to commit to continuous administration of the server and keeping it up to date.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Reminder and notes: authoritative and recursive name servers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Authoritative<\/em> name server, as its name says, has authority over a zone (e.g. a domain and all of its possible subdomains). It means the authoritative name server is the master source of the information regarding the zone and it can also delegate some authority onwards to another server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, the authoritative name servers for <em>google.com<\/em> are <em>ns[1-4].google.com<\/em> when writing this. These servers know every hostname and subdomain under the google.com zone and if they don\u2019t, they know another server which knows. ns[1-4].google.com get their authority from <em>.com<\/em> top level domain name servers (which are <em>[a-m].gtld-servers.net<\/em>) which know every authoritative name server of every domain of <em>com<\/em> zone. In other words, they delegate the authority to other name servers and return the information about the delegated name servers to be queried next by the client.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Recursive<\/em> name server, or <em>resolver<\/em>, then, is a server which answers to all kinds of queries by clients and does the resolving work for them. Recursive name servers are no source of original information as they get every piece of information they know from authoritative name servers. Resolvers work in between the authoritative name servers and clients and by caching the results obtained in previous queries, they can reduce the traffic leaving a network and the load on authoritative name servers. So a recursive name server is fine if it\u2019s not openly queriable by everyone, but only a specified range of clients.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Recursive and authoritative server functions may reside in the same server instance but I would discourage it on the principle that authoritative name servers shouldn\u2019t do recursion at all. That is on the grounds of performance issues and possible easy misconfiguration. In this example, the recursive function is altogether disabled in BIND configuration, and NSD isn\u2019t even capable of doing recursion.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">NicTool preparations and prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Now it\u2019s time to install NicTool. First NicTool prerequisites are satisfied, then NicTool files are installed and the system configuration is done.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MariaDB (practically the GPL fork of Oracle MySQL) SQL DBMS is needed for information storage. Install MariaDB on ns1:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">yum install mariadb mariadb-server mariadb-devel\nsystemctl enable mariadb\nsystemctl start mariadb<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Apache web server is required for serving the frontend and we really want it secured. Install Apache with mod_ssl and Perl:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">yum install httpd httpd-devel mod_ssl epel-release\nyum install mod_perl mod_perl-devel<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Note: You should check whether the epel-release fingerprint is valid, below an example:<\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Retrieving key from file:\/\/\/etc\/pki\/rpm-gpg\/RPM-GPG-KEY-EPEL-7\nImporting GPG key 0x352C64E5:\n Userid     : \"Fedora EPEL (7) &lt;epel@fedoraproject.org&gt;\"\n Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5\n Package    : epel-release-7-11.noarch (@extras)\n From       : \/etc\/pki\/rpm-gpg\/RPM-GPG-KEY-EPEL-7\nIs this ok [y\/N]: y<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">systemctl enable httpd<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Install some Perl and other related stuff to satisfy NicTool install dependencies:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">yum install curl gcc make gettext gettext-devel rsync libxml2 libxml2-devel perl-Net-IP perl-XML-Parser perl-XML-LibXML perl-Digest-HMAC perl-ExtUtils-MakeMaker\nyum install cpan perl-Module-Build perl-LWP-Protocol-https<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Get the NicTool bundle and prepare it for installation. By default, NicTool is to be installed to <tt>\/usr\/local<\/tt> but I decided it\u2019s a more suitable and state-of-the-art way to install this kind of blob into <tt>\/opt<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd \/opt\nwget https:\/\/github.com\/msimerson\/NicTool\/archive\/master.zip\nyum install unzip -y &amp;&amp; unzip master.zip\nmv NicTool-master nictool\nrm master.zip<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add a user account for syncing the config files and <tt>chown<\/tt> NicTool files to the new user:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">useradd -d \/opt\/nictool -c \"nssync user\" -rU -s \/bin\/sh nssync\nchown nssync: nictool\/<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">On many systems, there already exists a <tt>bind<\/tt> user account but as a little extra security measure, I decided to go for a totally separate account. That\u2019s because I want to allow NicTool to alter only specific config files \u2013 not everything that&nbsp;<tt>bind<\/tt> user has write access to.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing NicTool files and dependencies<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run NicTool install scripts which install NicTool and seek to fulfil its dependencies:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd nictool\/client\/\nperl bin\/install_deps.pl\nperl Makefile.PL; make; make install clean\ncd ..\/server\/\nperl bin\/nt_install_deps.pl\nperl Makefile.PL; make; make install clean<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Some dependencies might fail installation and it\u2019s not a big deal. Just install them directly from CPAN.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">The following modules failed installation:\nApache::DBI\nBIND::Conf_Parser\nCrypt::KeyDerivation\nCrypt::Mac::HMAC\nCryptX\nNet::DNS::ZoneFile<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As of July 2018 perl-CGI has to be also installed from CPAN because the prepackaged version isn\u2019t new enough:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">yum remove perl-CGI\ncpan\n&gt; install CGI Apache::DBI BIND::Conf_Parser Crypt::KeyDerivation Crypt::Mac::HMAC CryptX Net::DNS::ZoneFile\n&gt; quit<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now everything should be ready for setting up the NicTool itself.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">NicTool system configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here the NicTool database and NicTool\u2019s own base configuration are set up.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First the SQL database is to be initialized:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># cd sql\/\n# perl create_tables.pl<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enter the database hostname and root password (that\u2019s empty for default installs).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enter parameters for creating the NicTool MariaDB user and the db itself;<br>Database name and user <tt>nictool<\/tt> are fine. Database password should be different from any other password as it\u2019s used only with the database connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">creating the nictool \u2018root\u2019 admin account in the db:<br>Give the script an email and a password for logging in at the NicTool GUI. The password should be totally solid, the infrastructure\u2019s integrity depends on it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You should probably record the information the script gives you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now to do NicTool server\u2019s system configuration.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># cd ..\/lib\n# cp nictoolserver.conf.dist nictoolserver.conf<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <tt>nictoolserver.conf<\/tt>, define the previously set database password in the <tt>nictoolserver.conf<\/tt> config file, and check the other config parameters are correct.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then configuring the NicTool client.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># cd ..\/..\/client\/lib\/\n# cp nictoolclient.conf.dist nictoolclient.conf<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <tt>nictoolclient.conf<\/tt>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>change <tt>\/usr\/local\/nictool\/client<\/tt> to <tt>\/opt\/nictool\/client<\/tt><\/li>\n\n\n\n<li>here are the parameters to be used for default DNS values.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">NicTool system configuration should be fine now but NicTool is yet waiting for the web server setup before it can be accessed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Web server setup with Apache and Let&#8217;s Encrypt<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">NicTool client (frontend) is served with Apache web server, at this step it is going to be installed with encryption.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Let\u2019s Encrypt<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Install the Let\u2019s Encrypt package:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">yum install python2-certbot-apache\nsystemctl start httpd<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <tt>\/etc\/httpd\/conf.d\/default_vhost.conf<\/tt> to accommodate Let\u2019s Encrypt temporary config, replace the server name with your domain and subdomain:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;VirtualHost _default_:80&gt;\n   DocumentRoot \"\/var\/www\/html\"\n   ServerName <span style=\"color: #ff0000;\">ns1.example.com<\/span>\n&lt;\/VirtualHost&gt;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The CentOS template on UpCloud includes <tt>firewalls,<\/tt> which blocks DNS, HTTP and HTTPS connections by default. Enable these with the following commands.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">firewall-cmd --permanent --add-service http\nfirewall-cmd --permanent --add-service https\nfirewall-cmd --permanent --add-service dns\nfirewall-cmd --reload<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then, the real thing of this step asking for <tt>certbot<\/tt> to issue and install a new certificate:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">certbot --apache -d <span style=\"color: #ff0000;\">ns1.example.com<\/span><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Follow the instructions to complete the certificate acquisition. In the last question about whether to redirect HTTP traffic to the encrypted channel, choose yes.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\"Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.\"\n-&gt; answer <tt>2<\/tt>.<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s Encrypt should request and install a new certificate, and modify the default <tt>vhost<\/tt> to make it redirect to HTTPS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Make <tt>certbot<\/tt> renew the certificates regularly by adding an entry to <tt>\/etc\/crontab<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">16   2  *  *  7 root       \/usr\/bin\/certbot renew -n --apache<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This tells <tt>cron<\/tt> to run the command as the \u2018root\u2019 user every Sunday (\u20187\u2019) at 2:16 o\u2019clock.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Apache<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Then to hone the Apache config. At a CentOS setup, begin by blanking the default <tt>ssl.conf<\/tt>. I backed it up to <tt>\/root<\/tt>. Blanking the file prevents system updates from replacing it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>On other distributions or OS\u2019es, your procedure may vary, but the desired config is presented later.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cp \/etc\/httpd\/conf.d\/ssl.conf \/root\/\necho &gt; \/etc\/httpd\/conf.d\/ssl.conf\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Get the NicTool example config for Apache:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd \/etc\/httpd\/conf.d\/\nwget http:\/\/www.nictool.com\/download\/nictool-24.conf\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the Apache config and <em>migrate the SSL part<\/em> from your <tt>default_vhost-le-ssl.conf<\/tt> to Apache NicTool configuration file:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><tt>nictool-24.conf<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">PerlRequire \/opt\/nictool\/client\/lib\/nictoolclient.conf\n\n# shouldn't be needed:\n#&lt;VirtualHost _default_:80&gt;\n#    # force a https connection\n#    ServerName <span style=\"color: #ff0000;\">ns1.example.com<\/span>\n#    Redirect \/ https:\/\/<span style=\"color: #ff0000;\">ns1.example.com<\/span>\/\n#&lt;\/VirtualHost&gt;\n\nListen 443\n&lt;VirtualHost *:443&gt;\n    ServerName <span style=\"color: #ff0000;\">ns1.example.com<\/span>\n\n#    DocumentRoot \/opt\/nictool\/client\/htdocs\n#    Alias \/images\/ \"\/opt\/nictool\/client\/htdocs\/images\/\"\n    Alias \/nictool\/ \"\/opt\/nictool\/client\/htdocs\/\"\n    RedirectMatch 301 ^\/$ https:\/\/<span style=\"color: #ff0000;\">example.com<\/span>\/\n\n    DirectoryIndex index.cgi index.html\n\n    SSLEngine on\n    SSLCertificateFile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">ns1.example.com<\/span>\/cert.pem\n    SSLCertificateKeyFile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">ns1.example.com<\/span>\/privkey.pem\n    Include \/etc\/letsencrypt\/options-ssl-apache.conf\n    SSLCertificateChainFile \/etc\/letsencrypt\/live\/<span style=\"color: #ff0000;\">ns1.example.com<\/span>\/chain.pem\n\n    &lt;Files \"*.cgi\"&gt;\n       SetHandler perl-script\n       PerlResponseHandler ModPerl::Registry\n       PerlOptions +ParseHeaders\n       Options +ExecCGI\n    &lt;\/Files&gt;\n\n    &lt;Directory \"\/opt\/nictool\/client\/htdocs\"&gt;\n        Require all granted\n    &lt;\/Directory&gt;\n&lt;\/VirtualHost&gt;\n\n&lt;IfDefine !MODPERL2&gt; \n   PerlFreshRestart On\n&lt;\/IfDefine&gt;\nPerlTaintCheck Off\n\nListen 8082\n\nPerlRequire \/opt\/nictool\/server\/lib\/nictoolserver.conf\n\n&lt;VirtualHost *:8082&gt;\n    KeepAlive Off\n    &lt;Location \/&gt;\n        SetHandler perl-script\n        PerlResponseHandler NicToolServer\n    &lt;\/Location&gt;\n    &lt;Location \/soap&gt;\n        SetHandler perl-script\n        PerlResponseHandler Apache::SOAP\n        PerlSetVar dispatch_to \"\/opt\/nictool\/server, NicToolServer::SOAP\"\n    &lt;\/Location&gt;\n&lt;\/VirtualHost&gt;\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Some notes about the config:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The NicTool directory is aliased to \/nictool\/ instead of the server root\n<ul class=\"wp-block-list\">\n<li>RedirectMatch directive is there to redirect the NicTool host\u2019s HTTP root to a real (e.g. company) website.<\/li>\n\n\n\n<li>One should switch comments at the beginning of the lines on <tt>DocumentRoot<\/tt> configuration block to host NicTool in the HTTP root of the server.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>In <tt>DirectoryIndex<\/tt> there has been added <tt>index.html<\/tt> as a fallback option so that some directories can have an HTML index page; try removing <tt>index.html<\/tt> if you encounter problems.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">After configuration,&nbsp;apply the config into effect:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mv nictool-24.conf z_nictool.conf\nrm default_vhost-le-ssl.conf\nsystemctl reload httpd\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And then\u2026 using a web browser go to the website and log in! -> <code>https:\/\/ns1.example.com\/nictool<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now the NicTool client\/frontend should be working. Next NicTool needs to be populated with the name server info and the server\/backend which executes the exports needs to be configured.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Populating NicTool with information<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here NicTool is set up with the minimum required amount of information to ultimately complete the setup. The payload (other zones and resource records) can be added whenever it suits the user.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, one should add a user for themselves from the NicTool web user interface (UI) and log in with it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When logged in at the web UI, at the Nameservers tab edit the name servers.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>First nameserver ns1:\n<ul class=\"wp-block-list\">\n<li>NS type <em>bind<\/em>,<\/li>\n\n\n\n<li>data directory <tt>\/opt\/nictool\/ns1<\/tt>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Second nameserver ns2:\n<ul class=\"wp-block-list\">\n<li>NS type <em>NSD<\/em>,<\/li>\n\n\n\n<li>data dir <tt>\/opt\/nictool\/ns2<\/tt>,<\/li>\n\n\n\n<li>remote login <em>nssync<\/em>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">In the web UI\u2019s Zones tab, there should exist at least one zone with the freshly edited name servers selected as the zone\u2019s name servers (so that there is something for NicTool to export).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/nictool-add-new-zone.png\" alt=\"NicTool adding new zone\" class=\"wp-image-7353\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Then add at least A records for the name servers in the new zone.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/nictool-nameserver-a-records.png\" alt=\"NicTool nameserver A records\" class=\"wp-image-7356\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Next, back at the shell, creating the config export directories for each name server:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd \/opt\/nictool\nsu -m nssync -c \"mkdir ns1 ns2\"<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Making the exports<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One of the most powerful features of NicTool is the ability to create and push a coherent and up-to-date config for every name server set up in it. Now to configure the exports from the NicTool server side:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd ns1\nln -s ..\/server\/bin\/nt_export.pl\nsu -m nssync -c .\/nt_export.pl<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">-&gt; Running <tt>nt_export.pl<\/tt> should show name servers that NicTool knows of.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Note: For me, there was something odd at this step and I didn\u2019t get the listing as described in the documentation and elsewhere. Anyway, it seems one can get the <tt>nsid<\/tt> information from the NicTool GUI too: just look at the ID number in the link URLs when configuring each name server.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because now we\u2019re configuring ns1 which has NicTool\u2019s <em>nsid 1<\/em> we use <tt>-nsid 1<\/tt> with the export script:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">su -m nssync -c '.\/nt_export.pl -nsid 1'<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">-&gt; This generates the <tt>run<\/tt> file which is basically a nice wrapper script for executing the export.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then open the&nbsp;<tt>run<\/tt>&nbsp;file in an editor and change the user name to <tt>nssync<\/tt>&nbsp;as below.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">EXPORT_USER=nssync<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run the <tt>run<\/tt> file to get a <tt>Makefile<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\/run<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">-&gt; In the <tt>Makefile<\/tt> one can define which commands NicTool executes at different stages of the export. Edit the Makefile restart section:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">restart: \/opt\/nictool\/ns1\/named.conf.nictool\n        sudo rndc reload\n        test 1<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">To give an unprivileged user the authority to reload the BIND config, <tt>sudo<\/tt> is used. The privilege must be granted in the <tt>\/etc\/sudoers<\/tt> file, open it using <tt>visudo<\/tt>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">visudo<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then add the following line:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">nssync  ALL=(ALL)       NOPASSWD: \/usr\/sbin\/rndc reload<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">-&gt; The line gives <tt>nssync<\/tt> user the permission to run the BIND named reload command <tt>rndc reload<\/tt> via <tt>sudo<\/tt> and no password.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NicTool generated BIND config file can be customized with a template:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mkdir templates\ntouch templates\/default<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then add the following to the <tt>default<\/tt> file. Replace the IP shown in red with the private IP address of the ns2 name server:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">zone \"ZONE\" {\n    type master;\n    file \"\/opt\/nictool\/ns1\/ZONE\";\n    notify yes;\n    also-notify {\n        <span style=\"color: #ff0000;\">10.234.55.66<\/span>;\n    };\n    allow-transfer {\n        <span style=\"color: #ff0000;\">10.234.55.66<\/span>;\n    };\n };<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Actually, <tt>notify<\/tt> and <tt>transfer<\/tt> shouldn\u2019t be needed since we push all the configs to slave servers. They\u2019re here as an example, one should remove them at their discretion.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To start and enable BIND:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">systemctl start named\nsystemctl enable named<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because the export is in the ns1 case done to the local filesystem, no remote login or other tricks are needed. Check the export is working like it should, i.e. config file is generated, put into a proper place, and the named server reloaded:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\/run<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now the first name server should be working, then to install the second.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Install ns2<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Up to this point all commands have been given to ns1. From now on the server is indicated before the command.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, install the Extra Packages for Enterprise Linux (EPEL) on the ns2 as well:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # yum install epel-release<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Install NSD and rsync along with the other requisites:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # yum install nsd rsync openssl sudo<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Also, enable DNS port at firewalld on ns2:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # firewall-cmd --add-service --permanent dns\nns2 # firewall-cmd --reload<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then, prepare the ns2 for NicTool export:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # mkdir -p \/opt\/nictool\/ns2\nns2 # useradd -d \/opt\/nictool -c \"nssync user\" -rU -s \/bin\/sh nssync\nns2 # chown -R nssync: \/opt\/nictool\/<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <tt>\/etc\/nsd\/nsd.conf<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">server:\n        # listen on IPv4\/6 connections\n        do-ip4: yes\n        do-ip6: yes\n\n        database: \"\"\n\n        logfile: \"\/var\/log\/nsd.log\"\n\n        # Optional local server config\n        include: \"\/etc\/nsd\/server.d\/*.conf\"\n\n# Include optional local configs.\ninclude: \"\/etc\/nsd\/conf.d\/*.conf\"\n\ninclude: \"\/opt\/nictool\/ns2\/nsd.nictool.conf\"\n\nremote-control:\n        # Enable remote control with nsd-control(8) here.\n        # set up the keys and certificates with nsd-control-setup.\n        control-enable: yes<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The last <tt>include:<\/tt> feeds our NicTool generated configuration to NSD. Although on CentOS 7 most of the defaults are fine, some things are explicitly defined in the configuration. You should follow the comments in the config file and read <em>nsd.conf(5)<\/em> manual when configuring your own server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">NSD keys and certs must be generated and the daemon enabled:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # nsd-control-setup\nns2 # systemctl enable nsd\nns2 # systemctl start nsd<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><tt>nsd-control-setup<\/tt> should create the keys and certificates into the default place so separate configuration in <tt>nsd.conf<\/tt> shouldn\u2019t be needed. You can of course explicitly define the files if you want.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After this, whenever needed, reload NSD config with:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # nsd-control reconfig &amp;&amp; nsd-control reload<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Setup exports for ns2<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As earlier mentioned, the exports work like:<br>-&gt; compile config files<br>-&gt; push new confs to name servers<br>-&gt; reload name servers\u2019 configs<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Setting up the export begins by doing the same magic as with ns1 export, but this time with <tt>-nsid 2<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns1 # cd \/opt\/nictool\/ns2\nns1 # ln -s ..\/server\/bin\/nt_export.pl\nns1 # su -m nssync -c '.\/nt_export.pl -nsid 2'<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Set the export user in <tt>run<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">EXPORT_USER=nssync<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run the export \u2013 it will fail because login hasn\u2019t been setup yet but it will generate the <tt>Makefile<\/tt>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tunc <tt>Makefile<\/tt> to suit ns2:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># NSD v4\ncompile: \/opt\/nictool\/ns2\/nsd.nictool.conf\n        test 1\n\nremote: \/opt\/nictool\/ns2\n        rsync -az --delete \/opt\/nictool\/ns2\/*.* nssync@<span style=\"color: #ff0000;\">10.234.55.66<\/span>:\/opt\/nictool\/ns2\/\n\nrestart: \/opt\/nictool\/ns2\n        ssh nssync@<span style=\"color: #ff0000;\">10.234.55.66<\/span> \"sudo nsd-control reconfig &amp;&amp; sudo nsd-control reload\"<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The IP address in the above config example refers to ns2.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Giving nssync the ability to control NSD with sudo<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <tt>\/etc\/sudoers<\/tt> using <tt>visudo<\/tt> (<tt>export EDITOR<\/tt> if needed\u2026) and add the following config line:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # visudo<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">nssync  ALL=(ALL)       NOPASSWD: \/usr\/sbin\/nsd-control<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The above line grants <tt>nssync<\/tt> user the ability to use <tt>nsd-control<\/tt> without password.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">SSH public key authentication<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Generate the keys which NicTool uses in export. Leave the key passphrase empty:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns1 # su -m nssync -c 'ssh-keygen -t rsa'<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">On ns2 make the <tt>nssync<\/tt> user able to login via SSH public key:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # mkdir \/opt\/nictool\/.ssh<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Insert ns1\u2019s public key (from <tt>\/opt\/nictool\/.ssh\/id_rsa.pub<\/tt>) into ns2\u2019s <tt>\/opt\/nictool\/.ssh\/authorized_keys<\/tt> file. Replace the IP with the private IP and the domain with the server name of your first name server:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">from=\"<span style=\"color: #ff0000;\">10.234.44.55<\/span>\" ssh-rsa AAAAB3NzaC1fae[...] nssync@<span style=\"color: #ff0000;\">ns1.example.com<\/span><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In which the&nbsp;<tt>from=<\/tt>&nbsp;is the private IP of the master nameserver from where the key is accepted only.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SSH won\u2019t accept <tt>authorized_keys<\/tt> without proper permissions:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns2 # chown -R nssync: ~nssync\/.ssh\nns2 # chmod 700 ~nssync\/.ssh &amp;&amp; chmod 600 ~nssync\/.ssh\/authorized_keys<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The export might initially fail because the underlying <tt>ssh<\/tt> is confused about some things. I encountered two types of problems:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>SSH does not know about the private key to use in the authentication process, and<\/li>\n\n\n\n<li>SSH fails to check the remote host key.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">In the first case the use of private key has to be stated by giving rsync the option <tt>-e 'ssh -i ~nssync\/.ssh\/id_rsa'<\/tt>, as seen in the snippet from ns1\u2019s <tt>\/opt\/nictool\/ns2\/Makefile<\/tt>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">remote: \/opt\/nictool\/ns2\n        rsync -az --delete -e 'ssh -i ~nssync\/.ssh\/id_rsa' \n        \/opt\/nictool\/ns2\/*.* nssync@<span style=\"color: #ff0000;\">10.234.55.66<\/span>:\/opt\/nictool\/ns2\/<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the second case, SSH wants to do the remote host key checking but the key doesn\u2019t yet exist in <tt>~nssync\/.ssh\/known_hosts<\/tt>. This can be solved by ensuring the ns2\u2019s SSH host key is in the <tt>known_hosts<\/tt> file, something like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns1 # su -m nssync -c 'ssh-keyscan -H <span style=\"color: #ff0000;\">10.234.55.66<\/span> &gt;&gt; ~nssync\/.ssh\/known_hosts'<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">SSH may also be forced <em>not<\/em> to do the strict key checking by adopting this option in the <tt>rsync<\/tt> command: <tt>-e 'ssh -o StrictHostKeyChecking=no'<\/tt>. However, I wouldn\u2019t recommend using it in a real-world environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Doing the exports automatically using cron<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One of the last steps is to make the exports run automatically. As the export to a specific server is done by executing the corresponding <tt>run<\/tt> script, we can run each export periodically from cron.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <tt>nssync<\/tt> user\u2019s crontab on ns1:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ns1 # crontab -eu nssync<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The following lines run the <tt>run<\/tt> scripts at the interval of 15 minutes. One line should exist for each synced nameserver. In other words, the changes made using the NicTool GUI are exported to nameservers every <tt>run<\/tt>. One should adjust the interval to their needs.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">*\/15 * * * * \/opt\/nictool\/ns1\/run\n*\/15 * * * * \/opt\/nictool\/ns2\/run<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At this point each <tt>run<\/tt> file in <tt>\/opt\/nictool\/ns?\/<\/tt> has to be checked that the command suited for periodical execution is uncommented and the command for interactive use is commented out.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">######################################################\n# For use with periodic triggers like cron and at\n######################################################\nexec \/usr\/bin\/perl .\/nt_export.pl -nsid 1 -pfextra | logger -t nt_export\n...\n######################################################\n# For interactive human use.\n######################################################\n# Note that the -force option is included, as you likely want to export\n# regardless of DB changes since the last successful export.\n#exec su -m $EXPORT_USER -c \" .\/nt_export.pl -nsid 1 -force -pfextra \"<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Delegate authority to your nameservers<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With the new name servers up and working, you migth want to delegate authority to them. The ns1 has already been configured as authoritative but your domain still needs to know where to find the server name records.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This process will depend on your domain name registrar but should be quite simple. Go to your domain name registrar and log in to their control panel or dashboard. In your domain\u2019s management, find the option that allows you to specify custom name servers.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/domain-name-authority.png\" alt=\"Domain name authority\" class=\"wp-image-7365\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Enter the public IP addresses of the <tt>ns1<\/tt> and <tt>ns2<\/tt> in the available fields and save. Telling your domain name registrar to delegate authority over your domain to your new NS allows the setup to take control of the domain. Instead of the regular A records, the registrar will create a glue record to the specific IP addresses which tells other name servers on the internet who to ask about your records under domain.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once done, the domain name registrar will begin to advertise the new name servers as authoritative over your domain. The changes might take some time to propagate, usually between 24-48 hour.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The final discussion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">NicTool should be now able to export the respective configs to ns1 and ns2 automatically and reload the servers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Making changes to DNS records from the GUI and running corresponding <tt>run<\/tt> scripts on ns1 should now be fully functioning and export each configuration without any further user intervention.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By adapting these instructions more name servers can be added to the system.<\/p>\n","protected":false},"author":18,"featured_media":27433,"comment_status":"open","ping_status":"closed","template":"","community-category":[223,259],"class_list":["post-2245","tutorial","type-tutorial","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/types\/tutorial"}],"author":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/users\/18"}],"replies":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/comments?post=2245"}],"version-history":[{"count":0,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/2245\/revisions"}],"wp:attachment":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/media?parent=2245"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/community-category?post=2245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}