[{"data":1,"prerenderedAt":1167},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002F7-docker-mistakes-i-keep-seeing-on-production-servers":48,"\u002Fblog\u002F7-docker-mistakes-i-keep-seeing-on-production-servers-surround":1154,"$f7Td39Vonkf02bgvz57NR3EcUtcG7bggq1tBSUZMiX14":1165},[4,23],{"title":5,"path":6,"stem":7,"children":8,"icon":22},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F2.installation","i-lucide-download",{"title":18,"path":19,"stem":20,"icon":21},"Usage","\u002Fdocs\u002Fgetting-started\u002Fusage","1.docs\u002F1.getting-started\u002F3.usage","i-lucide-sliders",false,{"title":24,"path":25,"stem":26,"children":27,"page":22},"Essentials","\u002Fdocs\u002Fessentials","1.docs\u002F2.essentials",[28,33,38,43],{"title":29,"path":30,"stem":31,"icon":32},"Markdown Syntax","\u002Fdocs\u002Fessentials\u002Fmarkdown-syntax","1.docs\u002F2.essentials\u002F1.markdown-syntax","i-lucide-heading-1",{"title":34,"path":35,"stem":36,"icon":37},"Code Blocks","\u002Fdocs\u002Fessentials\u002Fcode-blocks","1.docs\u002F2.essentials\u002F2.code-blocks","i-lucide-code-xml",{"title":39,"path":40,"stem":41,"icon":42},"Prose Components","\u002Fdocs\u002Fessentials\u002Fprose-components","1.docs\u002F2.essentials\u002F3.prose-components","i-lucide-component",{"title":44,"path":45,"stem":46,"icon":47},"Images and Embeds","\u002Fdocs\u002Fessentials\u002Fimages-embeds","1.docs\u002F2.essentials\u002F4.images-embeds","i-lucide-image",{"id":49,"title":50,"authors":51,"badge":57,"body":59,"date":1140,"description":1141,"extension":1142,"image":1143,"meta":1145,"navigation":1146,"path":1147,"seo":1148,"stem":1152,"__hash__":1153},"posts\u002F3.blog\u002F4.7-docker-mistakes-i-keep-seeing-on-production-servers.md","7 Docker Mistakes I Keep Seeing on Production Servers",[52],{"name":53,"to":54,"avatar":55},"Adi Sulaksono","https:\u002F\u002Fwww.github.com\u002Fadislksn\u002F",{"src":56},"\u002Fimg\u002Fprofile.png",{"label":58},"Docker, DevOps, VPS",{"type":60,"value":61,"toc":1124},"minimark",[62,75,82,89,100,105,108,115,119,125,128,168,171,176,207,216,220,227,230,234,240,331,338,345,349,356,359,363,366,414,417,444,455,459,462,465,482,493,497,522,543,547,562,565,594,598,601,678,685,689,696,702,706,831,838,846,853,856,873,877,908,912,1025,1029,1071,1075,1081,1084,1087,1105,1108,1120],[63,64,65,66,70,71],"p",{},"Docker on a VPS feels like free infrastructure. One ",[67,68,69],"code",{},"docker compose up -d"," and your app is live. No Kubernetes. No platform team. Just you, a $12 server, and a README that says ",[72,73,74],"em",{},"\"it works on my machine.\"",[63,76,77,78,81],{},"Then production teaches the lesson. Disk hits 100%. SSH becomes unresponsive. ",[67,79,80],{},"docker ps"," shows forty containers and half of them are from projects you forgot existed. The OOM killer takes out MySQL because a Node process leaked memory for three weeks. You discover backups were never configured — only hoped for.",[63,83,84,88],{},[85,86,87],"strong",{},"Docker production mistakes"," do not always look dramatic. They look like small defaults left unchanged until the VPS crashes at 2 a.m. These are the seven I see most often on real servers — and what to do instead.",[63,90,91],{},[92,93],"img",{"alt":94,"className":95,"height":97,"src":98,"width":99},"Server room with blinking lights and rack infrastructure",[96],"rounded-lg",400,"https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1558494949-ef010cbdcc31?w=1200&h=400&fit=crop",1200,[101,102,104],"h2",{"id":103},"why-vps-docker-is-a-different-beast","Why VPS + Docker Is a Different Beast",[63,106,107],{},"A VPS is not a managed platform. There is no autoscaler, no built-in log drain, no volume snapshot button you cannot forget to click. You own the full stack: kernel, disk, networking, TLS, and every container you ever started and never removed.",[63,109,110,111,114],{},"That is why ",[85,112,113],{},"Docker DevOps"," on a single server punishes shortcuts harder than local development ever will. The mistakes below compound quietly — until they do not.",[101,116,118],{"id":117},"_1-container-sprawl","1. Container Sprawl",[63,120,121,124],{},[85,122,123],{},"Container sprawl"," is what happens when every experiment, client project, and \"quick staging\" environment lives on the same VPS forever.",[63,126,127],{},"Typical symptoms:",[129,130,131,150,153,165],"ul",{},[132,133,134,135,138,139,142,143,146,147],"li",{},"Twelve ",[67,136,137],{},"docker-compose.yml"," files across ",[67,140,141],{},"\u002Fopt",", ",[67,144,145],{},"\u002Fhome\u002Fdeploy",", and ",[67,148,149],{},"\u002Fvar\u002Fwww",[132,151,152],{},"Stopped containers from 2024 still holding port bindings and volume mounts",[132,154,155,156,142,159,142,162],{},"Duplicate databases — ",[67,157,158],{},"postgres",[67,160,161],{},"postgres-staging",[67,163,164],{},"postgres-old",[132,166,167],{},"Nobody knows which stack serves which domain",[63,169,170],{},"Sprawl wastes RAM and disk, creates port conflicts, and makes incident response slow. During an outage, you are not debugging one app — you are archaeology.",[63,172,173],{},[85,174,175],{},"Fix it:",[129,177,178,187,194,200],{},[132,179,180,181,142,184],{},"One directory per environment: ",[67,182,183],{},"\u002Fsrv\u002Fappname\u002Fproduction",[67,185,186],{},"\u002Fsrv\u002Fappname\u002Fstaging",[132,188,189,190,193],{},"Run ",[67,191,192],{},"docker system prune"," on a schedule — but only after confirming nothing important is stopped",[132,195,196,197],{},"Use explicit project names: ",[67,198,199],{},"docker compose -p myapp-prod up -d",[132,201,202,203,206],{},"Document what runs where. A simple ",[67,204,205],{},"SERVICES.md"," on the server beats tribal knowledge",[208,209,210],"callout",{},[63,211,212,215],{},[85,213,214],{},"Rule of thumb:"," If you cannot list every running container and its purpose in under two minutes, you have sprawl.",[101,217,219],{"id":218},"_2-logging-with-no-rotation","2. Logging With No Rotation",[63,221,222,223,226],{},"Docker captures stdout\u002Fstderr into JSON log files on the host — by default, ",[85,224,225],{},"with no size limit",". On a busy Laravel, Node, or nginx container, those files grow until the root partition is full.",[63,228,229],{},"Then everything fails at once: database writes, SSL renewals, SSH sessions, deploy scripts.",[63,231,232],{},[85,233,175],{},[63,235,236,237,239],{},"Set log rotation in ",[67,238,137],{}," or your daemon config:",[241,242,247],"pre",{"className":243,"code":244,"language":245,"meta":246,"style":246},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","services:\n  app:\n    logging:\n      driver: json-file\n      options:\n        max-size: \"10m\"\n        max-file: \"5\"\n","yaml","",[67,248,249,262,270,278,291,299,316],{"__ignoreMap":246},[250,251,254,258],"span",{"class":252,"line":253},"line",1,[250,255,257],{"class":256},"swJcz","services",[250,259,261],{"class":260},"sMK4o",":\n",[250,263,265,268],{"class":252,"line":264},2,[250,266,267],{"class":256},"  app",[250,269,261],{"class":260},[250,271,273,276],{"class":252,"line":272},3,[250,274,275],{"class":256},"    logging",[250,277,261],{"class":260},[250,279,281,284,287],{"class":252,"line":280},4,[250,282,283],{"class":256},"      driver",[250,285,286],{"class":260},":",[250,288,290],{"class":289},"sfazB"," json-file\n",[250,292,294,297],{"class":252,"line":293},5,[250,295,296],{"class":256},"      options",[250,298,261],{"class":260},[250,300,302,305,307,310,313],{"class":252,"line":301},6,[250,303,304],{"class":256},"        max-size",[250,306,286],{"class":260},[250,308,309],{"class":260}," \"",[250,311,312],{"class":289},"10m",[250,314,315],{"class":260},"\"\n",[250,317,319,322,324,326,329],{"class":252,"line":318},7,[250,320,321],{"class":256},"        max-file",[250,323,286],{"class":260},[250,325,309],{"class":260},[250,327,328],{"class":289},"5",[250,330,315],{"class":260},[63,332,333,334,337],{},"For production at scale, ship logs to a central sink — Loki, Grafana Cloud, Papertrail, or at minimum rsyslog. ",[85,335,336],{},"Docker logging"," on a VPS is not \"set and forget\" unless you cap it.",[63,339,340,341,344],{},"Also watch application-level logs mounted to volumes. A Laravel ",[67,342,343],{},"storage\u002Flogs"," directory on a bind mount can fill disk just as fast as Docker's json-file driver.",[101,346,348],{"id":347},"_3-ignoring-memory-leaks","3. Ignoring Memory Leaks",[63,350,351,352,355],{},"Applications leak memory. Node workers, PHP-FPM pools, Java heaps, Redis misconfigurations — they all drift upward over days. Without limits, one leaky container consumes the VPS until the ",[85,353,354],{},"Linux OOM killer"," intervenes.",[63,357,358],{},"The OOM killer does not politely stop your leak. It picks a process — often MySQL, PostgreSQL, or dockerd itself — and terminates it. Your \"random\" database crash at 3 a.m. was probably a memory leak three containers away.",[63,360,361],{},[85,362,175],{},[63,364,365],{},"Set memory limits per service:",[241,367,369],{"className":243,"code":368,"language":245,"meta":246,"style":246},"services:\n  app:\n    deploy:\n      resources:\n        limits:\n          memory: 512M\n",[67,370,371,377,383,390,397,404],{"__ignoreMap":246},[250,372,373,375],{"class":252,"line":253},[250,374,257],{"class":256},[250,376,261],{"class":260},[250,378,379,381],{"class":252,"line":264},[250,380,267],{"class":256},[250,382,261],{"class":260},[250,384,385,388],{"class":252,"line":272},[250,386,387],{"class":256},"    deploy",[250,389,261],{"class":260},[250,391,392,395],{"class":252,"line":280},[250,393,394],{"class":256},"      resources",[250,396,261],{"class":260},[250,398,399,402],{"class":252,"line":293},[250,400,401],{"class":256},"        limits",[250,403,261],{"class":260},[250,405,406,409,411],{"class":252,"line":301},[250,407,408],{"class":256},"          memory",[250,410,286],{"class":260},[250,412,413],{"class":289}," 512M\n",[63,415,416],{},"On standalone Docker Compose (non-Swarm), use the older syntax that still works in practice:",[241,418,420],{"className":243,"code":419,"language":245,"meta":246,"style":246},"services:\n  app:\n    mem_limit: 512m\n",[67,421,422,428,434],{"__ignoreMap":246},[250,423,424,426],{"class":252,"line":253},[250,425,257],{"class":256},[250,427,261],{"class":260},[250,429,430,432],{"class":252,"line":264},[250,431,267],{"class":256},[250,433,261],{"class":260},[250,435,436,439,441],{"class":252,"line":272},[250,437,438],{"class":256},"    mem_limit",[250,440,286],{"class":260},[250,442,443],{"class":289}," 512m\n",[63,445,446,447,450,451,454],{},"Monitor with ",[67,448,449],{},"docker stats"," or Prometheus + cAdvisor. Restart policies help containers recover, but they do not fix leaks — they just delay the crash. Profile the app, cap workers, and tune pool sizes (PHP-FPM ",[67,452,453],{},"pm.max_children",", Node cluster size, etc.).",[101,456,458],{"id":457},"_4-no-backup-strategy-for-volumes","4. No Backup Strategy for Volumes",[63,460,461],{},"This is the mistake that only hurts once — when you need a restore and discover backups were never real.",[63,463,464],{},"Common failures:",[129,466,467,473,476,479],{},[132,468,469,470],{},"Data stored inside the container filesystem instead of a ",[85,471,472],{},"named volume",[132,474,475],{},"Volumes exist but nothing snapshots them",[132,477,478],{},"Backups copy the git repo, not the PostgreSQL data directory",[132,480,481],{},"\"I will set up backups next week\" for eleven months",[63,483,484,485,488,489,492],{},"A ",[67,486,487],{},"docker compose down"," or ",[67,490,491],{},"docker volume rm"," on the wrong day becomes permanent data loss.",[63,494,495],{},[85,496,175],{},[129,498,499,502,512,519],{},[132,500,501],{},"Always use named volumes for databases and uploaded files",[132,503,504,505,142,508,511],{},"Automate backups: ",[67,506,507],{},"pg_dump",[67,509,510],{},"mysqldump",", or volume snapshots via your provider (Hetzner, DigitalOcean, Vultr all support this)",[132,513,514,515,518],{},"Store backups ",[85,516,517],{},"off-server"," — S3, Backblaze B2, another region",[132,520,521],{},"Test restores quarterly. A backup you have never restored is a guess",[523,524,525,530,533],"picture-and-text",{},[526,527,529],"h3",{"id":528},"the-3-2-1-rule-still-applies","The 3-2-1 rule still applies",[63,531,532],{},"Three copies, two media types, one off-site. Docker does not change that — it just makes it easier to forget where your data actually lives.",[534,535,536],"template",{"v-slot:image":246},[63,537,538],{},[92,539],{"alt":540,"className":541,"height":97,"src":542,"width":97},"External hard drives stacked for backup redundancy",[96],"https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1597872200969-2b65d56bd16b?w=400&h=400&fit=crop",[101,544,546],{"id":545},"_5-skipping-or-misconfiguring-reverse-proxies","5. Skipping or Misconfiguring Reverse Proxies",[63,548,549,550,553,554,557,558,561],{},"Exposing ",[67,551,552],{},"app:3000"," directly on ",[67,555,556],{},"0.0.0.0:3000"," is the fastest way to turn a VPS into a public attack surface. ",[85,559,560],{},"Reverse proxies"," — Traefik, Caddy, nginx — exist to terminate TLS, route by hostname, rate-limit, and keep application ports off the public internet.",[63,563,564],{},"Mistakes I see constantly:",[129,566,567,574,577,580,587],{},[132,568,569,570,573],{},"Apps bound to ",[67,571,572],{},"0.0.0.0"," with no firewall, no proxy, no TLS",[132,575,576],{},"Manual certbot on nginx configs that break on renewal",[132,578,579],{},"Mixing proxy configs across three tools on one server",[132,581,582,583,586],{},"WebSocket and SSE apps proxied without proper ",[67,584,585],{},"Upgrade"," headers",[132,588,589,590,593],{},"Trusting ",[67,591,592],{},"X-Forwarded-For"," without setting real IP headers correctly",[63,595,596],{},[85,597,175],{},[63,599,600],{},"Pick one reverse proxy per server. Traefik or Caddy shine with Docker labels; nginx is fine if you already know it cold.",[241,602,604],{"className":243,"code":603,"language":245,"meta":246,"style":246},"services:\n  app:\n    expose:\n      - \"3000\"\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.app.rule=Host(`app.example.com`)\"\n      - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n",[67,605,606,612,618,625,637,644,655,666],{"__ignoreMap":246},[250,607,608,610],{"class":252,"line":253},[250,609,257],{"class":256},[250,611,261],{"class":260},[250,613,614,616],{"class":252,"line":264},[250,615,267],{"class":256},[250,617,261],{"class":260},[250,619,620,623],{"class":252,"line":272},[250,621,622],{"class":256},"    expose",[250,624,261],{"class":260},[250,626,627,630,632,635],{"class":252,"line":280},[250,628,629],{"class":260},"      -",[250,631,309],{"class":260},[250,633,634],{"class":289},"3000",[250,636,315],{"class":260},[250,638,639,642],{"class":252,"line":293},[250,640,641],{"class":256},"    labels",[250,643,261],{"class":260},[250,645,646,648,650,653],{"class":252,"line":301},[250,647,629],{"class":260},[250,649,309],{"class":260},[250,651,652],{"class":289},"traefik.enable=true",[250,654,315],{"class":260},[250,656,657,659,661,664],{"class":252,"line":318},[250,658,629],{"class":260},[250,660,309],{"class":260},[250,662,663],{"class":289},"traefik.http.routers.app.rule=Host(`app.example.com`)",[250,665,315],{"class":260},[250,667,669,671,673,676],{"class":252,"line":668},8,[250,670,629],{"class":260},[250,672,309],{"class":260},[250,674,675],{"class":289},"traefik.http.routers.app.tls.certresolver=letsencrypt",[250,677,315],{"class":260},[63,679,680,681,684],{},"Bind apps to internal networks only. Let the proxy be the single public entry point on ports 80 and 443. Lock everything else with ",[67,682,683],{},"ufw"," or your provider firewall.",[101,686,688],{"id":687},"_6-no-health-checks-or-restart-policies","6. No Health Checks or Restart Policies",[63,690,691,692,695],{},"Containers exit. Processes segfault. Servers reboot. Without ",[67,693,694],{},"restart: unless-stopped"," and proper health checks, your app stays down until a human notices — or until a client sends an angry email.",[63,697,698,699,701],{},"I have SSH'd into servers where ",[67,700,80],{}," showed a clean bill of health, but the app container had been restarting in a crash loop for days because nothing monitored it.",[63,703,704],{},[85,705,175],{},[241,707,709],{"className":243,"code":708,"language":245,"meta":246,"style":246},"services:\n  app:\n    restart: unless-stopped\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http:\u002F\u002Flocalhost:3000\u002Fhealth\"]\n      interval: 30s\n      timeout: 5s\n      retries: 3\n      start_period: 40s\n",[67,710,711,717,723,733,740,789,799,809,820],{"__ignoreMap":246},[250,712,713,715],{"class":252,"line":253},[250,714,257],{"class":256},[250,716,261],{"class":260},[250,718,719,721],{"class":252,"line":264},[250,720,267],{"class":256},[250,722,261],{"class":260},[250,724,725,728,730],{"class":252,"line":272},[250,726,727],{"class":256},"    restart",[250,729,286],{"class":260},[250,731,732],{"class":289}," unless-stopped\n",[250,734,735,738],{"class":252,"line":280},[250,736,737],{"class":256},"    healthcheck",[250,739,261],{"class":260},[250,741,742,745,747,750,753,756,758,761,763,766,768,770,772,775,777,779,781,784,786],{"class":252,"line":293},[250,743,744],{"class":256},"      test",[250,746,286],{"class":260},[250,748,749],{"class":260}," [",[250,751,752],{"class":260},"\"",[250,754,755],{"class":289},"CMD",[250,757,752],{"class":260},[250,759,760],{"class":260},",",[250,762,309],{"class":260},[250,764,765],{"class":289},"curl",[250,767,752],{"class":260},[250,769,760],{"class":260},[250,771,309],{"class":260},[250,773,774],{"class":289},"-f",[250,776,752],{"class":260},[250,778,760],{"class":260},[250,780,309],{"class":260},[250,782,783],{"class":289},"http:\u002F\u002Flocalhost:3000\u002Fhealth",[250,785,752],{"class":260},[250,787,788],{"class":260},"]\n",[250,790,791,794,796],{"class":252,"line":301},[250,792,793],{"class":256},"      interval",[250,795,286],{"class":260},[250,797,798],{"class":289}," 30s\n",[250,800,801,804,806],{"class":252,"line":318},[250,802,803],{"class":256},"      timeout",[250,805,286],{"class":260},[250,807,808],{"class":289}," 5s\n",[250,810,811,814,816],{"class":252,"line":668},[250,812,813],{"class":256},"      retries",[250,815,286],{"class":260},[250,817,819],{"class":818},"sbssI"," 3\n",[250,821,823,826,828],{"class":252,"line":822},9,[250,824,825],{"class":256},"      start_period",[250,827,286],{"class":260},[250,829,830],{"class":289}," 40s\n",[63,832,833,834,837],{},"Expose a real ",[67,835,836],{},"\u002Fhealth"," endpoint — not just \"port open.\" Check database connectivity if your app needs it. Pair this with uptime monitoring (Uptime Kuma, Better Stack, Pingdom) so failures reach you before users do.",[101,839,841,842,845],{"id":840},"_7-treating-latest-and-dev-defaults-as-production-config","7. Treating ",[67,843,844],{},"latest"," and Dev Defaults as Production Config",[63,847,848,849,852],{},"Pulling ",[67,850,851],{},"image: latest"," on every deploy is not continuous delivery — it is roulette. A upstream breaking change at midnight becomes your outage.",[63,854,855],{},"Other dev defaults that leak into production:",[129,857,858,864,867,870],{},[132,859,860,863],{},[67,861,862],{},"DEBUG=true"," in environment variables",[132,865,866],{},"Compose files with volume mounts to source code (hot reload on a VPS)",[132,868,869],{},"No pinned image digests or version tags",[132,871,872],{},"Docker socket mounted into containers for \"convenience\"",[63,874,875],{},[85,876,175],{},[129,878,879,888,898,905],{},[132,880,881,882,142,885],{},"Pin versions: ",[67,883,884],{},"postgres:16.2",[67,886,887],{},"redis:7.2-alpine",[132,889,890,891,894,895],{},"Use ",[67,892,893],{},".env.production"," separate from local ",[67,896,897],{},".env",[132,899,900,901,904],{},"Never mount ",[67,902,903],{},"\u002Fvar\u002Frun\u002Fdocker.sock"," unless you fully understand the security implications",[132,906,907],{},"Tag and push your own app images to a registry — build once, deploy the same artifact",[101,909,911],{"id":910},"quick-reference-symptom-likely-cause","Quick Reference: Symptom → Likely Cause",[913,914,915,931],"table",{},[916,917,918],"thead",{},[919,920,921,925,928],"tr",{},[922,923,924],"th",{},"Symptom",[922,926,927],{},"Likely cause",[922,929,930],{},"First move",[932,933,934,954,971,993,1004,1015],"tbody",{},[919,935,936,940,943],{},[937,938,939],"td",{},"Disk full, SSH sluggish",[937,941,942],{},"Unbounded Docker logs",[937,944,945,946,949,950,953],{},"Set ",[67,947,948],{},"max-size"," \u002F ",[67,951,952],{},"max-file","; prune old logs",[919,955,956,959,962],{},[937,957,958],{},"Random DB restarts",[937,960,961],{},"OOM from memory leak",[937,963,964,966,967,970],{},[67,965,449],{},"; set ",[67,968,969],{},"mem_limit","; fix the leak",[919,972,973,976,983],{},[937,974,975],{},"\"It worked yesterday\" after reboot",[937,977,978,979,982],{},"No ",[67,980,981],{},"restart"," policy",[937,984,985,986,989,990],{},"Add ",[67,987,988],{},"unless-stopped","; check ",[67,991,992],{},"docker ps -a",[919,994,995,998,1001],{},[937,996,997],{},"SSL expired",[937,999,1000],{},"Proxy\u002Fcertbot misconfig",[937,1002,1003],{},"Centralize TLS on one reverse proxy",[919,1005,1006,1009,1012],{},[937,1007,1008],{},"Data gone after redeploy",[937,1010,1011],{},"No volume \u002F no backup",[937,1013,1014],{},"Named volumes + off-site dumps",[919,1016,1017,1020,1022],{},[937,1018,1019],{},"Too many unknown containers",[937,1021,123],{},[937,1023,1024],{},"Audit, name projects, prune, document",[101,1026,1028],{"id":1027},"frequently-asked-questions","Frequently Asked Questions",[1030,1031,1032,1039,1045,1056],"accordion",{},[1033,1034,1036],"accordion-item",{"label":1035},"How much RAM does Docker need on a VPS?",[63,1037,1038],{},"Plan for your apps plus 20–30% headroom for the OS, Docker daemon, and spikes. A small stack (reverse proxy + app + database) often needs 2 GB minimum; 4 GB is safer for production. Always set per-container memory limits so one service cannot take the whole server.",[1033,1040,1042],{"label":1041},"What is the best reverse proxy for Docker on a VPS?",[63,1043,1044],{},"Traefik and Caddy integrate cleanly with Docker labels and automatic Let's Encrypt. nginx is excellent if you prefer explicit config files. The best choice is the one you will maintain consistently — not three different proxies on the same box.",[1033,1046,1048],{"label":1047},"How do I back up Docker volumes on a VPS?",[63,1049,1050,1051,142,1053,1055],{},"Use database-native dumps (",[67,1052,507],{},[67,1054,510],{},") on a schedule, copy artifacts off-server, and optionally snapshot volumes at the provider level. Test restores regularly. Backups that only exist on the same VPS as your data are not disaster recovery.",[1033,1057,1059],{"label":1058},"Why does my VPS crash after running Docker for weeks?",[63,1060,1061,1062,142,1065,146,1068,1070],{},"Usually disk full from logs, memory exhaustion from leaks without limits, or container sprawl consuming resources. Check ",[67,1063,1064],{},"df -h",[67,1066,1067],{},"docker system df",[67,1069,449],{},". Those three commands diagnose most \"mystery\" VPS crashes.",[101,1072,1074],{"id":1073},"conclusion","Conclusion",[63,1076,1077,1080],{},[85,1078,1079],{},"Docker on a production VPS"," rewards discipline more than cleverness. Container sprawl, runaway logging, unchecked memory leaks, missing backup strategy, and reverse proxies done wrong are not exotic failures — they are the default outcome when Docker is treated as a local dev tool dropped onto a live server.",[63,1082,1083],{},"None of these require Kubernetes or an enterprise platform. They require caps on logs, limits on memory, named volumes with real backups, one reverse proxy at the edge, and the habit of cleaning up what you deploy.",[63,1085,1086],{},"Your future self — the one SSH'ing in at 2 a.m. — will thank you for boring infrastructure.",[208,1088,1089],{},[63,1090,1091,1094,1095,1100,1101,1104],{},[85,1092,1093],{},"Running Docker on a VPS and not sure if your setup will survive traffic?"," I write about production architecture from ",[1096,1097,1099],"a",{"href":1098},"\u002Fblog\u002Fbluetooth-pos","Laravel stacks"," to the ops layer that keeps them online. If your server keeps crashing and you want a second pair of eyes on compose files, logging, and backups — hit ",[85,1102,1103],{},"Connect"," on this site.",[1106,1107],"hr",{},[63,1109,1110],{},[72,1111,1112,1113,1119],{},"Images from ",[1096,1114,1118],{"href":1115,"rel":1116},"https:\u002F\u002Funsplash.com",[1117],"nofollow","Unsplash"," — free to use under the Unsplash License.",[1121,1122,1123],"style",{},"html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":246,"searchDepth":264,"depth":264,"links":1125},[1126,1127,1128,1129,1130,1133,1134,1135,1137,1138,1139],{"id":103,"depth":264,"text":104},{"id":117,"depth":264,"text":118},{"id":218,"depth":264,"text":219},{"id":347,"depth":264,"text":348},{"id":457,"depth":264,"text":458,"children":1131},[1132],{"id":528,"depth":272,"text":529},{"id":545,"depth":264,"text":546},{"id":687,"depth":264,"text":688},{"id":840,"depth":264,"text":1136},"7. Treating latest and Dev Defaults as Production Config",{"id":910,"depth":264,"text":911},{"id":1027,"depth":264,"text":1028},{"id":1073,"depth":264,"text":1074},"2026-06-26","Container sprawl, runaway logging, memory leaks, missing backups, and reverse proxy misconfigurations — the Docker mistakes that crash VPS servers and how to avoid them.","md",{"src":1144},"https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1558494949-ef010cbdcc31?w=640&h=360&fit=crop",{},true,"\u002Fblog\u002F7-docker-mistakes-i-keep-seeing-on-production-servers",{"title":1149,"description":1150,"keywords":1151},"7 Docker Mistakes That Crash VPS Servers — Production DevOps Guide","Common Docker production mistakes on VPS servers — container sprawl, logging, memory leaks, backup strategy, and reverse proxies — plus fixes that keep your stack online.","Docker, DevOps, VPS, production servers, container sprawl, logging, memory leaks, reverse proxy, backups","3.blog\u002F4.7-docker-mistakes-i-keep-seeing-on-production-servers","2mgPBszBNoMKGnFi6UeJAgn-WvWrJxPtWS59oMl-w3c",[1155,1160],{"title":1156,"path":1157,"stem":1158,"description":1159,"children":-1},"The Hidden Technical Debt in Laravel Projects","\u002Fblog\u002Fthe-hidden-technical-debt-in-laravel-projects","3.blog\u002F3.the-hidden-technical-debt-in-laravel-projects","Why most Laravel codebases become difficult to maintain — and how fat controllers, service layers, repository patterns, and modular architecture quietly compound the problem.",{"title":1161,"path":1162,"stem":1163,"description":1164,"children":-1},"WhatsApp Username, What Is It and What Should We Do?","\u002Fblog\u002Fwhatsapp-username-what-is-it-and-what-should-we-do","3.blog\u002F5.whatsapp-username-what-is-it-and-what-should-we-do","WhatsApp usernames let you start chats without sharing your phone number. Here is what the feature means, the privacy benefits, the scam risks, and what to do now.",{"url":1166},"https:\u002F\u002Fadislksn.web.id",1783705974593]