[{"data":1,"prerenderedAt":701},["ShallowReactive",2],{"docs-nav":3,"docs:\u002Fdocs\u002Fhow-to\u002Fdeploy-production":139},[4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136],{"path":5,"title":6},"\u002Fdocs\u002Faccess-gating","Protect a local route",{"path":8,"title":9},"\u002Fdocs\u002Farchitecture\u002Fsecurity-and-trust","Security and trust",{"path":11,"title":12},"\u002Fdocs\u002Fconcepts\u002Fbuilds-and-deployments","Build and deploy",{"path":14,"title":15},"\u002Fdocs\u002Fconcepts\u002Fconfiguration-ownership","Where configuration belongs",{"path":17,"title":18},"\u002Fdocs\u002Fconcepts\u002Fenvironments-and-secrets","Environment values and secrets",{"path":20,"title":21},"\u002Fdocs\u002Fconcepts\u002Fmental-model","How projects fit together",{"path":23,"title":24},"\u002Fdocs\u002Fconcepts\u002Fplans-and-apply","Plans and apply",{"path":26,"title":27},"\u002Fdocs\u002Fconcepts\u002Ftargets-and-runtimes","Choose a target and runtime",{"path":29,"title":30},"\u002Fdocs\u002Fcontribute\u002Freleases","Publish a release",{"path":32,"title":33},"\u002Fdocs\u002Fdevelopment-mounts","Development mounts",{"path":35,"title":36},"\u002Fdocs\u002Fgetting-started","Getting started",{"path":38,"title":39},"\u002Fdocs\u002Fhelp\u002Ffaq","FAQ",{"path":41,"title":42},"\u002Fdocs\u002Fhelp\u002Ftroubleshooting","Troubleshooting",{"path":44,"title":45},"\u002Fdocs\u002Fhow-to\u002Fdeploy-production","Prepare a deployment environment",{"path":47,"title":48},"\u002Fdocs\u002Fhow-to\u002Fswarm-cluster","Run on a multi-node Swarm",{"path":50,"title":51},"\u002Fdocs","mm documentation",{"path":53,"title":54},"\u002Fdocs\u002Fjobs-and-schedules","Jobs and schedules",{"path":56,"title":57},"\u002Fdocs\u002Flocal-dashboard","Local dashboard",{"path":59,"title":60},"\u002Fdocs\u002Flocal-https","Local HTTPS",{"path":62,"title":63},"\u002Fdocs\u002Flocal-services","Local services",{"path":65,"title":66},"\u002Fdocs\u002Fmcp","Let an AI agent work on your project",{"path":68,"title":69},"\u002Fdocs\u002Fmulti-project-hosts","Run multiple projects on one host",{"path":71,"title":72},"\u002Fdocs\u002Fonboarding","Set up a project",{"path":74,"title":75},"\u002Fdocs\u002Fopenbao","Use OpenBao",{"path":77,"title":78},"\u002Fdocs\u002Fproject\u002Fcontributing","Contributing",{"path":80,"title":81},"\u002Fdocs\u002Fproject\u002Flicense","License",{"path":83,"title":84},"\u002Fdocs\u002Fproject\u002Fsecurity","Security",{"path":86,"title":87},"\u002Fdocs\u002Freference\u002Fcapability-matrix","Supported features and platforms",{"path":89,"title":90},"\u002Fdocs\u002Freference\u002Fcli","CLI command reference",{"path":92,"title":93},"\u002Fdocs\u002Freference\u002Fconfiguration","Configuration",{"path":95,"title":96},"\u002Fdocs\u002Freference\u002Fenvironment-variables","Environment variables",{"path":98,"title":99},"\u002Fdocs\u002Freference\u002Ferrors-and-exit-codes","Errors and exit codes",{"path":101,"title":102},"\u002Fdocs\u002Freference\u002Fknown-issues","Known limitations",{"path":104,"title":105},"\u002Fdocs\u002Fremote-access","Manage remote access",{"path":107,"title":108},"\u002Fdocs\u002Fremote-daemon","Set up a remote host",{"path":110,"title":111},"\u002Fdocs\u002Fruntime-observability","Status, logs, and commands",{"path":113,"title":114},"\u002Fdocs\u002Fsecret-delivery","Pass secrets to your app",{"path":116,"title":117},"\u002Fdocs\u002Fsecret-providers","Choose a secret store",{"path":119,"title":120},"\u002Fdocs\u002Fstart\u002Finstall","Install mm",{"path":122,"title":123},"\u002Fdocs\u002Fterminal-ui","Terminal UI",{"path":125,"title":126},"\u002Fdocs\u002Ftutorials\u002Fdotnet-web-api",".NET web API example",{"path":128,"title":129},"\u002Fdocs\u002Ftutorials\u002Ffirst-local-app","First local app",{"path":131,"title":132},"\u002Fdocs\u002Ftutorials\u002Flaravel-rust","Laravel and Rust example",{"path":134,"title":135},"\u002Fdocs\u002Ftutorials\u002Fnode-fullstack","Node full stack example",{"path":137,"title":138},"\u002Fdocs\u002Fvault","Use HashiCorp Vault",{"id":140,"title":45,"body":141,"description":695,"extension":696,"meta":697,"navigation":203,"path":44,"seo":698,"stem":699,"__hash__":700},"docs\u002Fdocs\u002Fhow-to\u002Fdeploy-production.md",{"type":142,"value":143,"toc":692},"minimark",[144,148,151,289,319,492,500,511,516,519,636,659,674,688],[145,146,147],"p",{},"Use this workflow to set up a production-like environment. Try it on a test\nhost first.",[145,149,150],{},"Keep the same project configuration and Compose files. Add the environment's\ndomains, target, and build variant:",[152,153,158],"pre",{"className":154,"code":155,"language":156,"meta":157,"style":157},"language-yaml shiki shiki-themes mm","environment-delivery:\n  default: direct\n  development-default: env-file\n\nenvironments:\n  local:\n    build-variant: development\n  production:\n    target: production\n    environment-delivery: direct\n    build-variant: production\n    domains:\n      api: api.example.com\n","yaml","",[159,160,161,174,187,198,205,213,221,232,240,251,261,270,278],"code",{"__ignoreMap":157},[162,163,166,170],"span",{"class":164,"line":165},"line",1,[162,167,169],{"class":168},"sWZmh","environment-delivery",[162,171,173],{"class":172},"sIbZ0",":\n",[162,175,177,180,183],{"class":164,"line":176},2,[162,178,179],{"class":168},"  default",[162,181,182],{"class":172},":",[162,184,186],{"class":185},"sv8ni"," direct\n",[162,188,190,193,195],{"class":164,"line":189},3,[162,191,192],{"class":168},"  development-default",[162,194,182],{"class":172},[162,196,197],{"class":185}," env-file\n",[162,199,201],{"class":164,"line":200},4,[162,202,204],{"emptyLinePlaceholder":203},true,"\n",[162,206,208,211],{"class":164,"line":207},5,[162,209,210],{"class":168},"environments",[162,212,173],{"class":172},[162,214,216,219],{"class":164,"line":215},6,[162,217,218],{"class":168},"  local",[162,220,173],{"class":172},[162,222,224,227,229],{"class":164,"line":223},7,[162,225,226],{"class":168},"    build-variant",[162,228,182],{"class":172},[162,230,231],{"class":185}," development\n",[162,233,235,238],{"class":164,"line":234},8,[162,236,237],{"class":168},"  production",[162,239,173],{"class":172},[162,241,243,246,248],{"class":164,"line":242},9,[162,244,245],{"class":168},"    target",[162,247,182],{"class":172},[162,249,250],{"class":185}," production\n",[162,252,254,257,259],{"class":164,"line":253},10,[162,255,256],{"class":168},"    environment-delivery",[162,258,182],{"class":172},[162,260,186],{"class":185},[162,262,264,266,268],{"class":164,"line":263},11,[162,265,226],{"class":168},[162,267,182],{"class":172},[162,269,250],{"class":185},[162,271,273,276],{"class":164,"line":272},12,[162,274,275],{"class":168},"    domains",[162,277,173],{"class":172},[162,279,281,284,286],{"class":164,"line":280},13,[162,282,283],{"class":168},"      api",[162,285,182],{"class":172},[162,287,288],{"class":185}," api.example.com\n",[145,290,291,292,295,296,299,300,303,304,307,308,313,314,318],{},"Provision the target and restricted operator identity before deploying.\n",[159,293,294],{},"mm target setup"," installs the runtime, and with ",[159,297,298],{},"--origin"," and\n",[159,301,302],{},"--break-glass"," it also installs ",[159,305,306],{},"mmd"," and the restricted SSH account. See\n",[309,310,312],"a",{"href":311},"..\u002Fremote-daemon","Remote daemon operations"," and ",[309,315,317],{"href":316},"..\u002Fremote-access","Remote access and\nRBAC","; do not copy private target credentials into project\nconfiguration.",[152,320,324],{"className":321,"code":322,"language":323,"meta":157,"style":157},"language-sh shiki shiki-themes mm","mm --target production target setup plan\nmm --target production target setup apply --plan TARGET_PLAN_HASH --yes\nmm --environment production env review\nmm --environment production build --publish plan\nmm --environment production build --publish apply --plan BUILD_PLAN_HASH --yes\nmm --environment production build receipt build-receipt.json\nmm --environment production deploy plan --receipt build-receipt.json\nmm --environment production deploy apply --plan DEPLOY_PLAN_HASH --yes\nmm --environment production service status\n","sh",[159,325,326,348,372,387,403,424,440,459,478],{"__ignoreMap":157},[162,327,328,332,336,339,342,345],{"class":164,"line":165},[162,329,331],{"class":330},"svrjQ","mm",[162,333,335],{"class":334},"sbRf1"," --target",[162,337,338],{"class":185}," production",[162,340,341],{"class":185}," target",[162,343,344],{"class":185}," setup",[162,346,347],{"class":185}," plan\n",[162,349,350,352,354,356,358,360,363,366,369],{"class":164,"line":176},[162,351,331],{"class":330},[162,353,335],{"class":334},[162,355,338],{"class":185},[162,357,341],{"class":185},[162,359,344],{"class":185},[162,361,362],{"class":185}," apply",[162,364,365],{"class":334}," --plan",[162,367,368],{"class":185}," TARGET_PLAN_HASH",[162,370,371],{"class":334}," --yes\n",[162,373,374,376,379,381,384],{"class":164,"line":189},[162,375,331],{"class":330},[162,377,378],{"class":334}," --environment",[162,380,338],{"class":185},[162,382,383],{"class":185}," env",[162,385,386],{"class":185}," review\n",[162,388,389,391,393,395,398,401],{"class":164,"line":200},[162,390,331],{"class":330},[162,392,378],{"class":334},[162,394,338],{"class":185},[162,396,397],{"class":185}," build",[162,399,400],{"class":334}," --publish",[162,402,347],{"class":185},[162,404,405,407,409,411,413,415,417,419,422],{"class":164,"line":207},[162,406,331],{"class":330},[162,408,378],{"class":334},[162,410,338],{"class":185},[162,412,397],{"class":185},[162,414,400],{"class":334},[162,416,362],{"class":185},[162,418,365],{"class":334},[162,420,421],{"class":185}," BUILD_PLAN_HASH",[162,423,371],{"class":334},[162,425,426,428,430,432,434,437],{"class":164,"line":215},[162,427,331],{"class":330},[162,429,378],{"class":334},[162,431,338],{"class":185},[162,433,397],{"class":185},[162,435,436],{"class":185}," receipt",[162,438,439],{"class":185}," build-receipt.json\n",[162,441,442,444,446,448,451,454,457],{"class":164,"line":223},[162,443,331],{"class":330},[162,445,378],{"class":334},[162,447,338],{"class":185},[162,449,450],{"class":185}," deploy",[162,452,453],{"class":185}," plan",[162,455,456],{"class":334}," --receipt",[162,458,439],{"class":185},[162,460,461,463,465,467,469,471,473,476],{"class":164,"line":234},[162,462,331],{"class":330},[162,464,378],{"class":334},[162,466,338],{"class":185},[162,468,450],{"class":185},[162,470,362],{"class":185},[162,472,365],{"class":334},[162,474,475],{"class":185}," DEPLOY_PLAN_HASH",[162,477,371],{"class":334},[162,479,480,482,484,486,489],{"class":164,"line":242},[162,481,331],{"class":330},[162,483,378],{"class":334},[162,485,338],{"class":185},[162,487,488],{"class":185}," service",[162,490,491],{"class":185}," status\n",[145,493,494,495,499],{},"Replace each hash with the one printed by its plan command. The remote host\nnever builds: it deploys the digests in the build receipt, which must be a\nbuild of the commit you deploy. A receipt CI built for another environment\nworks too when production builds the same units; see ",[309,496,498],{"href":497},"..\u002Fconcepts\u002Fbuilds-and-deployments#promote-a-build-to-another-environment","promote a build to\nanother\nenvironment",".\nBefore applying, check the target, images,\nsecrets, routes, and backups. If the configuration\nor target changes after review, create a new plan.",[145,501,502,503,506,507,510],{},"Use ",[159,504,505],{},"mm service logs"," to diagnose the remote services. Remote exec needs an\nexplicit permission grant and has no stdin, TTY, or interactive shell support.\nDo not assume remote jobs or schedules are available merely because local\nCompose supports them. See ",[309,508,509],{"href":316},"remote access",".",[512,513,515],"h2",{"id":514},"pull-from-a-private-registry","Pull from a private registry",[145,517,518],{},"When the images are private, declare the registry and a secret holding a pull\ntoken. Set the secret in each environment that deploys; the same name holds a\ndifferent token per environment:",[152,520,522],{"className":154,"code":521,"language":156,"meta":157,"style":157},"secrets:\n  ghcr.read-token:\n    storage: {provider: age, location: local\u002Fghcr-read-token}\n    input: {prompt: \"GHCR token (classic PAT, read:packages)\"}\n\nregistries:\n  ghcr.io:\n    username: example-bot\n    password: {secret: ghcr.read-token}\n",[159,523,524,531,538,570,589,593,600,607,617],{"__ignoreMap":157},[162,525,526,529],{"class":164,"line":165},[162,527,528],{"class":168},"secrets",[162,530,173],{"class":172},[162,532,533,536],{"class":164,"line":176},[162,534,535],{"class":168},"  ghcr.read-token",[162,537,173],{"class":172},[162,539,540,543,545,548,551,553,556,559,562,564,567],{"class":164,"line":189},[162,541,542],{"class":168},"    storage",[162,544,182],{"class":172},[162,546,547],{"class":172}," {",[162,549,550],{"class":168},"provider",[162,552,182],{"class":172},[162,554,555],{"class":185}," age",[162,557,558],{"class":172},",",[162,560,561],{"class":168}," location",[162,563,182],{"class":172},[162,565,566],{"class":185}," local\u002Fghcr-read-token",[162,568,569],{"class":172},"}\n",[162,571,572,575,577,579,582,584,587],{"class":164,"line":200},[162,573,574],{"class":168},"    input",[162,576,182],{"class":172},[162,578,547],{"class":172},[162,580,581],{"class":168},"prompt",[162,583,182],{"class":172},[162,585,586],{"class":185}," \"GHCR token (classic PAT, read:packages)\"",[162,588,569],{"class":172},[162,590,591],{"class":164,"line":207},[162,592,204],{"emptyLinePlaceholder":203},[162,594,595,598],{"class":164,"line":215},[162,596,597],{"class":168},"registries",[162,599,173],{"class":172},[162,601,602,605],{"class":164,"line":223},[162,603,604],{"class":168},"  ghcr.io",[162,606,173],{"class":172},[162,608,609,612,614],{"class":164,"line":234},[162,610,611],{"class":168},"    username",[162,613,182],{"class":172},[162,615,616],{"class":185}," example-bot\n",[162,618,619,622,624,626,629,631,634],{"class":164,"line":242},[162,620,621],{"class":168},"    password",[162,623,182],{"class":172},[162,625,547],{"class":172},[162,627,628],{"class":168},"secret",[162,630,182],{"class":172},[162,632,633],{"class":185}," ghcr.read-token",[162,635,569],{"class":172},[152,637,639],{"className":321,"code":638,"language":323,"meta":157,"style":157},"mm -e production secret set ghcr.read-token\n",[159,640,641],{"__ignoreMap":157},[162,642,643,645,648,650,653,656],{"class":164,"line":165},[162,644,331],{"class":330},[162,646,647],{"class":334}," -e",[162,649,338],{"class":185},[162,651,652],{"class":185}," secret",[162,654,655],{"class":185}," set",[162,657,658],{"class":185}," ghcr.read-token\n",[145,660,661,662,665,666,669,670,673],{},"Each deploy reads the token from the deploying host's store and gives it to\nDocker, Compose, or Podman in a private configuration that is removed when the\ncommand ends; nothing is written to ",[159,663,664],{},"~\u002F.docker",". A Swarm stack is deployed with\n",[159,667,668],{},"--with-registry-auth",", so every node that runs a task can pull. On a cluster\ntarget, ",[159,671,672],{},"mm target setup apply"," pushes the token to every node with the\nenvironment's other secrets.",[145,675,676,677,679,680,683,684,687],{},"When the token is missing, ",[159,678,331],{}," says where to create one. For GHCR that is a\nclassic personal access token with only the ",[159,681,682],{},"read:packages"," scope, because the\nGitHub container registry accepts no other kind:\n",[159,685,686],{},"https:\u002F\u002Fgithub.com\u002Fsettings\u002Ftokens\u002Fnew?scopes=read:packages",". Choose \"No\nexpiration\", or the longest your organization allows, and authorize the token\nfor single sign-on if the organization requires it. Prefer a machine account,\nso the token does not depend on one person's access.",[689,690,691],"style",{},"html pre.shiki code .sWZmh, html code.shiki .sWZmh{--shiki-default:var(--mm-code-key)}html pre.shiki code .sIbZ0, html code.shiki .sIbZ0{--shiki-default:var(--mm-code-punctuation)}html pre.shiki code .sv8ni, html code.shiki .sv8ni{--shiki-default:var(--mm-code-string)}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 pre.shiki code .svrjQ, html code.shiki .svrjQ{--shiki-default:var(--mm-code-function)}html pre.shiki code .sbRf1, html code.shiki .sbRf1{--shiki-default:var(--mm-code-option)}",{"title":157,"searchDepth":176,"depth":176,"links":693},[694],{"id":514,"depth":176,"text":515},"Configure domains, images, and a remote target for a production-like environment.","md",{},{"title":45,"description":695},"docs\u002Fhow-to\u002Fdeploy-production","aw143bhpFlzpU-0DzikU_ackpZyB-aSvmY4aRUPqGw4",1794512546197]