[{"data":1,"prerenderedAt":867},["ShallowReactive",2],{"navigation_docs":3,"-docs-guides-docker-deployment":86,"-docs-guides-docker-deployment-surround":862},[4,22,31,48,65],{"title":5,"path":6,"stem":7,"children":8,"page":21},"Api","\u002Fdocs\u002Fapi","docs\u002Fapi",[9,13,17],{"title":10,"path":11,"stem":12},"CLI Reference","\u002Fdocs\u002Fapi\u002Fcli-reference","docs\u002Fapi\u002F1.cli-reference",{"title":14,"path":15,"stem":16},"ZMQ Protocol Reference","\u002Fdocs\u002Fapi\u002Fzmq-protocol","docs\u002Fapi\u002F2.zmq-protocol",{"title":18,"path":19,"stem":20},"Error Codes","\u002Fdocs\u002Fapi\u002Ferror-codes","docs\u002Fapi\u002F3.error-codes",false,{"title":23,"path":24,"stem":25,"children":26,"page":21},"Community","\u002Fdocs\u002Fcommunity","docs\u002Fcommunity",[27],{"title":28,"path":29,"stem":30},"Contributing","\u002Fdocs\u002Fcommunity\u002Fcontributing","docs\u002Fcommunity\u002F1.contributing",{"title":32,"path":33,"stem":34,"children":35,"page":21},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002Fconcepts",[36,40,44],{"title":37,"path":38,"stem":39},"Architecture","\u002Fdocs\u002Fconcepts\u002Farchitecture","docs\u002Fconcepts\u002F1.architecture",{"title":41,"path":42,"stem":43},"Certificate Lifecycle","\u002Fdocs\u002Fconcepts\u002Fcertificate-lifecycle","docs\u002Fconcepts\u002F2.certificate-lifecycle",{"title":45,"path":46,"stem":47},"Security Model","\u002Fdocs\u002Fconcepts\u002Fsecurity-model","docs\u002Fconcepts\u002F3.security-model",{"title":49,"path":50,"stem":51,"children":52,"page":21},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002Fgetting-started",[53,57,61],{"title":54,"path":55,"stem":56},"Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002Fgetting-started\u002F1.introduction",{"title":58,"path":59,"stem":60},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002Fgetting-started\u002F2.installation",{"title":62,"path":63,"stem":64},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002Fgetting-started\u002F3.quick-start",{"title":66,"path":67,"stem":68,"children":69,"page":21},"Guides","\u002Fdocs\u002Fguides","docs\u002Fguides",[70,74,78,82],{"title":71,"path":72,"stem":73},"Configuration","\u002Fdocs\u002Fguides\u002Fconfiguration","docs\u002Fguides\u002F1.configuration",{"title":75,"path":76,"stem":77},"Certificate Profiles","\u002Fdocs\u002Fguides\u002Fcertificate-profiles","docs\u002Fguides\u002F2.certificate-profiles",{"title":79,"path":80,"stem":81},"Docker Deployment","\u002Fdocs\u002Fguides\u002Fdocker-deployment","docs\u002Fguides\u002F3.docker-deployment",{"title":83,"path":84,"stem":85},"Importing an Existing CA","\u002Fdocs\u002Fguides\u002Fimporting-existing-ca","docs\u002Fguides\u002F4.importing-existing-ca",{"id":87,"title":79,"body":88,"description":856,"extension":857,"links":858,"meta":859,"navigation":473,"path":80,"seo":860,"stem":81,"__hash__":861},"docs\u002Fdocs\u002Fguides\u002F3.docker-deployment.md",{"type":89,"value":90,"toc":849},"minimark",[91,95,100,224,232,236,657,663,678,682,685,766,770,777,785,789,792,809,812,845],[92,93,79],"h1",{"id":94},"docker-deployment",[96,97,99],"h2",{"id":98},"single-container","Single container",[101,102,107],"pre",{"className":103,"code":104,"language":105,"meta":106,"style":106},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","docker run -d \\\n  --name upki-ca \\\n  -p 5000:5000 \\\n  -p 5001:5001 \\\n  -e UPKI_DATA_DIR=\u002Fdata \\\n  -e UPKI_CA_SEED=\"${PKI_SEED}\" \\\n  -e UPKI_CA_HOST=0.0.0.0 \\\n  -v upki-ca-data:\u002Fdata \\\n  ghcr.io\u002Fcircle-rd\u002Fupki-ca:latest\n","bash","",[108,109,110,130,141,152,162,173,193,207,218],"code",{"__ignoreMap":106},[111,112,115,119,123,126],"span",{"class":113,"line":114},"line",1,[111,116,118],{"class":117},"sBMFI","docker",[111,120,122],{"class":121},"sfazB"," run",[111,124,125],{"class":121}," -d",[111,127,129],{"class":128},"sTEyZ"," \\\n",[111,131,133,136,139],{"class":113,"line":132},2,[111,134,135],{"class":121},"  --name",[111,137,138],{"class":121}," upki-ca",[111,140,129],{"class":128},[111,142,144,147,150],{"class":113,"line":143},3,[111,145,146],{"class":121},"  -p",[111,148,149],{"class":121}," 5000:5000",[111,151,129],{"class":128},[111,153,155,157,160],{"class":113,"line":154},4,[111,156,146],{"class":121},[111,158,159],{"class":121}," 5001:5001",[111,161,129],{"class":128},[111,163,165,168,171],{"class":113,"line":164},5,[111,166,167],{"class":121},"  -e",[111,169,170],{"class":121}," UPKI_DATA_DIR=\u002Fdata",[111,172,129],{"class":128},[111,174,176,178,181,185,188,191],{"class":113,"line":175},6,[111,177,167],{"class":121},[111,179,180],{"class":121}," UPKI_CA_SEED=",[111,182,184],{"class":183},"sMK4o","\"${",[111,186,187],{"class":128},"PKI_SEED",[111,189,190],{"class":183},"}\"",[111,192,129],{"class":128},[111,194,196,198,201,205],{"class":113,"line":195},7,[111,197,167],{"class":121},[111,199,200],{"class":121}," UPKI_CA_HOST=",[111,202,204],{"class":203},"sbssI","0.0.0.0",[111,206,129],{"class":128},[111,208,210,213,216],{"class":113,"line":209},8,[111,211,212],{"class":121},"  -v",[111,214,215],{"class":121}," upki-ca-data:\u002Fdata",[111,217,129],{"class":128},[111,219,221],{"class":113,"line":220},9,[111,222,223],{"class":121},"  ghcr.io\u002Fcircle-rd\u002Fupki-ca:latest\n",[225,226,227,228,231],"p",{},"On the very first start, the container runs ",[108,229,230],{},"init"," automatically (creating the CA key and certificate), then starts both ZMQ listeners.",[96,233,235],{"id":234},"docker-compose-with-upki-ra","Docker Compose with uPKI RA",[101,237,241],{"className":238,"code":239,"language":240,"meta":106,"style":106},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# docker-compose.yml\nservices:\n  upki-ca:\n    image: ghcr.io\u002Fcircle-rd\u002Fupki-ca:latest\n    restart: unless-stopped\n    environment:\n      UPKI_DATA_DIR: \u002Fdata\n      UPKI_CA_SEED: ${PKI_SEED}\n      UPKI_CA_HOST: 0.0.0.0\n    volumes:\n      - upki-ca-data:\u002Fdata\n    ports:\n      - \"5000:5000\"\n      - \"5001:5001\"\n    healthcheck:\n      test:\n        - \"CMD-SHELL\"\n        - >\n          python -c \"import socket; s=socket.socket(); s.settimeout(2);\n          s.connect(('127.0.0.1', 5000)); s.close()\"\n      interval: 10s\n      timeout: 5s\n      retries: 10\n      start_period: 15s\n\n  upki-ra:\n    image: ghcr.io\u002Fcircle-rd\u002Fupki-ra:latest\n    restart: unless-stopped\n    depends_on:\n      upki-ca:\n        condition: service_healthy\n    environment:\n      UPKI_DATA_DIR: \u002Fdata\n      UPKI_CA_HOST: upki-ca\n      UPKI_CA_SEED: ${PKI_SEED}\n      UPKI_RA_TLS: \"true\"\n      UPKI_RA_SANS: \"upki-ra\"\n    volumes:\n      - upki-ra-data:\u002Fdata\n    ports:\n      - \"8000:8000\"\n\nvolumes:\n  upki-ca-data:\n  upki-ra-data:\n","yaml",[108,242,243,249,258,265,276,286,293,303,313,323,331,340,348,362,374,382,390,403,412,418,424,435,446,457,468,475,483,493,502,510,518,529,536,545,555,564,579,594,601,609,616,628,633,641,649],{"__ignoreMap":106},[111,244,245],{"class":113,"line":114},[111,246,248],{"class":247},"sHwdD","# docker-compose.yml\n",[111,250,251,255],{"class":113,"line":132},[111,252,254],{"class":253},"swJcz","services",[111,256,257],{"class":183},":\n",[111,259,260,263],{"class":113,"line":143},[111,261,262],{"class":253},"  upki-ca",[111,264,257],{"class":183},[111,266,267,270,273],{"class":113,"line":154},[111,268,269],{"class":253},"    image",[111,271,272],{"class":183},":",[111,274,275],{"class":121}," ghcr.io\u002Fcircle-rd\u002Fupki-ca:latest\n",[111,277,278,281,283],{"class":113,"line":164},[111,279,280],{"class":253},"    restart",[111,282,272],{"class":183},[111,284,285],{"class":121}," unless-stopped\n",[111,287,288,291],{"class":113,"line":175},[111,289,290],{"class":253},"    environment",[111,292,257],{"class":183},[111,294,295,298,300],{"class":113,"line":195},[111,296,297],{"class":253},"      UPKI_DATA_DIR",[111,299,272],{"class":183},[111,301,302],{"class":121}," \u002Fdata\n",[111,304,305,308,310],{"class":113,"line":209},[111,306,307],{"class":253},"      UPKI_CA_SEED",[111,309,272],{"class":183},[111,311,312],{"class":121}," ${PKI_SEED}\n",[111,314,315,318,320],{"class":113,"line":220},[111,316,317],{"class":253},"      UPKI_CA_HOST",[111,319,272],{"class":183},[111,321,322],{"class":203}," 0.0.0.0\n",[111,324,326,329],{"class":113,"line":325},10,[111,327,328],{"class":253},"    volumes",[111,330,257],{"class":183},[111,332,334,337],{"class":113,"line":333},11,[111,335,336],{"class":183},"      -",[111,338,339],{"class":121}," upki-ca-data:\u002Fdata\n",[111,341,343,346],{"class":113,"line":342},12,[111,344,345],{"class":253},"    ports",[111,347,257],{"class":183},[111,349,351,353,356,359],{"class":113,"line":350},13,[111,352,336],{"class":183},[111,354,355],{"class":183}," \"",[111,357,358],{"class":121},"5000:5000",[111,360,361],{"class":183},"\"\n",[111,363,365,367,369,372],{"class":113,"line":364},14,[111,366,336],{"class":183},[111,368,355],{"class":183},[111,370,371],{"class":121},"5001:5001",[111,373,361],{"class":183},[111,375,377,380],{"class":113,"line":376},15,[111,378,379],{"class":253},"    healthcheck",[111,381,257],{"class":183},[111,383,385,388],{"class":113,"line":384},16,[111,386,387],{"class":253},"      test",[111,389,257],{"class":183},[111,391,393,396,398,401],{"class":113,"line":392},17,[111,394,395],{"class":183},"        -",[111,397,355],{"class":183},[111,399,400],{"class":121},"CMD-SHELL",[111,402,361],{"class":183},[111,404,406,408],{"class":113,"line":405},18,[111,407,395],{"class":183},[111,409,411],{"class":410},"s7zQu"," >\n",[111,413,415],{"class":113,"line":414},19,[111,416,417],{"class":121},"          python -c \"import socket; s=socket.socket(); s.settimeout(2);\n",[111,419,421],{"class":113,"line":420},20,[111,422,423],{"class":121},"          s.connect(('127.0.0.1', 5000)); s.close()\"\n",[111,425,427,430,432],{"class":113,"line":426},21,[111,428,429],{"class":253},"      interval",[111,431,272],{"class":183},[111,433,434],{"class":121}," 10s\n",[111,436,438,441,443],{"class":113,"line":437},22,[111,439,440],{"class":253},"      timeout",[111,442,272],{"class":183},[111,444,445],{"class":121}," 5s\n",[111,447,449,452,454],{"class":113,"line":448},23,[111,450,451],{"class":253},"      retries",[111,453,272],{"class":183},[111,455,456],{"class":203}," 10\n",[111,458,460,463,465],{"class":113,"line":459},24,[111,461,462],{"class":253},"      start_period",[111,464,272],{"class":183},[111,466,467],{"class":121}," 15s\n",[111,469,471],{"class":113,"line":470},25,[111,472,474],{"emptyLinePlaceholder":473},true,"\n",[111,476,478,481],{"class":113,"line":477},26,[111,479,480],{"class":253},"  upki-ra",[111,482,257],{"class":183},[111,484,486,488,490],{"class":113,"line":485},27,[111,487,269],{"class":253},[111,489,272],{"class":183},[111,491,492],{"class":121}," ghcr.io\u002Fcircle-rd\u002Fupki-ra:latest\n",[111,494,496,498,500],{"class":113,"line":495},28,[111,497,280],{"class":253},[111,499,272],{"class":183},[111,501,285],{"class":121},[111,503,505,508],{"class":113,"line":504},29,[111,506,507],{"class":253},"    depends_on",[111,509,257],{"class":183},[111,511,513,516],{"class":113,"line":512},30,[111,514,515],{"class":253},"      upki-ca",[111,517,257],{"class":183},[111,519,521,524,526],{"class":113,"line":520},31,[111,522,523],{"class":253},"        condition",[111,525,272],{"class":183},[111,527,528],{"class":121}," service_healthy\n",[111,530,532,534],{"class":113,"line":531},32,[111,533,290],{"class":253},[111,535,257],{"class":183},[111,537,539,541,543],{"class":113,"line":538},33,[111,540,297],{"class":253},[111,542,272],{"class":183},[111,544,302],{"class":121},[111,546,548,550,552],{"class":113,"line":547},34,[111,549,317],{"class":253},[111,551,272],{"class":183},[111,553,554],{"class":121}," upki-ca\n",[111,556,558,560,562],{"class":113,"line":557},35,[111,559,307],{"class":253},[111,561,272],{"class":183},[111,563,312],{"class":121},[111,565,567,570,572,574,577],{"class":113,"line":566},36,[111,568,569],{"class":253},"      UPKI_RA_TLS",[111,571,272],{"class":183},[111,573,355],{"class":183},[111,575,576],{"class":121},"true",[111,578,361],{"class":183},[111,580,582,585,587,589,592],{"class":113,"line":581},37,[111,583,584],{"class":253},"      UPKI_RA_SANS",[111,586,272],{"class":183},[111,588,355],{"class":183},[111,590,591],{"class":121},"upki-ra",[111,593,361],{"class":183},[111,595,597,599],{"class":113,"line":596},38,[111,598,328],{"class":253},[111,600,257],{"class":183},[111,602,604,606],{"class":113,"line":603},39,[111,605,336],{"class":183},[111,607,608],{"class":121}," upki-ra-data:\u002Fdata\n",[111,610,612,614],{"class":113,"line":611},40,[111,613,345],{"class":253},[111,615,257],{"class":183},[111,617,619,621,623,626],{"class":113,"line":618},41,[111,620,336],{"class":183},[111,622,355],{"class":183},[111,624,625],{"class":121},"8000:8000",[111,627,361],{"class":183},[111,629,631],{"class":113,"line":630},42,[111,632,474],{"emptyLinePlaceholder":473},[111,634,636,639],{"class":113,"line":635},43,[111,637,638],{"class":253},"volumes",[111,640,257],{"class":183},[111,642,644,647],{"class":113,"line":643},44,[111,645,646],{"class":253},"  upki-ca-data",[111,648,257],{"class":183},[111,650,652,655],{"class":113,"line":651},45,[111,653,654],{"class":253},"  upki-ra-data",[111,656,257],{"class":183},[225,658,659,662],{},[108,660,661],{},".env"," file:",[101,664,666],{"className":103,"code":665,"language":105,"meta":106,"style":106},"PKI_SEED=your-strong-random-seed-here\n",[108,667,668],{"__ignoreMap":106},[111,669,670,672,675],{"class":113,"line":114},[111,671,187],{"class":128},[111,673,674],{"class":183},"=",[111,676,677],{"class":121},"your-strong-random-seed-here\n",[96,679,681],{"id":680},"healthcheck","Healthcheck",[225,683,684],{},"The default CA healthcheck uses a TCP socket probe on port 5000 — it does not require the CA to be in a particular operational state, just to be listening.",[101,686,688],{"className":238,"code":687,"language":240,"meta":106,"style":106},"healthcheck:\n  test:\n    - \"CMD-SHELL\"\n    - >\n      python -c \"import socket; s=socket.socket(); s.settimeout(2);\n      s.connect(('127.0.0.1', 5000)); s.close()\"\n  interval: 10s\n  timeout: 5s\n  retries: 10\n  start_period: 15s\n",[108,689,690,696,703,714,720,725,730,739,748,757],{"__ignoreMap":106},[111,691,692,694],{"class":113,"line":114},[111,693,680],{"class":253},[111,695,257],{"class":183},[111,697,698,701],{"class":113,"line":132},[111,699,700],{"class":253},"  test",[111,702,257],{"class":183},[111,704,705,708,710,712],{"class":113,"line":143},[111,706,707],{"class":183},"    -",[111,709,355],{"class":183},[111,711,400],{"class":121},[111,713,361],{"class":183},[111,715,716,718],{"class":113,"line":154},[111,717,707],{"class":183},[111,719,411],{"class":410},[111,721,722],{"class":113,"line":164},[111,723,724],{"class":121},"      python -c \"import socket; s=socket.socket(); s.settimeout(2);\n",[111,726,727],{"class":113,"line":175},[111,728,729],{"class":121},"      s.connect(('127.0.0.1', 5000)); s.close()\"\n",[111,731,732,735,737],{"class":113,"line":195},[111,733,734],{"class":253},"  interval",[111,736,272],{"class":183},[111,738,434],{"class":121},[111,740,741,744,746],{"class":113,"line":209},[111,742,743],{"class":253},"  timeout",[111,745,272],{"class":183},[111,747,445],{"class":121},[111,749,750,753,755],{"class":113,"line":220},[111,751,752],{"class":253},"  retries",[111,754,272],{"class":183},[111,756,456],{"class":203},[111,758,759,762,764],{"class":113,"line":325},[111,760,761],{"class":253},"  start_period",[111,763,272],{"class":183},[111,765,467],{"class":121},[96,767,769],{"id":768},"persisting-data","Persisting data",[225,771,772,773,776],{},"Always mount ",[108,774,775],{},"UPKI_DATA_DIR"," as a named volume or host bind mount. The CA root key, all node certificates, and the TinyDB files live there.",[778,779,781,782,784],"callout",{"type":780},"danger","If ",[108,783,775],{}," is not persisted, the CA will regenerate a new root key on every container restart, invalidating all previously issued certificates.",[96,786,788],{"id":787},"exposing-zmq-ports","Exposing ZMQ ports",[225,790,791],{},"In production:",[793,794,795,803],"ul",{},[796,797,798,802],"li",{},[799,800,801],"strong",{},"Port 5000"," — expose only to RA nodes and admin tools. Do not expose to the internet.",[796,804,805,808],{},[799,806,807],{},"Port 5001"," — expose only during initial RA registration, then restrict with a firewall rule.",[225,810,811],{},"Use Docker network isolation or a firewall to enforce this:",[101,813,815],{"className":238,"code":814,"language":240,"meta":106,"style":106},"networks:\n  pki-internal:\n    internal: true # no external internet routing\n",[108,816,817,824,831],{"__ignoreMap":106},[111,818,819,822],{"class":113,"line":114},[111,820,821],{"class":253},"networks",[111,823,257],{"class":183},[111,825,826,829],{"class":113,"line":132},[111,827,828],{"class":253},"  pki-internal",[111,830,257],{"class":183},[111,832,833,836,838,842],{"class":113,"line":143},[111,834,835],{"class":253},"    internal",[111,837,272],{"class":183},[111,839,841],{"class":840},"sfNiH"," true",[111,843,844],{"class":247}," # no external internet routing\n",[846,847,848],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":106,"searchDepth":132,"depth":132,"links":850},[851,852,853,854,855],{"id":98,"depth":132,"text":99},{"id":234,"depth":132,"text":235},{"id":680,"depth":132,"text":681},{"id":768,"depth":132,"text":769},{"id":787,"depth":132,"text":788},"Run uPKI CA in Docker or Docker Compose with production-ready settings.","md",null,{},{"title":79,"description":856},"8RJ38mj_ZhJMH92aYjdo9IiTpYSOUKhzAi_28yDo-kA",[863,865],{"title":75,"path":76,"stem":77,"description":864,"children":-1},"Built-in profiles and how to create custom ones.",{"title":83,"path":84,"stem":85,"description":866,"children":-1},"How to bootstrap uPKI CA from an existing key\u002Fcertificate pair.",1775569478524]