One place for hosting & domains

      Basic

      How To Use Basic Types in TypeScript


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      TypeScript is an extension of the JavaScript language that uses JavaScript’s runtime with a compile-time type checker. This combination allows developers to use the full JavaScript ecosystem and language features, while also adding optional static type-checking, enum data types, classes, and interfaces. These features provide the developer with the flexibility of JavaScript’s dynamic nature, but also allow for a more reliable codebase, where type information can be used at compile-time to detect possible issues that could cause bugs or other unexpected behavior at runtime.

      The extra type information also provides better documentation of codebases and improved IntelliSense (code completion, parameters info, and similar content assist features) in text editors. Teammates can identify exactly what types are expected for any variable or function parameter, without having to go through the implementation itself.

      This tutorial will go through type declaration and all the basic types used in TypeScript. It will lead you through examples with different code samples, which you can follow along with in your own TypeScript environment or the TypeScript Playground, an online environment that allows you to write TypeScript directly in the browser.

      Prerequisites

      To follow this tutorial, you will need:

      • An environment in which you can execute TypeScript programs to follow along with the examples. To set this up on your local machine, you will need the following.
      • If you do not wish to create a TypeScript environment on your local machine, you can use the official TypeScript Playground to follow along.
      • You will need sufficient knowledge of JavaScript, especially ES6+ syntax, such as destructuring, rest operators, and imports/exports. If you need more information on these topics, reading our How To Code in JavaScript series is recommended.
      • This tutorial will reference aspects of text editors that support TypeScript and show in-line errors. This is not necessary to use TypeScript, but does take more advantage of TypeScript features. To gain the benefit of these, you can use a text editor like Visual Studio Code, which has full support for TypeScript out of the box. You can also try out these benefits in the TypeScript Playground.

      All examples shown in this tutorial were created using TypeScript version 4.2.2.

      Declaring Variable Types in TypeScript

      When writing code in JavaScript, which is a purely dynamic language, you can’t specify the data types of variables. You create the variables and assign them a value, but do not specify a type, as shown in the following:

      const language = {
        name: "JavaScript"
      };
      

      In this code block, language is an object that holds a string value for the property name. The value type for language and its properties is not explicitly set, and this could cause confusion later if future developers do not know what kind of value language references.

      TypeScript has as a main benefit a strict type system. A statically typed language is one where the type of the variables is known at compilation time. In this section, you will try out the syntax used to specify variable types with TypeScript.

      Types are extra information that you write directly in your code. The TypeScript compiler uses this extra information to enforce the correct use of the different values depending on their type.

      Imagine working with a dynamic language, such as JavaScript, and using a string variable as if it were a number. When you do not have strict unit testing, the possible bug is only going to appear during runtime. If using the type system available with TypeScript, the compiler would not compile the code, giving an error instead, like this:

      Output

      The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. (2363)

      To declare a variable with a certain type in TypeScript, use the following syntax:

      declarationKeyword variableName: Type
      

      declarationKeyword would be something like let, var, or const. This would be followed by the variable name, a colon (:), and the type of that variable.

      Any code you write in TypeScript is, in some way, already using the type system, even if you are not specifying any types. Take this code as an example:

      let language="TypeScript";
      

      In TypeScript, this has the same meaning as the following:

      let language: string = 'TypeScript';
      

      In the first example, you did not set the type of the language variable to string, but TypeScript inferred the type because you assigned a string value when it was declared. In the second example, you are explicitly setting the type of the language variable to string.

      If you used const instead of let, it would be the following:

      const language="TypeScript";
      

      In this case, TypeScript would use the string literal TypeScript as the type of your variable, as if you typed it this way:

      const language: 'TypeScript' = 'TypeScript';
      

      TypeScript does this because, when using const, you are not going to assign a new value to the variable after the declaration, as doing this would raise an error.

      Note: If you are using an editor that supports TypeScript, hovering over the variables with your cursor will display the type information of each variable.

      If you explicitly set the type of a variable then use a different type as its value, the TypeScript Compiler (tsc) or your editor will show the error 2322. Try running the following:

      const myNumber: number="look! this is not a number :)";
      

      This will yield the following error:

      Output

      Type 'string' is not assignable to type 'number'. (2322)

      Now that you’ve tried out setting the type of a variable in TypeScript, the next section will show all the basic types supported by TypeScript.

      Basic Types Used in TypeScript

      TypeScript has multiple basic types that are used as building blocks when building more complex types. In the following sections, you are going to examine most of these types. Notice that most variables you are creating throughout this section could have their type omitted because TypeScript would be able to infer them, but you are being explicit about the types for learning purposes.

      string

      The type string is used for textual data types, like string literals or template strings.

      Try out the following code:

      const language: string = 'TypeScript';
      const message: string = `I'm programming in ${language}!`;
      

      In this code block, both language and message are assigned the string type. The template literal is still a string, even though it is determined dynamically.

      Since strings are common in JavaScript programming, this is probably one of the types you are going to use most.

      boolean

      The type boolean is used to represent true or false.

      Try out the code in the following block:

      const hasErrors: boolean = true;
      const isValid: boolean = false;
      

      Since hasErrors and isValid were declared as booleans, they can only be assigned the values true and false. Note that truthy and falsy values are not converted into their boolean equivalents and will throw an error if used with these variables.

      number

      The type number is used to represent integers and floats, as in the following:

      const pi: number = 3.14159;
      const year: number = 2021;
      

      This is another common type that is used often in JavaScript development, so this declaration will be common in TypeScript.

      bigint

      The type bigint is a type that can be used when targetting ES2020. It’s used to represent BigInt, which is a new datatype to store integers bigger than 2^53.

      Try the following code:

      const bigNumber: bigint = 9007199254740993n;
      

      Note: If this code throws an error, it is possible that TypeScript is not set up to target ES2020. This can be changed in your tsconfig.json file.

      If you are working with numbers bigger than 2^53 or with some Math libraries, bigint will be a common type declaration.

      symbol

      The symbol type is used to represent the Symbol primitive value. This will create a unique, unnamed value.

      Run the following code using the Symbol() constructor function:

      const mySymbol: symbol = Symbol('unique-symbol-value');
      

      The uniqueness of these values can be used to avoid reference collisions. For more on symbols in JavaScript, read the symbol article on Mozilla Developer Network (MDN).

      Arrays

      In TypeScript, arrays are typed based on the elements they are expected to have. There are two ways to type an array:

      • Appending [] to the expected type of the array elements. For example, if you want to type an array that holds multiple number values, you could do it like this:
      const primeNumbers: number[] = [2, 3, 5, 7, 11];
      

      If you assigned a string value to this array, TypeScript would give you an error.

      • Using the Array<T> Generic, where T is the expected type of the elements in that array. Using the previous example, it would become this:
      const primeNumbers: Array<number> = [2, 3, 5, 7, 11];
      

      Both ways are identical, so pick one and try using only that format to represent arrays. This will keep the codebase consistent, which is often more important than choosing one style over the other.

      One important aspect of using variables that hold arrays in TypeScript is that most of the time you will have to type them. Try the following code:

      const myArray = [];
      

      TypeScript is not able to infer the correct type expected by this array. Instead, it uses any[], which means an array of anything. This is not type-safe, and could cause confusion later in your code.

      To make your code more robust, it is recommended to be explicit about the types of the array. For example, this would make sure the array has number elements:

      const myArray: number[] = [];
      

      This way, if you try to push an invalid value to the array, TypeScript will yield an error. Try out the following code:

      const myArray: number[] = [];
      
      myArray.push('some-text');
      

      The TypeScript Compiler will show error 2345:

      Output

      Argument of type 'string' is not assignable to parameter of type 'number'. (2345)

      Tuples

      Tuples are arrays with a specific number of elements. One common use-case for this is storing 2D coordinates in the format [x, y]. If you are working with React and using Hooks, the result from most Hooks is also a tuple, like const [isValid, setIsValid] = React.useState(false).

      To type a tuple, as opposed to when typing an array, you wrap the type of the elements inside a [], separating them with commas. Imagine you are creating a literal array with the types of the elements:

      const position: [number, number] = [1, 2];
      

      If you try to pass less, or more, than the number of elements that the tuple expects, the TypeScript Compiler is going to show the error 2322.

      Take the following code, for example:

      const position: [number, number] = [1, 2, 3];
      

      This would yield the following:

      Output

      Type '[number, number, number]' is not assignable to type '[number, number]'. Source has 3 element(s) but target allows only 2. (2322)

      any

      In certain situations it may be too hard to specify the types of a value, such as if that value is coming from a third-party library or from code that was initially written without TypeScript. This can be especially common when migrating a JavaScript codebase to TypeScript in small steps. In these scenarios, it is possible to use a special type called any, which means any type. Using any means opting-out of type checking, and is the same as making the TypeScript Compiler ignore that value.

      Take the following code block:

      let thisCanBeAnything: any = 12345;
      
      thisCanBeAnything = "I can be anything - Look, I'm a string now";
      
      thisCanBeAnything = ["Now I'm an array - This is almost like pure JavaScript!"];
      

      None of these declarations will give an error in TypeScript, since the type was declared as any.

      Note: Most of the time, if you can, you should avoid using any. Using this loses one of the main benefits of TypeScript: having statically typed code.

      unknown

      The unknown type is like a type-safe counterpart of the any type. You can use unknown when you want to type something that you can not determine the value of, but still want to make sure that any code using that value is correctly checking the type before using it. This is useful for library authors with functions in their library that may accept a broad range of values from their users and do not want to type the value explicitly.

      For example, if you have a variable called code:

      let code: unknown;
      

      Then later in the program you can assign different values to that field, like 35 (number), or completely unrelated values, like arrays or even objects.

      Note: You are using let because you are going to assign a new value to that variable.

      Later in the same code, you could set code to a number:

      code = 35;
      

      But then later you could assign it to an array:

      code = [12345];
      

      You could even re-assign it to an object:

      code = {};
      

      If later in the code you want to compare that value against some other number, like:

      const isCodeGreaterThan100 = code > 100;
      

      The TypeScript compiler is going to display the error 2571:

      Output

      Object is of type 'unknown'. (2571)

      This happens because code needs to be a number type for this comparison, not an unknown type. When doing any operation with a value of type unknown, TypeScript needs to make sure that the type is the one it expects. One example of doing this is using the typeof operator that already exists in JavaScript. Examine the following code block:

      if (typeof code === 'number') {
        const isCodeGreaterThan100 = code > 60;
        // ...
      } else {
        throw new Error('Invalid value received as code');
      }
      

      In this example, you are checking if code is a number using the typeof operator. When you do that, TypeScript is going to coerce the type of your variable to number inside that if block, because at runtime the code inside the if block is only going to be executed if code is currently set to a number. Otherwise, you will throw a JavaScript error saying that the value passed is invalid.

      To understand the differences between the unknown and any types, you can think of unknown as “I do not know the type of that value” and any as “I do not care what type this value holds”.

      void

      You can use the void type to define the variable in question as holding no type at all. If you assign the result of a function that returns no value to a variable, that variable is going to have the type void.

      Take the following code:

      function doSomething() {};
      
      const resultOfVoidFunction: void = doSomething();
      

      You will rarely have to use the void type directly in TypeScript.

      null and undefined

      null and undefined values in TypeScript have their own unique types that are called by the same name:

      const someNullField: null = null;
      const someUndefinedField: undefined = undefined;
      

      These are especially useful when creating your own custom types, which will be covered later in this series.

      never

      The never type is the type of a value that will never exist. For example, imagine you create a numeric variable:

      const year: number = 2021;
      

      If you create an if block to run some code if year is not a number, it could be like the following:

      if (typeof year !== "number") {
        year;
      }
      

      The type of the variable year inside that if block is going to be never. This is because, since year is typed as number, the condition for this if block will never be met. You can think of the never type as an impossible type because that variable can’t have a value at this point.

      object

      The object type represents any type that is not a primitive type. This means that it is not one of the following types:

      • number
      • string
      • boolean
      • bigint
      • symbol
      • null
      • undefined

      The object type is commonly used to describe object literals because any object literal can be assigned to it:

      const programmingLanguage: object = {
        name: "TypeScript"
      };
      

      Note: There is a much better type than object that could be used in this case called Record. This has to do with creating custom types and is covered in a later tutorial in this series.

      Conclusion

      In this tutorial, you tried out the different basic types that are available in TypeScript. These types are going to be frequently used when working in a TypeScript codebase and are the main building blocks to create more complex, custom types.

      For more tutorials on TypeScript, check out our TypeScript Topic page.



      Source link

      How to Install Tinc and Set Up a Basic VPN on Ubuntu 18.04


      Introduction

      Tinc is an open-source Virtual Private Network (VPN) daemon with useful features like encryption, optional compression, and automatic mesh routing that can opportunistically route VPN traffic directly between servers. These features differentiate tinc from other VPN solutions, and make it a good choice for creating a VPN out of many small, geographically distributed networks.

      In this tutorial, we will go over how to use tinc to create a secure VPN on which your servers can communicate as if they were on a local network. We will also demonstrate how to use tinc to set up a secure tunnel into a private network. We will be using Ubuntu 18.04 servers, but the configurations can be adapted for use with any other OS.

      Goals

      In order to cover multiple use cases, this tutorial outlines how to connect one client node to the VPN over a private network interface and another over a public one. You can, however, adapt this setup to suit your own needs. You’ll just need to plan out how you want your servers to access each other and adapt the examples presented in this tutorial to your own needs. If you are adapting this to your own setup, be sure to substitute the highlighted values in the examples with your own values. It may be in your interest, though, to first follow the tutorial as it’s written to make sure you understand the components and processes involved before modifying these instructions.

      To help keep things clear, this tutorial will refer to the servers like this:

      • server-01: All of the VPN nodes will connect to this machine, and the connection must be maintained for proper VPN functionality. Additional servers can be configured in the same way as this one to provide redundancy, if desired
      • client-01: Connects to the server-01 VPN node using its private network interface
      • client-02: Connects to the server-01 VPN node over the public network interface

      Note: Tinc itself doesn’t differentiate between servers (machines that host and deliver VPN services) and clients (the machines that connect to and use the secure private network), but it can be helpful to understand and visualize how tinc works by thinking of your servers like this.

      Here is a diagram of the VPN that we want to set up:

      Tinc VPN Setup

      The blue box represents our VPN and the pink represents the underlying private network. All three servers can communicate on the VPN, even though the private network is otherwise inaccessible to client-02.

      Prerequisites

      If you would like to follow this tutorial exactly, provision two Ubuntu 18.04 servers (server-01 and client-01) in the same datacenter and enable private networking on each. Then, create another Ubuntu 18.04 server (client-02) in a separate datacenter. Each server should have an administrative user and a firewall configured with ufw. To set this up, follow our initial server setup guide for Ubuntu 18.04.

      Additionally, later on in this tutorial we’ll need to transfer a few files between each machine using scp. Because of this, you’ll need to generate SSH keys on each of your servers, add both client-01 and client-02’s SSH keys to server-01’s authorized_keys file, and then add server-01’s SSH key to both client-01 and client-02’s authorized_keys files. For help setting this up, see our guide on How to Set Up SSH Keys on Ubuntu 18.04.

      Step 1 — Installing Tinc

      Tinc is available from the default Ubuntu APT repositories, which means we can install it with just a few commands.

      If you’ve not done so recently, run the following command on each server to update their respective package indexes:

      All servers

      Then install tinc on each server by running the following command:

      All servers

      With that, you’ve installed tinc on each of your servers. However, you’ll need to make some changes to tinc’s configuration on each machine in order to get your VPN up and running. Let’s begin with updating server-01.

      Step 2 — Configuring the Tinc Server

      Tinc requires that every machine that will be part of the VPN has the following three configuration components:

      • Tinc configuration files: There are three distinct files that configure the tinc daemon:
        • tinc.conf, which defines the netname, the network device over which the VPN will run, and other VPN options;
        • tinc-up, a script that activates the network device defined in tinc.conf after tinc is started;
        • tinc-down, which deactivates the network device whenever tinc stops.
      • Public/private key pairs: Tinc uses public/private key pairs to ensure that only users with valid keys are able to access the VPN.
      • Host configuration files: Each machine (or host) on the VPN has its own configuration file that holds the host’s actual IP address and the subnet where tinc will serve it

      Tinc uses a netname to distinguish one tinc VPN from another. This is helpful in cases where you want to set up multiple VPNs, but it’s recommended that you use a netname even if you are only planning on configuring one VPN. You can give your VPN whatever netname you like, but for simplicity we will call our VPN netname.

      On server-01, create the configuration directory structure for the VPN:

      server-01

      • sudo mkdir -p /etc/tinc/netname/hosts

      Use your preferred text editor to create a tinc.conf file. Here, we’ll use nano:

      server-01

      • sudo nano /etc/tinc/netname/tinc.conf

      Add the following lines to the empty file. These configure a tinc node named server_01 with a network interface called tun0 which will use IPv4:

      server-01:/etc/tinc/netname/tinc.conf

      Name = server_01
      AddressFamily = ipv4
      Interface = tun0
      

      Warning: Note how the value after the Name directive includes an underscore (_) rather than a hyphen (-). This is important, since tinc requires that the Name value contain only alphanumeric or underscore characters. If you use a hyphen here, you’ll encounter an error when you try to start the VPN later in this guide.

      Save and close the file after adding these lines. If you used nano, do so by pressing CTRL+X, Y, then ENTER.

      Next, create a host configuration file named server_01 in the hosts subdirectory. Ultimately, the client nodes will use this file to communicate with server-01:

      server-01

      • sudo nano /etc/tinc/netname/hosts/server_01

      Again, note that the name of this file contains an underscore rather than a hyphen. This way, it aligns with the Name directive in the tinc.conf file which will allow tinc to automatically append the server’s public RSA key to this file when we generate later on.

      Add the following lines to the file, making sure to include server-01’s public IP address:

      server-01:/etc/tinc/netname/hosts/server_01

      Address = server-01_public_IP_address
      Subnet = 10.0.0.1/32
      

      The Address field specifies how other nodes will connect to this server, and Subnet specifies which subnet this daemon will serve. Save and close the file.

      Next, generate a pair of public and private RSA keys for this host with the following command:

      server-01

      • sudo tincd -n netname -K4096

      After running this command, you’ll be prompted to enter filenames where tinc will save the public and private RSA keys:

      Output

      . . . Please enter a file to save private RSA key to [/etc/tinc/netname/rsa_key.priv]: Please enter a file to save public RSA key to [/etc/tinc/netname/hosts/server_01]:

      Press ENTER to accept the default locations at each prompt; doing so will tell tinc to store the private key in a file named rsa_key.priv and append the public key to the server_01 host configuration file.

      Next, create tinc-up, the script that will run whenever the netname VPN is started:

      server-01

      • sudo nano /etc/tinc/netname/tinc-up

      Add the following lines:

      server-01:/etc/tinc/netname/tinc-up

      #!/bin/sh
      ip link set $INTERFACE up
      ip addr add 10.0.0.1/32 dev $INTERFACE
      ip route add 10.0.0.0/24 dev $INTERFACE
      

      Here’s what each of these lines do:

      • ip link …: sets the status of tinc’s virtual network interface as up
      • ip addr …: adds the IP address 10.0.0.1 with a netmask of 32 to tinc’s virtual network interface, which will cause the other machines on the VPN to see server-01’s IP address as 10.0.0.1
      • ip route …: adds a route (10.0.0.0/24) which can be reached on tinc’s virtual network interface

      Save and close the file after adding these lines.

      Next, create a script to remove the virtual network interface when your VPN is stopped:

      server-01

      • sudo nano /etc/tinc/netname/tinc-down

      Add the following lines:

      server-01:/etc/tinc/netname/tinc-down

      #!/bin/sh
      ip route del 10.0.0.0/24 dev $INTERFACE
      ip addr del 10.0.0.1/32 dev $INTERFACE
      ip link set $INTERFACE down
      

      These lines have the opposite effects as those in the tinc-up script:

      • ip route …: deletes the 10.0.0.0/24 route
      • ip addr …: deletes the IP address 10.0.0.1 from tinc’s virtual network interface
      • ip link …: sets the status of tinc’s virtual network interface as down

      Save and close the file, then make both of these new network scripts executable:

      server-01

      • sudo chmod 755 /etc/tinc/netname/tinc-*

      As a final step of configuring server-01, add a firewall rule that will allow traffic through port 655, tinc’s default port:

      server-01

      server-01 is now fully configured and you can move on to setting up your client nodes.

      Step 3 — Configuring the Client Nodes

      Both of your client machines will require a slightly different configuration than the server, although the process will generally be quite similar.

      Because of the setup we’re aiming for in this guide, we will configure client-01 and client-02 almost identically with only a few slight differences between them. Hence, many of the commands given in this step must be run on both machines. Note, though, that if client-01 or client-02 require a specific command or special configuration, those instructions will be shown in a blue or red command block, respectively.

      On both client-01 and client-02, replicate the directory structure you created on server-01:

      client-01 & client-02

      • sudo mkdir -p /etc/tinc/netname/hosts

      Then create a tinc.conf file:

      client-01 & client-02

      • sudo nano /etc/tinc/netname/tinc.conf

      Add the following lines to the file on both machines:

      client-01 & client-02 /etc/tinc/netname/tinc.conf

      Name = node_name
      AddressFamily = ipv4
      Interface = tun0
      ConnectTo = server_01
      

      Be sure to substitute node_name with the respective client node’s name. Again, make sure this name uses an underscore (_) rather than a hyphen.

      Note that this file contains a ConnectTo directive pointing to server_01, while server-01’s tinc.conf file didn’t include this directive. By not including a ConnectTo statement on server-01, it means that server-01 will only listen for incoming connections. This works for our setup since it won’t connect to any other machines.

      Save and close the file.

      Next, create a host configuration file on each client node. Again, make sure the file name is spelled with an underscore instead of a hyphen:

      client-01 & client-02

      • sudo nano /etc/tinc/netname/hosts/node_name

      For client-01, add this line:

      client-01:/etc/tinc/netname/hosts/client_01

      Subnet = 10.0.0.2/32
      

      For client-02, add this line:

      client-02:/etc/tinc/netname/hosts/client_02

      Subnet = 10.0.0.3/32
      

      Note that each client has a different subnet that tinc will serve. Save and close the file.

      Next, generate the keypairs on each client machine:

      client-01 & client-02

      • sudo tincd -n netname -K4096

      Again as you did with server-01, when prompted to select files to store the RSA keys, press ENTER to accept the default choices.

      Following that, create the network interface start script on each client:

      client-01 & client-02

      • sudo nano /etc/tinc/netname/tinc-up

      For client-01, add these lines:

      client-01:/etc/tinc/netname/tinc-up

      #!/bin/sh
      ip link set $INTERFACE up
      ip addr add 10.0.0.2/32 dev $INTERFACE
      ip route add 10.0.0.0/24 dev $INTERFACE
      

      For client-02, add the following:

      client-02:/etc/tinc/netname/tinc-up

      #!/bin/sh
      ip link set $INTERFACE up
      ip addr add 10.0.0.3/32 dev $INTERFACE
      ip route add 10.0.0.0/24 dev $INTERFACE
      

      Save and close each file.

      Next, create the network interface stop script on each client:

      client-01 & client-02

      • sudo nano /etc/tinc/netname/tinc-down

      On client-01, add the following content to the empty file:

      client-01:/etc/tinc/netname/tinc-down

      #!/bin/sh
      ip route del 10.0.0.0/24 dev $INTERFACE
      ip addr del 10.0.0.2/32 dev $INTERFACE
      ip link set $INTERFACE down
      

      On client-02, add the following::

      client-02:/etc/tinc/netname/tinc-down

      #!/bin/sh
      ip route del 10.0.0.0/24 dev $INTERFACE
      ip addr del 10.0.0.3/32 dev $INTERFACE
      ip link set $INTERFACE down
      

      Save and close the files.

      Make networking scripts executable by running the following command on each client machine:

      client-01 & client-02

      • sudo chmod 755 /etc/tinc/netname/tinc-*

      Lastly, open up port 655 on each client:

      client-01 & client-02

      At this point, the client nodes are almost, although not quite, set up. They still need the public key that we created on server-01 in the previous step in order to authenticate the connection to the VPN.

      Step 4 — Distributing the Keys

      Each node that wants to communicate directly with another node must have exchanged public keys, which are inside of the host configuration files. In our case, server-01 needs to exchange public keys with the other nodes.

      Exchange Keys Between server-01 and client-01

      On client-01, copy its host configuration file to server-01. Because both client-01 and server-01 are in the same data center and both have private networking enabled, you can use server01’s private IP address here:

      client-01

      • scp /etc/tinc/netname/hosts/client_01 sammy@server-01_private_IP:/tmp

      Then on server-01, copy the client-01 host configuration file into the /etc/tinc/netname/hosts/ directory:

      server-01

      • sudo cp /tmp/client_01 /etc/tinc/netname/hosts/

      Then, while still on server-01, copy its host configuration file to client-01:

      server-01

      • scp /etc/tinc/netname/hosts/server_01 user@client-01_private_IP:/tmp

      On client-01, copy server-01’s file to the appropriate location:

      client-01

      • sudo cp /tmp/server_01 /etc/tinc/netname/hosts/

      On client-01, edit server-01’s host configuration file so the Address field is set to server-01’s private IP address. This way, client-01 will connect to the VPN via the private network:

      client-01

      • sudo nano /etc/tinc/netname/hosts/server_01

      Change the Address directive to point to server-01’s private IP address:

      client-01:/etc/tinc/netname/hosts/server_01

      Address = server-01_private_IP
      Subnet = 10.0.0.1/32
      

      Save and quit. Now let’s move on to our remaining node, client-02.

      Exchange Keys Between server-01 and client-02

      On client-02, copy its host configuration file to server-01:

      client-02

      • scp /etc/tinc/netname/hosts/client_02 sammy@server-01_public_IP:/tmp

      Then on server-01, copy the client_02 host configuration file into the appropriate location:

      server-01

      • sudo cp /tmp/client_02 /etc/tinc/netname/hosts/

      Then copy server-01’s host configuration file to client-02:

      server-01

      • scp /etc/tinc/netname/hosts/server_01 user@client-02_public_IP:/tmp

      On client-02, copy server-01’s file to the appropriate location:

      client-02

      • sudo cp /tmp/server_01 /etc/tinc/netname/hosts/

      Assuming you’re only setting up two client nodes, you’re finished distributing public keys. If, however, you’re creating a larger VPN, now is a good time to exchange the keys between those other nodes. Remember that if you want two nodes to directly communicate with each other (without a forwarding server between), they need to have exchanged their keys/hosts configuration files, and they need to be able to access each other’s real network interfaces. Also, it is fine to just copy each host’s configuration file to every node in the VPN.

      Step 5 — Testing the Configuration

      On each node, starting with server-01, start tinc with the following command:

      All servers

      • sudo tincd -n netname -D -d3

      This command includes the -n flag, which points to the netname for our VPN, netname. This is useful if you have more than one VPN set up and you need to specify which one you want to start. It also includes the -D flag, which prevents tinc from forking and detaching, as well as disables tinc’s automatic restart mechanism. Lastly, it includes the -d flag, which tells tinc to run in debug mode, with a debug level of 3.

      Note: When it comes to the tinc daemon, a debug level of 3 will show every request exchanged between any two of the servers, including authentication requests, key exchanges, and connection list updates. Higher debug levels show more information regarding network traffic, but for now we’re only concerned with whether the nodes can communicate with one another, so a level of 3 will suffice. In a production scenario, though, you would want to change to a lower debug level so as not to fill disks with log files.

      You can learn more about tinc’s debug levels by reviewing the official documentation.

      After starting the daemon on each node, you should see output with the names of each node as they connect to server-01. Now let’s test the connection over the VPN.

      In a separate window, on client-02, ping client-01’s VPN IP address. We assigned this to be 10.0.0.2, earlier:

      client-02

      The ping should work correctly, and you should see some debug output in the other windows about the connection on the VPN. This indicates that client-02 is able to communicate over the VPN through server-01 to client-01. Press CTRL+C to quit pinging.

      You may also use the VPN interfaces to do any other network communication, like application connections, copying files, and SSH.

      On each tinc daemon debug window, quit the daemon by pressing CTRL+.

      Step 6 — Configuring Tinc To Start Up on Boot

      Ubuntu servers use systemd as the default system manager to control starting and running processes. Because of this, we can enable the netname VPN to start up automatically at boot with a single systemctl command.

      Run the following command on each node to set the tinc VPN to start up whenever the machines boot:

      All servers

      • sudo systemctl enable tinc@netname

      Tinc is configured to start at boot on each of your machines and you can control it with the systemctl command. If you would like to start it now, run the following command on each of your nodes:

      All servers

      • sudo systemctl start tinc@netname

      Note: If you have multiple VPNs you enable or start each of them at once, like this:

      All servers

      • sudo systemctl start tinc@natename_01 tinc@netname_02 … tinc@netname_n

      With that, your tinc VPN fully configured and running on each of your nodes.

      Conclusion

      Now that you have gone through this tutorial, you should have a good foundation to build out your VPN to meet your needs. Tinc is very flexible, and any node can be configured to connect to any other node (that it can access over the network) so it can act as a mesh VPN without relying on one individual node.



      Source link

      Troubleshooting Basic Connection Issues


      Updated by Linode Written by Linode

      This guide presents troubleshooting strategies for Linodes that are unresponsive to any network access. One reason that a Linode may be unresponsive is if you recently performed a distribution upgrade or other broad software updates to your Linode, as those changes can lead to unexpected problems for your core system components.

      Similarly, your server may be unresponsive after maintenance was applied by Linode to your server’s host (frequently, this is correlated with software/distribution upgrades performed on your deployment prior to the host’s maintenance). This guide is designed as a useful resource for either of these scenarios.

      If you can ping your Linode, but you cannot access SSH or other services, this guide will not assist with troubleshooting those services. Instead, refer to the Troubleshooting SSH or Troubleshooting Web Servers, Databases, and Other Services guides.

      Where to go for help outside this guide

      This guide explains how to use different troubleshooting commands on your Linode. These commands can produce diagnostic information and logs that may expose the root of your connection issues. For some specific examples of diagnostic information, this guide also explains the corresponding cause of the issue and presents solutions for it.

      If the information and logs you gather do not match a solution outlined here, consider searching the Linode Community Site for posts that match your system’s symptoms. Or, post a new question in the Community Site and include your commands’ output.

      Linode is not responsible for the configuration or installation of software on your Linode. Refer to Linode’s Scope of Support for a description of which issues Linode Support can help with.

      Before You Begin

      There are a few core troubleshooting tools you should familiarize yourself with that are used when diagnosing connection problems.

      The Linode Shell (Lish)

      Lish is a shell that provides access to your Linode’s serial console. Lish does not establish a network connection to your Linode, so you can use it when your networking is down or SSH is inaccessible. Much of your troubleshooting for basic connection issues will be performed from the Lish console.

      To learn about Lish in more detail, and for instructions on how to connect to your Linode via Lish, review the Using the Linode Shell (Lish) guide. In particular, using your web browser is a fast and simple way to access Lish.

      MTR

      When your network traffic leaves your computer to your Linode, it travels through a series of routers that are administered by your internet service provider, by Linode’s transit providers, and by the various organizations that form the Internet’s backbone. It is possible to analyze the route that your traffic takes for possible service interruptions using a tool called MTR.

      MTR is similar to the traceroute tool, in that it will trace and display your traffic’s route. MTR also runs several iterations of its tracing algorithm, which means that it can report statistics like average packet loss and latency over the period that the MTR test runs.

      Review the installation instructions in Linode’s Diagnosing Network Issues with MTR guide and install MTR on your computer.

      Is your Linode Running?

      Log in to the Linode Manager and inspect the Linode’s dashboard. If the Linode is powered off, turn it on.

      Inspect the Lish Console

      If the Linode is listed as running in the Manager, or after you boot it from the Manager, open the Lish console and look for a login prompt. If a login prompt exists, try logging in with your root user credentials (or any other Linux user credentials that you previously created on the server).

      Note

      The root user is available in Lish even if root user login is disabled in your SSH configuration.

      1. If you can log in at the Lish console, move on to the diagnose network connection issues section of this guide.

        If you see a log in prompt, but you have forgotten the credentials for your Linode, follow the instructions for resetting your root password and then attempt to log in at the Lish console again.

      2. If you do not see a login prompt, your Linode may have issues with booting.

      Troubleshoot Booting Issues

      If your Linode isn’t booting normally, you will not be able to rely on the Lish console to troubleshoot your deployment directly. To continue, you will first need to reboot your Linode into Rescue Mode, which is a special recovery environment that Linode provides.

      When you boot into Rescue Mode, you are booting your Linode into the Finnix recovery Linux distribution. This Finnix image includes a working network configuration, and you will be able to mount your Linode’s disks from this environment, which means that you will be able to access your files.

      1. Review the Rescue and Rebuild guide for instructions and boot into Rescue Mode. If your Linode does not reboot into Rescue Mode successfully, please contact Linode Support.

      2. Connect to Rescue Mode via the Lish console as you would normally. You will not be required to enter a username or password to start using the Lish console while in Rescue Mode.

      Perform a File System Check

      If your Linode can’t boot, then it may have experienced filesystem corruption.

      1. Review the Rescue and Rebuild guide for instructions on running a filesystem check.

        Caution

        Never run a filesystem check on a disk that is mounted.

      2. If your filesystem check reports errors that cannot be fixed, you may need to rebuild your Linode.

      3. If the filesystem check reports errors that it has fixed, try rebooting your Linode under your normal configuration profile. After you reboot, you may find that your connection issues are resolved. If you still cannot connect as normal, restart the troubleshooting process from the beginning of this guide.

      4. If the filesystem check does not report any errors, there may be another reason for your booting issues. Continue to inspecting your system and kernel logs.

      Inspect System and Kernel Logs

      In addition to being able to mount your Linode’s disks, you can also change root (sometimes abbreviated as chroot) within Rescue Mode. Chrooting will make Rescue Mode’s working environment emulate your normal Linux distribution. This means your files and logs will appear where you normally expect them, and you will be able to work with tools like your standard package manager and other system utilities.

      To proceed, review the Rescue and Rebuild guide’s instructions on changing root. Once you have chrooted, you can then investigate your Linode’s logs for messages that may describe the cause of your booting issues.

      In systemd Linux distributions (like Debian 8+, Ubuntu 16.04+, CentOS 7+, and recent releases of Arch), you can run the journalctl command to view system and kernel logs. In these and other distributions, you may also find system log messages in the following files:

      • /var/log/messages

      • /var/log/syslog

      • /var/log/kern.log

      • /var/log/dmesg

      You can use the less command to review the contents of these files (e.g. less /var/log/syslog). Try pasting your log messages into a search engine or searching in the Linode Community Site to see if anyone else has run into similar issues. If you don’t find any results, you can try asking about your issues in a new post on the Linode Community Site. If it becomes difficult to find a solution, you may need to rebuild your Linode.

      Quick Tip for Ubuntu and Debian Systems

      After you have chrooted inside Rescue Mode, the following command may help with issues related to your package manager’s configuration:

      dpkg --configure -a
      

      After running this command, try rebooting your Linode into your normal configuration profile. If your issues persist, you may need to investigate and research your system logs further, or consider rebuilding your Linode.

      Diagnose Network Connection Issues

      If you can boot your Linode normally and access the Lish console, you can continue investigating network issues. Networking issues may have two causes:

      • There may be a network routing problem between you and your Linode, or:

      • If the traffic is properly routed, your Linode’s network configuration may be malfunctioning.

      Check for Network Route Problems

      To diagnose routing problems, run and analyze an MTR report from your computer to your Linode. For instructions on how to use MTR, review Linode’s MTR guide. It is useful to run your MTR report for 100 cycles in order to get a good sample size (note that running a report with this many cycles will take more time to complete). This recommended command includes other helpful options:

      mtr -rwbzc 100 -i 0.2 -rw 198.51.100.0 <Linode's IP address>
      

      Once you have generated this report, compare it with the following example scenarios.

      Note

      If you are located in China, and the output of your MTR report shows high packet loss or an improperly configured router, then your IP address may have been blacklisted by the GFW (Great Firewall of China). Linode is not able to change your IP address if it has been blacklisted by the GFW. If you have this issue, review this community post for troubleshooting help.
      • High Packet Loss

        root@localhost:~# mtr --report www.google.com
        HOST: localhost                   Loss%   Snt   Last   Avg  Best  Wrst StDev
        1. 63.247.74.43                   0.0%    10    0.3   0.6   0.3   1.2   0.3
        2. 63.247.64.157                  0.0%    10    0.4   1.0   0.4   6.1   1.8
        3. 209.51.130.213                60.0%    10    0.8   2.7   0.8  19.0   5.7
        4. aix.pr1.atl.google.com        60.0%    10    6.7   6.8   6.7   6.9   0.1
        5. 72.14.233.56                  50.0%   10    7.2   8.3   7.1  16.4   2.9
        6. 209.85.254.247                40.0%   10   39.1  39.4  39.1  39.7   0.2
        7. 64.233.174.46                 40.0%   10   39.6  40.4  39.4  46.9   2.3
        8. gw-in-f147.1e100.net          40.0%   10   39.6  40.5  39.5  46.7   2.2
        

        This example report shows high persistent packet loss starting mid-way through the route at hop 3, which indicates an issue with the router at hop 3. If your report looks like this, open a support ticket with your MTR results for further troubleshooting assistance.

        Note

        If your route only shows packet loss at certain routers, and not through to the end of the route, then it is likely that those routers are purposefully limiting ICMP responses. This is generally not a problem for your connection. Linode’s MTR guide provides more context for packet loss issues.

        If your report resembles the example, open a support ticket with your MTR results for further troubleshooting assistance. Also, consult Linode’s MTR guide for more context on packet loss issues.

      • Improperly Configured Router

        root@localhost:~# mtr --report www.google.com
        HOST: localhost                   Loss%   Snt   Last   Avg  Best  Wrst StDev
        1. 63.247.74.43                  0.0%    10    0.3   0.6   0.3   1.2   0.3
        2. 63.247.64.157                 0.0%    10    0.4   1.0   0.4   6.1   1.8
        3. 209.51.130.213                0.0%    10    0.8   2.7   0.8  19.0   5.7
        4. aix.pr1.atl.google.com        0.0%    10    6.7   6.8   6.7   6.9   0.1
        5. ???                           0.0%    10    0.0   0.0   0.0   0.0   0.0
        6. ???                           0.0%    10    0.0   0.0   0.0   0.0   0.0
        7. ???                           0.0%    10    0.0   0.0   0.0   0.0   0.0
        8. ???                           0.0%    10    0.0   0.0   0.0   0.0   0.0
        9. ???                           0.0%    10    0.0   0.0   0.0   0.0   0.0
        10. ???                           0.0%    10    0.0   0.0   0.0   0.0   0.0
        

        If your report shows question marks instead of the hostnames (or IP addresses) of the routers, and if these question marks persist to the end of the route, then the report indicates an improperly configured router. If your report looks like this, open a support ticket with your MTR results for further troubleshooting assistance.

        Note

        If your route only shows question marks for certain routers, and not through to the end of the route, then it is likely that those routers are purposefully blocking ICMP responses. This is generally not a problem for your connection. Linode’s MTR guide provides more information about router configuration issues.
      • Destination Host Networking Improperly Configured

        root@localhost:~# mtr --report www.google.com
        HOST: localhost                   Loss%   Snt   Last   Avg  Best  Wrst StDev
        1. 63.247.74.43                  0.0%    10    0.3   0.6   0.3   1.2   0.3
        2. 63.247.64.157                 0.0%    10    0.4   1.0   0.4   6.1   1.8
        3. 209.51.130.213                0.0%    10    0.8   2.7   0.8  19.0   5.7
        4. aix.pr1.atl.google.com        0.0%    10    6.7   6.8   6.7   6.9   0.1
        5. 72.14.233.56                  0.0%    10    7.2   8.3   7.1  16.4   2.9
        6. 209.85.254.247                0.0%    10   39.1  39.4  39.1  39.7   0.2
        7. 64.233.174.46                 0.0%    10   39.6  40.4  39.4  46.9   2.3
        8. gw-in-f147.1e100.net         100.0    10    0.0   0.0   0.0   0.0   0.0
        

        If your report shows no packet loss or low packet loss (or non-persistent packet loss isolated to certain routers) until the end of the route, and 100% loss at your Linode, then the report indicates that your Linode’s network interface is not configured correctly. If your report looks like this, move down to confirming network configuration issues from Rescue Mode.

      Note

      If your report does not look like any of the previous examples, read through the MTR guide for other potential scenarios.

      Confirm Network Configuration Issues from Rescue Mode

      If your MTR indicates a configuration issue within your Linode, you can confirm the problem by using Rescue Mode:

      1. Reboot your Linode into Rescue Mode.

      2. Run another MTR report from your computer to your Linode’s IP address.

      3. As noted earlier, Rescue Mode boots with a working network configuration. If your new MTR report does not show the same packet loss that it did before, this result confirms that your deployment’s network configuration needs to be fixed. Continue to troubleshooting network configuration issues.

      4. If your new MTR report still shows the same packet loss at your Linode, this result indicates issues outside of your configuration. Open a support ticket with your MTR results for further troubleshooting assistance.

      Open a Support Ticket with your MTR Results

      Before opening a support ticket, you should also generate a reverse MTR report. The MTR tool is run from your Linode and targets your machine’s IP address on your local network, whether you’re on your home LAN, for example, or public WiFi. To run an MTR from your Linode, log in to your Lish console. To find your local IP, visit a website like https://www.whatismyip.com/.

      Once you have generated your original MTR and your reverse MTR, open a Linode support ticket, and include your reports and a description of the troubleshooting you’ve performed so far. Linode Support will try to help further diagnose the routing issue.

      Troubleshoot Network Configuration Issues

      If you have determined that your network configuration is the cause of the problem, review the following troubleshooting suggestions. If you make any changes in an attempt to fix the issue, you can test those changes with these steps:

      1. Run another MTR report (or ping the Linode) from your computer to your Linode’s IP.

      2. If the report shows no packet loss but you still can’t access SSH or other services, this result indicates that your network connection is up again, but the other services are still down. Move onto troubleshooting SSH or troubleshooting other services.

      3. If the report still shows the same packet loss, review the remaining troubleshooting suggestions in this section.

      If the recommendations in this section do not resolve your issue, try pasting your diagnostic commands’ output into a search engine or searching for your output in the Linode Community Site to see if anyone else has run into similar issues. If you don’t find any results, you can try asking about your issues in a new post on the Linode Community Site. If it becomes difficult to find a solution, you may need to rebuild your Linode.

      Try Enabling Network Helper

      A quick fix may be to enable Linode’s Network Helper tool. Network Helper will attempt to generate the appropriate static networking configuration for your Linux distribution. After you enable Network Helper, reboot your Linode for the changes to take effect. If Network Helper was already enabled, continue to the remaining troubleshooting suggestions in this section.

      Did You Upgrade to Ubuntu 18.04+ From an Earlier Version?

      If you performed an inline upgrade from an earlier version of Ubuntu to Ubuntu 18.04+, you may need to enable the systemd-networkd service:

      sudo systemctl enable systemd-networkd
      

      Afterwards, reboot your Linode.

      Run Diagnostic Commands

      To collect more information about your network configuration, collect output from the diagnostic commands appropriate for your distribution:

      Network diagnostic commands

      • Debian 7, Ubuntu 14.04

        sudo service network status
        cat /etc/network/interfaces
        ip a
        ip r
        sudo ifdown eth0 && sudo ifup eth0
        
      • Debian 8 and 9, Ubuntu 16.04

        sudo systemctl status networking.service -l
        sudo journalctl -u networking --no-pager | tail -20
        cat /etc/network/interfaces
        ip a
        ip r
        sudo ifdown eth0 && sudo ifup eth0
        
      • Ubuntu 18.04

        sudo networkctl status
        sudo systemctl status systemd-networkd -l
        sudo journalctl -u systemd-networkd --no-pager | tail -20
        cat /etc/systemd/network/05-eth0.network
        ip a
        ip r
        sudo netplan apply
        
      • Arch, CoreOS

        sudo systemctl status systemd-networkd -l
        sudo journalctl -u systemd-networkd --no-pager | tail -20
        cat /etc/systemd/network/05-eth0.network
        ip a
        ip r
        
      • CentOS 6

        sudo service network status
        cat /etc/sysconfig/network-scripts/ifcfg-eth0
        ip a
        ip r
        sudo ifdown eth0 && sudo ifup eth0
        
      • CentOS 7, Fedora

        sudo systemctl status NetworkManager -l
        sudo journalctl -u NetworkManager --no-pager | tail -20
        sudo nmcli
        cat /etc/sysconfig/network-scripts/ifcfg-eth0
        ip a
        ip r
        sudo ifdown eth0 && sudo ifup eth0
        

      Inspect Error Messages

      Your commands’ output may show error messages, including generic errors like Failed to start Raise network interfaces. There may also be more specific errors that appear. Two common errors that can appear are related to Sendmail and iptables:

      Sendmail

      If you find a message similar to the following, it is likely that a broken Sendmail update is at fault:

        
      /etc/network/if-up.d/sendmail: 44: .: Can't open /usr/share/sendmail/dynamic run-parts: /etc/network/if-up.d/sendmail exited with return code 2
      
      

      The Sendmail issue can usually be resolved by running the following command and restarting your Linode:

      sudo mv /etc/network/if-up.d/sendmail ~
      ifdown -a && ifup -a
      

      Note

      Read more about the Sendmail bug here.

      iptables

      Malformed rules in your iptables ruleset can sometimes cause issues for your network scripts. An error similar to the following can appear in your logs if this is the case:

        
      Apr 06 01:03:17 xlauncher ifup[6359]: run-parts: failed to exec /etc/network/if- Apr 06 01:03:17 xlauncher ifup[6359]: run-parts: /etc/network/if-up.d/iptables e
      
      

      Run the following command and restart your Linode to resolve this issue:

      sudo mv /etc/network/if-up.d/iptables ~
      

      Please note that your firewall will be down at this point, so you will need to re-enable it manually. Review the Control Network Traffic with iptables guide for help with managing iptables.

      Was your Interface Renamed?

      In your commands’ output, you might notice that your eth0 interface is missing and replaced with another name (for example, ensp or ensp0). This behavior can be caused by systemd’s Predictable Network Interface Names feature.

      1. Disable the use of Predictable Network Interface Names with these commands:

        ln -s /dev/null /etc/systemd/network/99-default.link
        ln -s /dev/null /etc/udev/rules.d/80-net-setup-link.rules
        
      2. Reboot your Linode for the changes to take effect.

      Review Firewall Rules

      If your interface is up but your networking is still down, your firewall (which is likely implemented by the iptables software) may be blocking all connections, including basic ping requests. To review your current firewall ruleset, run:

      sudo iptables -L # displays IPv4 rules
      sudo ip6tables -L # displays IPv6 rules
      

      Note

      Your deployment may be running FirewallD or UFW, which are frontend software packages used to more easily manage your iptables rules. Run these commands to find out if you are running either package:

      sudo ufw status
      sudo firewall-cmd --state
      

      Review How to Configure a Firewall with UFW and Introduction to FirewallD on CentOS to learn how to manage and inspect your firewall rules with those packages.

      Firewall rulesets can vary widely. Review our Control Network Traffic with iptables guide to analyze your rules and determine if they are blocking connections.

      Disable Firewall Rules

      In addition to analyzing your firewall ruleset, you can also temporarily disable your firewall to test if it is interfering with your connections. Leaving your firewall disabled increases your security risk, so we recommend re-enabling it afterwards with a modified ruleset that will accept your connections. Review Control Network Traffic with iptables for help with this subject.

      1. Create a temporary backup of your current iptables:

        sudo iptables-save > ~/iptables.txt
        
      2. Set the INPUT, FORWARD and OUTPUT packet policies as ACCEPT:

        sudo iptables -P INPUT ACCEPT
        sudo iptables -P FORWARD ACCEPT
        sudo iptables -P OUTPUT ACCEPT
        
      3. Flush the nat table that is consulted when a packet that creates a new connection is encountered:

        sudo iptables -t nat -F
        
      4. Flush the mangle table that is used for specialized packet alteration:

        sudo iptables -t mangle -F
        
      5. Flush all the chains in the table:

        sudo iptables -F
        
      6. Delete every non-built-in chain in the table:

        sudo iptables -X
        
      7. Repeat these steps with the ip6tables command to flush your IPv6 rules. Be sure to assign a different name to the IPv6 rules file. (e.g. ~/ip6tables.txt).

      Next Steps

      If you are able to restore basic networking, but you still can’t access SSH or other services, refer to the Troubleshooting SSH or Troubleshooting Web Servers, Databases, and Other Services guides.

      If your connection issues were the result of maintenance performed by Linode, review the Reboot Survival Guide for methods to prepare a Linode for any future maintenance.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link