PageSourceSearch

https://docs.astar.network/assets/js/297e885a.a69be1e2.js

js astar.network collected 2026-10-03 19:24:41 UTC 19,227 bytes, 2 lines download raw bytes

1"use strict";(self.webpackChunkastar_docs=self.webpackChunkastar_docs||[]).push([["5439"],{18357(e,n,r){r.r(n),r.d(n,{metadata:()=>t,default:()=>p,frontMatter:()=>o,contentTitle:()=>c,toc:()=>u,assets:()=>d});var t=JSON.parse('{"id":"build/nodes/collator/secure_setup_guide/building_node","title":"4. Building Your Collator","description":"Let\'s get started","source":"@site/docs/build/nodes/collator/secure_setup_guide/building_node.md","sourceDirName":"build/nodes/collator/secure_setup_guide","slug":"/build/nodes/collator/secure_setup_guide/building_node","permalink":"/docs/build/nodes/collator/secure_setup_guide/building_node","draft":false,"unlisted":false,"editUrl":"https://github.com/AstarNetwork/astar-docs/tree/main/docs/build/nodes/collator/secure_setup_guide/building_node.md","tags":[],"version":"current","sidebarPosition":4,"frontMatter":{"sidebar_position":4},"sidebar":"tutorialSidebar","previous":{"title":"3. SSH Tunneling","permalink":"/docs/build/nodes/collator/secure_setup_guide/ssh_tunneling"},"next":{"title":"5. Node Monitoring","permalink":"/docs/build/nodes/collator/secure_setup_guide/node_monitoring"}}'),s=r(74848),a=r(28453),l=r(50773),i=r(57250);let o={sidebar_position:4},c="4. Building Your Collator",d={},u=[{value:"Let's get started",id:"lets-get-started",level:2},{value:"Build the node",id:"build-the-node",level:2},{value:"Build from source",id:"build-from-source",level:3},{value:"Build from binaries",id:"build-from-binaries",level:3},{value:"Run a Docker container",id:"run-a-docker-container",level:3},{value:"Launch Your Collator",id:"launch-your-collator",level:2},{value:"Set systemd service",id:"set-systemd-service",level:2},{value:"Snapshot",id:"snapshot",level:3},{value:"Finalizing",id:"finalizing",level:2}];function h(e){let n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"4-building-your-collator",children:"4. Building Your Collator"})}),"\n","\n",(0,s.jsx)(n.h2,{id:"lets-get-started",children:"Let's get started"}),"\n",(0,s.jsx)(n.p,{children:"Let's start with updating our server. Connect to your server and update:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo apt-get update\nsudo apt-get upgrade\nsudo apt install -y adduser libfontconfig1\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["the last command (related to ",(0,s.jsx)(n.code,{children:"libfontconfig1"}),") is optional and required if you want install Grafana in the later sections of Secure Setup Guide)."]})}),"\n",(0,s.jsx)(n.h2,{id:"build-the-node",children:"Build the node"}),"\n",(0,s.jsx)(n.p,{children:"To build a collator node, you have 3 different options"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"From source"}),": experience with using Linux"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"From binary"}),": easiest way to start and update node with new releases"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Run a Docker container"}),": Docker background requires"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"build-from-source",children:"Build from source"}),"\n",(0,s.jsx)(n.p,{children:"Building a node from source code is the most complicated path, but will also provide the best optimized node version for your server."}),"\n",(0,s.jsxs)(n.p,{children:["Make sure your server is ready to build a collator. The instructions that follow do not go into details which you can find in official ",(0,s.jsx)(n.a,{href:"https://docs.substrate.io/install/linux/",children:"Substrate Docs"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"## Prerequisites (Software required for compilation)\n##\nsudo apt install build-essential\nsudo apt install --assume-yes git clang curl cmake llvm protobuf-compiler\nsudo apt update\n\n## Install Rust\n##\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\nsource $HOME/.cargo/env\nrustup update nightly\nrustup target add wasm32-unknown-unknown --toolchain nightly\n"})}),"\n",(0,s.jsx)(n.p,{children:"Clone the Astar repository:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"git clone https://github.com/AstarNetwork/Astar.git\ncd Astar\n"})}),"\n",(0,s.jsx)(n.p,{children:"Make sure you have the latest commit in place:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"git checkout\ngit pull\n"})}),"\n",(0,s.jsx)(n.p,{children:"Compile the node binary:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:'CARGO_PROFILE_RELEASE_LTO=true RUSTFLAGS="-C codegen-units=1" cargo build --release\n'})}),"\n",(0,s.jsx)(n.h3,{id:"build-from-binaries",children:"Build from binaries"}),"\n",(0,s.jsxs)(n.p,{children:["The easiest way to install an Astar node is to download the binaries. You can find them here: ",(0,s.jsx)(n.a,{href:"https://github.com/AstarNetwork/Astar",children:"Astar releases"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Get the file and extract:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:'wget $(curl -s https://api.github.com/repos/AstarNetwork/Astar/releases/latest | grep "tag_name" | awk \'{print "https://github.com/AstarNetwork/Astar/releases/download/" substr($2, 2, length($2)-3) "/astar-collator-v" substr($2, 3, length($2)-4) "-ubuntu-x86_64.tar.gz"}\')\n'})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"tar -xvf astar-collator*.tar.gz\n"})}),"\n",(0,s.jsx)(n.h3,{id:"run-a-docker-container",children:"Run a Docker container"}),"\n",(0,s.jsxs)(n.p,{children:["You can find here the ",(0,s.jsx)(n.a,{href:"https://hub.docker.com/r/staketechnologies/astar-collator",children:"Astar Docker hub"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Pull the latest Docker version"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"docker pull staketechnologies/astar-collator:latest\n"})}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"launch-your-collator",children:"Launch Your Collator"}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["The following steps are suitable for ",(0,s.jsx)(n.strong,{children:"binary"})," usage (built from source or downloaded).\nIn case you want to run a Docker container, you will have to adapt those."]})}),"\n",(0,s.jsxs)(n.p,{children:["Create a dedicated user for the node and move the ",(0,s.jsx)(n.strong,{children:"node binary"})," (in this example, username is ",(0,s.jsx)(n.code,{children:"astar"}),"):"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo useradd --no-create-home --shell /usr/sbin/nologin astar\nsudo cp ./astar-collator /u
1sr/local/bin\nsudo chmod +x /usr/local/bin/astar-collator\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Create a dedicated directory for the ",(0,s.jsx)(n.strong,{children:"chain storage data"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo mkdir /var/lib/astar\n"})}),"\n",(0,s.jsx)(n.p,{children:"zeafr\nBefore running a collator, you have to create a node identity key."}),"\n",(0,s.jsxs)(l.A,{children:[(0,s.jsx)(i.A,{value:"astar",label:"Astar",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo astar-collator key generate-node-key --chain astar --base-path /var/lib/astar/\n"})})}),(0,s.jsx)(i.A,{value:"shiden",label:"Shiden",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo astar-collator key generate-node-key --chain shiden --base-path /var/lib/astar/\n"})})}),(0,s.jsx)(i.A,{value:"shibuya",label:"Shibuya",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo astar-collator key generate-node-key --chain shibuya --base-path /var/lib/astar/\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["Make ",(0,s.jsx)(n.code,{children:"astar"})," user the owner of the chain directory:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo chown -R astar:astar /var/lib/astar\n"})}),"\n",(0,s.jsx)(n.p,{children:"Now, let's go to our binary directory and start the collator manually:"}),"\n",(0,s.jsxs)(l.A,{children:[(0,s.jsx)(i.A,{value:"astar",label:"Astar",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"cd /usr/local/bin\n\nsudo -u astar ./astar-collator --collator --chain astar --state-pruning 1000 --name {COLLATOR_NAME} --base-path /var/lib/astar --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' -- --sync warp\n"})})}),(0,s.jsx)(i.A,{value:"shiden",label:"Shiden",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"cd /usr/local/bin\n\nsudo -u astar ./astar-collator --collator --chain shiden --state-pruning 1000 --name {COLLATOR_NAME} --base-path /var/lib/astar --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' -- --sync warp\n"})})}),(0,s.jsx)(i.A,{value:"shibuya",label:"Shibuya",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"cd /usr/local/bin\n\nsudo -u astar ./astar-collator --collator --chain shibuya --state-pruning 1000 --name {COLLATOR_NAME} --base-path /var/lib/astar --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' -- --sync warp\n"})})})]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Type in the place of ",(0,s.jsx)(n.strong,{children:"{COLLATOR_NAME}"}),", what you would like to call your node."]})}),"\n",(0,s.jsxs)(n.p,{children:["See your node syncing on ",(0,s.jsx)(n.a,{href:"https://telemetry.polkadot.io/#list/0x9eb76c5184c4ab8679d2d5d819fdf90b9c001403e9e17da2e14b6d8aec4029c6",children:"https://telemetry.polkadot.io/"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Useful commands to be used in screen:\n",(0,s.jsxs)(n.em,{children:[(0,s.jsx)(n.code,{children:"ctrl+a+d"})," (detach actual session)"]}),"\n",(0,s.jsxs)(n.em,{children:[(0,s.jsx)(n.code,{children:"screen ls"})," (this will list all running screens)"]}),"\n",(0,s.jsxs)(n.em,{children:[(0,s.jsx)(n.code,{children:"screen -r"})," (restore a screen session)"]})]}),"\n",(0,s.jsx)(n.p,{children:"Stop the manual node and kill the screen session:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"ctrl+c\nctrl+a+k\n"})}),"\n",(0,s.jsx)(n.h2,{id:"set-systemd-service",children:"Set systemd service"}),"\n",(0,s.jsxs)(n.p,{children:["To run a stable collator node, a ",(0,s.jsx)(n.strong,{children:"systemd service"})," has to be set and activated. This will ensure that the node is restarting even after a server reboot."]}),"\n",(0,s.jsx)(n.p,{children:"Create a service file"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo nano /etc/systemd/system/astar.service\n"})}),"\n",(0,s.jsx)(n.p,{children:"Add service parameters (this example is for Astar Network):"}),"\n",(0,s.jsxs)(l.A,{children:[(0,s.jsx)(i.A,{value:"astar",label:"Astar",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[Unit]\nDescription=Astar Collator\n\n[Service]\nUser=astar\nGroup=astar\n  \nExecStart=/usr/local/bin/astar-collator \\\n  --state-pruning archive \\\n  --collator \\\n  --name {COLLATOR_NAME} \\\n  --chain astar \\\n  --base-path /var/lib/astar \\\n  --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' \\\n  -- \\\n  --sync warp\n\nRestart=always\nRestartSec=120\n\n[Install]\nWantedBy=multi-user.target\n"})})}),(0,s.jsx)(i.A,{value:"shiden",label:"Shiden",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[Unit]\nDescription=Astar Collator\n\n[Service]\nUser=astar\nGroup=astar\n  \nExecStart=/usr/local/bin/astar-collator \\\n  --pruning archive \\\n  --collator \\\n  --name {COLLATOR_NAME} \\\n  --chain shiden \\\n  --base-path /var/lib/astar \\\n  --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' \\\n  -- \\\n  --sync warp\n\nRestart=always\nRestartSec=120\n\n[Install]\nWantedBy=multi-user.target\n"})})}),(0,s.jsx)(i.A,{value:"shibuya",label:"Shibuya",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[Unit]\nDescription=Astar Collator\n\n[Service]\nUser=astar\nGroup=astar\n  \nExecStart=/usr/local/bin/astar-collator \\\n  --pruning archive \\\n  --collator \\\n  --name {COLLATOR_NAME} \\\n  --chain shibuya \\\n  --base-path /var/lib/astar \\\n  --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' \\\n  -- \\\n  --sync warp\n\nRestart=always\nRestartSec=120\n\n[Install]\nWantedBy=multi-user.target\n"})})})]}),"\n",(0,s.jsx)(n.p,{children:"Start the service:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo systemctl start astar.service\n"})}),"\n",(0,s.jsx)(n.p,{children:"Check the node log and that everything is syncing fine:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"journalctl -f -u astar.service -n100\n"})}),"\n",(0,s.jsx)(n.p,{children:"Enable the service:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"sudo systemctl enable astar.service\n"})}),"\n",(0,s.jsx)(n.h3,{id:"snapshot",children:"Snapshot"}),"\n",(0,s.jsxs)(n.p,{children:["Please refer to the ",(0,s.jsx)(n.a,{href:"/docs/build/nodes/snapshots",children:(0,s.jsx)(n.strong,{children:"snapshot page"})}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"finalizing",children:"Finalizing"}),"\n",(0,s.jsx)(n.p,{children:"To finalize your collator you need to:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Setup an account"}),"\n",(0,s.jsx)(n.li,{children:"Author your session key"}),"\n",(0,s.jsx)(n.li,{children:"Set up your session key"}),"\n",(0,s.jsx)(n.li,{children:"Verify your identity"}),"\n",(0,s.jsx)(n.li,{children:"Bond tokens"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["this part is covered in chapter ",(0,s.jsx)(n.a,{href:"/docs/build/nodes/collator/spinup_collator",children:"Spin up a Collator"})]})]})}function p(e={}){let{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},57250(e,n,r){r.d(n,{A:()=>i});var t=r(74848);r(96540);
1var s=r(34164),a=r(57663);function l({children:e,className:n,hidden:r}){return(0,t.jsx)("div",{role:"tabpanel",className:(0,s.A)("tabItem_Ymn6",n),hidden:r,children:e})}function i({children:e,className:n,value:r}){let{selectedValue:s,lazy:o}=(0,a.uc)(),c=r===s;return!c&&o?null:(0,t.jsx)(l,{className:n,hidden:!c,children:e})}},50773(e,n,r){r.d(n,{A:()=>h});var t=r(74848);r(96540);var s=r(34164),a=r(88287),l=r(57663),i=r(28584),o=r(19863);function c({className:e}){let{selectedValue:n,selectValue:r,tabValues:a,block:o}=(0,l.uc)(),d=[],{blockElementScrollPositionUntilNextRender:u}=(0,i.a_)(),h=e=>{let t=e.currentTarget,s=a[d.indexOf(t)].value;s!==n&&(u(t),r(s))},p=e=>{let n=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{let r=d.indexOf(e.currentTarget)+1;n=d[r]??d[0];break}case"ArrowLeft":{let r=d.indexOf(e.currentTarget)-1;n=d[r]??d[d.length-1]}}n?.focus()};return(0,t.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.A)("tabs",{"tabs--block":o},e),children:a.map(({value:e,label:r,attributes:a})=>(0,t.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{d.push(e)},onKeyDown:p,onClick:h,...a,className:(0,s.A)("tabs__item","tabItem_LNqP",a?.className,{"tabs__item--active":n===e}),children:r??e},e))})}function d({children:e}){return(0,t.jsx)("div",{className:"margin-top--md",children:e})}function u({className:e,children:n}){return(0,t.jsxs)("div",{className:(0,s.A)(a.G.tabs.container,"tabs-container","tabList__CuJ"),children:[(0,t.jsx)(c,{className:e}),(0,t.jsx)(d,{children:n})]})}function h(e){let n=(0,o.A)(),r=(0,l.OC)(e);return(0,t.jsx)(l.O_,{value:r,children:(0,t.jsx)(u,{className:e.className,children:(0,l.vT)(e.children)})},String(n))}},57663(e,n,r){r.d(n,{OC:()=>h,O_:()=>b,uc:()=>x,vT:()=>d});var t=r(74848),s=r(96540),a=r(56347),l=r(99989),i=r(96629),o=r(80618),c=r(41367);function d(e){return s.Children.toArray(e).filter(e=>"\n"!==e)}function u({value:e,tabValues:n}){return n.some(n=>n.value===e)}function h(e){let n,{defaultValue:r,queryString:t=!1,groupId:d}=e,h=function(e){let{values:n,children:r}=e;return(0,s.useMemo)(()=>{let e=n??s.Children.toArray(r).flatMap(e=>{if(!e)return[];if((0,s.isValidElement)(e)&&function(e){let{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return[e];let n="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${n}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.
2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:n,attributes:r,default:t}})=>({value:e,label:n,attributes:r,default:t})),t=(0,o.XI)(e,(e,n)=>e.value===n.value);if(t.length>0)throw Error(`Docusaurus error: Duplicate values "${t.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[n,r])}(e),[p,x]=(0,s.useState)(()=>(function({defaultValue:e,tabValues:n}){if(0===n.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!u({value:e,tabValues:n}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${n.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let r=n.find(e=>e.default)??n[0];if(!r)throw Error("Unexpected error: 0 tabValues");return r.value})({defaultValue:r,tabValues:h})),[b,j]=function({queryString:e=!1,groupId:n}){let r=(0,a.W6)(),t=function({queryString:e=!1,groupId:n}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!n)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:e,groupId:n});return[(0,i.aZ)(t),(0,s.useCallback)(e=>{if(!t)return;let n=new URLSearchParams(r.location.search);n.set(t,e),r.replace({...r.location,search:n.toString()})},[t,r])]}({queryString:t,groupId:d}),[m,f]=function({groupId:e}){let n=e?`docusaurus.tab.${e}`:null,[r,t]=(0,c.Dv)(n);return[r,(0,s.useCallback)(e=>{n&&t.set(e)},[n,t])]}({groupId:d}),v=u({value:n=b??m,tabValues:h})?n:null;return(0,l.A)(()=>{v&&x(v)},[v]),{selectedValue:p,selectValue:(0,s.useCallback)(e=>{if(!u({value:e,tabValues:h}))throw Error(`Can't select invalid tab value=${e}`);x(e),j(e),f(e)},[j,f,h]),tabValues:h,lazy:e.lazy??!1,block:e.block??!1}}let p=(0,s.createContext)(null);function x(){let e=s.useContext(p);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function b(e){return(0,t.jsx)(p.Provider,{value:e.value,children:e.children})}},28453(e,n,r){r.d(n,{R:()=>l,x:()=>i});var t=r(96540);let s={},a=t.createContext(s);function l(e){let n=t.useContext(a);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.