{"id":34307,"date":"2025-12-07T16:53:48","date_gmt":"2025-12-07T09:53:48","guid":{"rendered":"https:\/\/dps.media\/?p=34307"},"modified":"2025-12-07T16:53:51","modified_gmt":"2025-12-07T09:53:51","slug":"guide-to-self-hosting-supabase-on-fastpanel-with-docker-portainer-resolving-port-conflicts","status":"publish","type":"post","link":"https:\/\/dps.media\/en\/guide-to-self-hosting-supabase-on-fastpanel-with-docker-portainer-resolving-port-conflicts\/","title":{"rendered":"Guide to Self-Hosting Supabase on Fastpanel with Docker &amp; Portainer (Resolving Port Conflicts)"},"content":{"rendered":"<?xml encoding=\"utf-8\" ?><p>Want to run Supabase (Firebase Alternative) on VPS Fastpanel but encountering port 8000\/3000 conflict errors? This article provides detailed instructions on deploying Supabase with Docker, separating domains for API and Studio Dashboard for the most stable system operation.<\/p><p>Supabase l\u00e0 m\u1ed9t gi\u1ea3i ph\u00e1p thay th\u1ebf m\u00e3 ngu\u1ed3n m\u1edf tuy\u1ec7t v\u1eddi cho Firebase. Tuy nhi\u00ean, vi\u1ec7c t\u1ef1 host (Self-host) Supabase tr\u00ean m\u1ed9t VPS \u0111\u00e3 c\u00e0i s\u1eb5n Control Panel (nh\u01b0 Fastpanel, CyberPanel\u2026) th\u01b0\u1eddng g\u1eb7p nhi\u1ec1u kh\u00f3 kh\u0103n, \u0111\u1eb7c bi\u1ec7t l\u00e0 v\u1ea5n \u0111\u1ec1 <strong>Reverse Proxy<\/strong> and <strong>Port Conflict<\/strong>.<\/p><p>By default, Supabase uses port <code>8000<\/code> for API Gateway, this port is often conflicted by other services (like Portainer or default Nginx). Additionally, the admin Dashboard (Supabase Studio) runs on port <code>3000<\/code> and needs to be properly configured to access.<\/p><p>In this article, <strong>DPS Media<\/strong> will share experience deploying Supabase on Ubuntu 24.04 using Fastpanel, with custom port configuration: <strong>API runs on port 8008<\/strong> and <strong>Studio runs on port 3003<\/strong>.<\/p><h2 class=\"wp-block-heading\">1. Prepare resources<\/h2><ul class=\"wp-block-list\">\n<li><strong>VPS:<\/strong> Ubuntu 22.04 or 24.04 (Recommended minimum 4GB RAM).<\/li>\n\n\n\n<li><strong>Fastpanel:<\/strong> Pre-installed.<\/li>\n\n\n\n<li><strong>Docker & Portainer:<\/strong> Installed (See previous guide).<\/li>\n\n\n\n<li><strong>Domain name:<\/strong> You need to prepare 2 subdomains:\n<ul class=\"wp-block-list\">\n<li><code>studio.domain.com<\/code>: Used for management interface.<\/li>\n\n\n\n<li><code>spb.domain.com<\/code>: Used for API backend.<\/li>\n<\/ul>\n<\/li>\n<\/ul><h2 class=\"wp-block-heading\">2. Download Supabase source code<\/h2><p>Access SSH to VPS with root privileges and download Supabase's Docker deploy kit:<\/p><p>Bash<\/p><pre class=\"wp-block-code\"><code># Move to working directory\ncd \/opt\n\n# Download source code from Github\ngit clone --depth 1 https:\/\/github.com\/supabase\/supabase\n\n# Enter the Docker configuration directory\ncd supabase\/docker\n<\/code><\/pre><h2 class=\"wp-block-heading\">3. Configure Docker Compose (Avoid port conflicts)<\/h2><p>This is the most important step. We will not use the default port (8000) to avoid conflicts with Portainer or other services.<\/p><p>Open file <code>docker-compose.yml<\/code>:<\/p><p>Bash<\/p><pre class=\"wp-block-code\"><code>nano docker-compose.yml\n<\/code><\/pre><p><strong>Make 2 important changes:<\/strong><\/p><ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Open port for Studio (Interface):<\/strong> Find service <code>studio<\/code>, add section <code>ports<\/code> to map port 3003 of VPS to port 3000 of container.<\/li>\n\n\n\n<li><strong>Change port for Kong (API):<\/strong> Find service <code>kong<\/code>, change map port to 8008.<\/li>\n<\/ol><p>The modified code will look like this:<\/p><p>YAML<\/p><pre class=\"wp-block-code\"><code>services:\n  studio:\n    image: supabase\/studio:2025...\n    # ... c\u00e1c config kh\u00e1c gi\u1eef nguy\u00ean\n    ports:\n      - \"3003:3000\"  # Map Host 3003 -> Container 3000\n\n  kong:\n    image: kong:2.8.1\n    # ... c\u00e1c config kh\u00e1c gi\u1eef nguy\u00ean\n    ports:\n      - \"8008:8000\/tcp\" # Map Host 8008 -> Container 8000 (API)\n      - \"${KONG_HTTPS_PORT}:8443\/tcp\"\n<\/code><\/pre><h2 class=\"wp-block-heading\">4. Configure environment variables (.env)<\/h2><p>Copy sample file and edit:<\/p><p>Bash<\/p><pre class=\"wp-block-code\"><code>cp .env.example .env\nnano .env\n<\/code><\/pre><p>You need to fill in strong passwords (Database, JWT Secret) and most importantly configure the URL to match the 2 prepared subdomains.<\/p><p><strong>Mandatory parameters to edit:<\/strong><\/p><p>Bash<\/p><pre class=\"wp-block-code\"><code># 1. Security (Generate strong random string yourself)\nPOSTGRES_PASSWORD=VeryStrongDbPassword!!!\nJWT_SECRET=Long_Secret_JWT_String_At_Least_32_Characters\nDASHBOARD_PASSWORD=WebLoginPassword!!!\n\n# 2. API Port Configuration (Must match the yml file above)\nKONG_HTTP_PORT=8008\n\n# 3. Domain Configuration (Important)\n# SITE_URL: Is the access address for Studio interface\nSITE_URL=https:\/\/studio.domain.com\n\n# SUPABASE_PUBLIC_URL: Is the API address (Studio will call this link to get data)\n# NOTE: Must fill in API domain, DO NOT fill in Studio domain\nSUPABASE_PUBLIC_URL=https:\/\/spb.domain.com\n\n# API Auth: Also points to API domain\nAPI_EXTERNAL_URL=https:\/\/spb.domain.com\n\n# Redirect URL: Add studio domain as well to return to the right place after login\nADDITIONAL_REDIRECT_URLS=https:\/\/studio.domain.com,https:\/\/spb.domain.com\n<\/code><\/pre><h2 class=\"wp-block-heading\">5. Start Supabase<\/h2><p>After configuration is complete, run the following command for Docker to download and build the system:<\/p><p>Bash<\/p><pre class=\"wp-block-code\"><code>docker compose up -d\n<\/code><\/pre><p><em>Note: This process may take 5-10 minutes to download about 1GB images.<\/em><\/p><h2 class=\"wp-block-heading\">6. Configure Reverse Proxy on Fastpanel<\/h2><p>To access the web without typing <code>IP:3003<\/code>, we use the Proxy feature of Fastpanel.<\/p><h3 class=\"wp-block-heading\">Page 1: Management interface (Studio)<\/h3><ol start=\"1\" class=\"wp-block-list\">\n<li>Create new site: <strong>Reverse Proxy<\/strong>.<\/li>\n\n\n\n<li>Domain: <code>studio.domain.com<\/code>.<\/li>\n\n\n\n<li>Upstream: <code>http:\/\/127.0.0.1:3003<\/code>.<\/li>\n\n\n\n<li><strong>Extremely important:<\/strong> Go to Settings -&gt; Static Content -&gt; <strong>TURN OFF<\/strong> line <em>\u201cUse NGINX for static files\u201d<\/em>.<\/li>\n\n\n\n<li>C\u00e0i SSL Let\u2019s Encrypt.<\/li>\n<\/ol><h3 class=\"wp-block-heading\">Page 2: API Backend (Supabase)<\/h3><ol start=\"1\" class=\"wp-block-list\">\n<li>Create new site: <strong>Reverse Proxy<\/strong>.<\/li>\n\n\n\n<li>Domain: <code>spb.domain.com<\/code>.<\/li>\n\n\n\n<li>Upstream: <code>http:\/\/127.0.0.1:8008<\/code>.<\/li>\n\n\n\n<li>Also <strong>TURN OFF<\/strong> line <em>\u201cUse NGINX for static files\u201d<\/em>.<\/li>\n\n\n\n<li>C\u00e0i SSL Let\u2019s Encrypt.<\/li>\n<\/ol><p><em>(Note: Page <code>spb<\/code> when accessed directly will report 404 Not Found error, this is normal because API Gateway has no interface).<\/em><\/p><h2 class=\"wp-block-heading\">7. K\u1ebft qu\u1ea3 & \u0110\u0103ng nh\u1eadp<\/h2><p>Now you access: <strong><code>https:\/\/studio.domain.com<\/code><\/strong><\/p><ul class=\"wp-block-list\">\n<li>Log in with account: <code>supabase<\/code> \/ Password you set in <code>.env<\/code>.<\/li>\n<\/ul><p><strong>Connection parameters for Dev:<\/strong><\/p><ul class=\"wp-block-list\">\n<li><strong>Project URL:<\/strong> <code>https:\/\/spb.domain.com<\/code><\/li>\n\n\n\n<li><strong>Anon\/Service Key:<\/strong> Get in Dashboard (Settings -&gt; API).<\/li>\n<\/ul><h2 class=\"wp-block-heading\">Conclusion<\/h2><p>Separation <strong>Studio (Port 3003)<\/strong> and <strong>API (Port 8008<\/strong> helps the Supabase system run smoothly on Fastpanel without interfering with other default services. Hope this guide helps you take control of your powerful Backend infrastructure.<\/p><hr class=\"wp-block-separator has-alpha-channel-opacity\"><p><em>Source: <a class=\"wpil_keyword_link\" href=\"https:\/\/dps.media\/en\/\" title=\"DPS.MEDIA JSC\" data-wpil-keyword-link=\"linked\" data-wpil-monitor-id=\"588\">dps.media<\/a><\/em><\/p><p><\/p>\n<style>\r\n.lwrp.link-whisper-related-posts{\r\n            \r\n            margin-top: 40px;\nmargin-bottom: 30px;\r\n        }\r\n        .lwrp .lwrp-title{\r\n            \r\n            \r\n        }.lwrp .lwrp-description{\r\n            \r\n            \r\n\r\n        }\r\n        .lwrp .lwrp-list-container{\r\n        }\r\n        .lwrp .lwrp-list-multi-container{\r\n            display: flex;\r\n        }\r\n        .lwrp .lwrp-list-double{\r\n            width: 48%;\r\n        }\r\n        .lwrp .lwrp-list-triple{\r\n            width: 32%;\r\n        }\r\n        .lwrp .lwrp-list-row-container{\r\n            display: flex;\r\n            justify-content: space-between;\r\n        }\r\n        .lwrp .lwrp-list-row-container .lwrp-list-item{\r\n            width: calc(33% - 20px);\r\n        }\r\n        .lwrp .lwrp-list-item:not(.lwrp-no-posts-message-item){\r\n            \r\n            max-width: 150px;\r\n        }\r\n        .lwrp .lwrp-list-item img{\r\n            max-width: 100%;\r\n            height: auto;\r\n            object-fit: cover;\r\n            aspect-ratio: 1 \/ 1;\r\n        }\r\n        .lwrp .lwrp-list-item.lwrp-empty-list-item{\r\n            background: initial !important;\r\n        }\r\n        .lwrp .lwrp-list-item .lwrp-list-link .lwrp-list-link-title-text,\r\n        .lwrp .lwrp-list-item .lwrp-list-no-posts-message{\r\n            \r\n            \r\n            \r\n            \r\n        }@media screen and (max-width: 480px) {\r\n            .lwrp.link-whisper-related-posts{\r\n                \r\n                \r\n            }\r\n            .lwrp .lwrp-title{\r\n                \r\n                \r\n            }.lwrp .lwrp-description{\r\n                \r\n                \r\n            }\r\n            .lwrp .lwrp-list-multi-container{\r\n                flex-direction: column;\r\n            }\r\n            .lwrp .lwrp-list-multi-container ul.lwrp-list{\r\n                margin-top: 0px;\r\n                margin-bottom: 0px;\r\n                padding-top: 0px;\r\n                padding-bottom: 0px;\r\n            }\r\n            .lwrp .lwrp-list-double,\r\n            .lwrp .lwrp-list-triple{\r\n                width: 100%;\r\n            }\r\n            .lwrp .lwrp-list-row-container{\r\n                justify-content: initial;\r\n                flex-direction: column;\r\n            }\r\n            .lwrp .lwrp-list-row-container .lwrp-list-item{\r\n                width: 100%;\r\n            }\r\n            .lwrp .lwrp-list-item:not(.lwrp-no-posts-message-item){\r\n                \r\n                max-width: initial;\r\n            }\r\n            .lwrp .lwrp-list-item .lwrp-list-link .lwrp-list-link-title-text,\r\n            .lwrp .lwrp-list-item .lwrp-list-no-posts-message{\r\n                \r\n                \r\n                \r\n                \r\n            };\r\n        }<\/style>\r\n<div id=\"link-whisper-related-posts-widget\" class=\"link-whisper-related-posts lwrp\">\r\n            <div class=\"lwrp-title\">Related Posts<\/div>    \r\n        <div class=\"lwrp-list-container\">\r\n                                <div class=\"lwrp-list lwrp-list-row-container lwrp-list-double-row\">\r\n                <div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/optimize-advertising-costs-on-facebook-with-just-5-steps\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Optimize Facebook advertising costs in just 5 steps<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/how-to-livestream-on-facebook-to-sell-products-and-reach-1000-first-views\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">How to livestream on Facebook to achieve 1000 views on the first broadcast<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/pr-press-booking-services-but-common-mistakes-businesses-make\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">PR newspaper booking service: Common mistakes businesses make<\/span><\/a><\/div>                <\/div>\r\n                            <div class=\"lwrp-list lwrp-list-row-container lwrp-list-double-row\">\r\n                <div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/how-to-promote-a-spa-without-running-ads-in-the-first-30-days\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">How to promote a spa without running ads in the first 30 days<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/marketing-course-in-hanoi-the-best-choice-to-improve-skills\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Marketing courses in Hanoi: The best choices to improve skills<\/span><\/a><\/div><div class=\"lwrp-list-item\"><a href=\"https:\/\/dps.media\/en\/google-gemini-now-supports-audio-files-as-a-note\/\" class=\"lwrp-list-link\"><span class=\"lwrp-list-link-title-text\">Google Gemini newly supports audio files worth noting<\/span><\/a><\/div>                <\/div>\r\n                <\/div>\r\n<\/div>","protected":false},"excerpt":{"rendered":"<p>B\u1ea1n mu\u1ed1n ch\u1ea1y Supabase (Firebase Alternative) tr\u00ean VPS Fastpanel nh\u01b0ng g\u1eb7p l\u1ed7i xung \u0111\u1ed9t c\u1ed5ng 8000\/3000? B\u00e0i vi\u1ebft n\u00e0y h\u01b0\u1edbng d\u1eabn chi ti\u1ebft c\u00e1ch deploy Supabase v\u1edbi Docker, t\u00e1ch ri\u00eang domain cho API v\u00e0 Studio Dashboard \u0111\u1ec3 h\u1ec7 th\u1ed1ng ho\u1ea1t \u0111\u1ed9ng \u1ed5n \u0111\u1ecbnh nh\u1ea5t.Supabase l\u00e0 m\u1ed9t gi\u1ea3i ph\u00e1p thay th\u1ebf m\u00e3 ngu\u1ed3n m\u1edf tuy\u1ec7t v\u1eddi [&hellip;]<\/p>","protected":false},"author":1,"featured_media":34308,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,1621],"tags":[],"class_list":["post-34307","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","category-fastpanel"],"acf":[],"rankmath_keywords":{"primary":"","secondary":[""]},"yoast_keywords":{"primary":"","secondary":[]},"yoast_focuskw":"","rankmath_focuskw":"","seo_keywords":{"primary":"","secondary":[""]},"_links":{"self":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/34307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/comments?post=34307"}],"version-history":[{"count":2,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/34307\/revisions"}],"predecessor-version":[{"id":34310,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/posts\/34307\/revisions\/34310"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/media\/34308"}],"wp:attachment":[{"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/media?parent=34307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/categories?post=34307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dps.media\/en\/wp-json\/wp\/v2\/tags?post=34307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}