[{"data":1,"prerenderedAt":46},["ShallowReactive",2],{"doc:\u002Fdatabases\u002Fupdating":3},{"page":4,"toc":40},{"path":5,"title":6,"description":7,"blocks":8},"\u002Fdatabases\u002Fupdating","Automated zero-downtime updates","Atomically replace MMDB files on live production servers without dropping a single lookup.",[9,12,16],{"type":10,"text":11},"p","To update a live `.mmdb` file safely, download to a temporary file on the **same filesystem**, verify the SHA-256 checksum and file header, and atomically replace the live path with `mv -f` (`rename(2)`).",{"type":13,"tone":14,"text":15},"callout","warning","Never write directly to the live `.mmdb` path while a process has it memory-mapped (`mmap`). Overwriting an active `mmap` region in place can corrupt reads or trigger `SIGBUS`. Atomic `mv` on the same mount keeps existing file descriptors valid until your reader reopens the path.",{"type":17,"steps":18},"steps",[19,30],{"title":20,"blocks":21},"Create the atomic update script (`\u002Fusr\u002Flocal\u002Fbin\u002Fipscope-update`)",[22],{"type":23,"samples":24},"code",[25],{"label":26,"lang":27,"code":28,"html":29},"\u002Fusr\u002Flocal\u002Fbin\u002Fipscope-update","bash","#!\u002Fusr\u002Fbin\u002Fenv bash\nset -euo pipefail\n\nEDITION=\"ipscope-complete\"\nDEST=\"\u002Fvar\u002Flib\u002Fipscope\u002F${EDITION}.mmdb\"\nETAG=\"\u002Fvar\u002Flib\u002Fipscope\u002F${EDITION}.etag\"\nTMP=\"$(mktemp \u002Fvar\u002Flib\u002Fipscope\u002F.${EDITION}.XXXXXX)\"\nSUM=\"${TMP}.sha256\"\ntrap 'rm -f \"$TMP\" \"$SUM\"' EXIT\n\nSTATUS=$(curl -sSL -w \"%{http_code}\" \"https:\u002F\u002Fdownload.ipscope.io\u002Fv1\u002Fdatabases\u002F${EDITION}\u002Flatest.mmdb\" \\\n  -H \"Authorization: Bearer ${IPSCOPE_KEY}\" \\\n  --etag-compare \"$ETAG\" --etag-save \"$ETAG\" \\\n  -o \"$TMP\")\n\nif [ \"$STATUS\" = \"304\" ]; then\n  exit 0\nfi\n\ncurl -fsSL \"https:\u002F\u002Fdownload.ipscope.io\u002Fv1\u002Fdatabases\u002F${EDITION}\u002Flatest.mmdb.sha256\" \\\n  -H \"Authorization: Bearer ${IPSCOPE_KEY}\" -o \"$SUM\"\n\nawk -v f=\"$TMP\" '{print $1 \"  \" f}' \"$SUM\" | sha256sum -c --status -\nchmod 0644 \"$TMP\"\nmv -f \"$TMP\" \"$DEST\"","\u003Cpre class=\"shiki ipscope\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">#!\u002Fusr\u002Fbin\u002Fenv bash\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">set\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -euo\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> pipefail\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">EDITION\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"ipscope-complete\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">DEST\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"\u002Fvar\u002Flib\u002Fipscope\u002F${EDITION}.mmdb\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">ETAG\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"\u002Fvar\u002Flib\u002Fipscope\u002F${EDITION}.etag\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">TMP\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"$(\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">mktemp\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> \u002Fvar\u002Flib\u002Fipscope\u002F.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">${EDITION}\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\">.XXXXXX\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">)\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">SUM\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"${TMP}.sha256\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">trap\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> 'rm -f \"$TMP\" \"$SUM\"'\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> EXIT\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">STATUS\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">$(\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">curl\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -sSL\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -w\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"%{http_code}\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"https:\u002F\u002Fdownload.ipscope.io\u002Fv1\u002Fdatabases\u002F${EDITION}\u002Flatest.mmdb\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-string)\">  -H\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"Authorization: Bearer ${IPSCOPE_KEY}\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-string)\">  --etag-compare\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$ETAG\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> --etag-save\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$ETAG\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-string)\">  -o\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$TMP\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">if\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> [ \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"$STATUS\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"304\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> ]; \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">then\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">  exit\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">fi\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">curl\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -fsSL\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"https:\u002F\u002Fdownload.ipscope.io\u002Fv1\u002Fdatabases\u002F${EDITION}\u002Flatest.mmdb.sha256\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-string)\">  -H\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"Authorization: Bearer ${IPSCOPE_KEY}\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -o\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$SUM\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">awk\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -v\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> f=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"$TMP\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> '{print $1 \"  \" f}'\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$SUM\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> |\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> sha256sum\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -c\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> --status\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">chmod\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0644\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$TMP\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">mv\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> -f\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$TMP\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$DEST\"\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",{"title":31,"blocks":32},"Schedule with a systemd timer (`RandomizedDelaySec`)",[33],{"type":23,"samples":34},[35],{"label":36,"lang":37,"code":38,"html":39},"\u002Fetc\u002Fsystemd\u002Fsystem\u002Fipscope-update.timer","text","[Unit]\nDescription=Update IPScope MMDB database\n\n[Timer]\nOnCalendar=*-*-* 04:00:00 UTC\nRandomizedDelaySec=30m\nPersistent=true\n\n[Install]\nWantedBy=timers.target","\u003Cpre class=\"shiki\">\u003Ccode>[Unit]\nDescription=Update IPScope MMDB database\n\n[Timer]\nOnCalendar=*-*-* 04:00:00 UTC\nRandomizedDelaySec=30m\nPersistent=true\n\n[Install]\nWantedBy=timers.target\u003C\u002Fcode>\u003C\u002Fpre>",[41,44],{"id":42,"text":20,"level":43},"step-create-the-atomic-update-script-usr-local-bin-ipscope-update",3,{"id":45,"text":31,"level":43},"step-schedule-with-a-systemd-timer-randomizeddelaysec",1793226505853]