Budowa strony SaaS w Hugo: od konfiguracji do wdrożenia w Oracle Cloud
Wprowadzenie
Budując aplikację SaaS, kluczowe jest stworzenie silnej obecności w sieci. Potrzebujemy miejsca, gdzie możemy publikować informacje o produkcie, udostępniać dokumentację i prezentować ofertę potencjalnym klientom.
Wybór właściwego narzędzia
Po analizie dostępnych rozwiązań zawęziłem wybór do dwóch ciekawych opcji. Pierwszą był Ghost — potężna platforma, ale wiąże się z kosztami subskrypcji. Na obecnym etapie projektu minimalizacja wydatków jest kluczowa, ponieważ mój SaaS nie generuje jeszcze przychodów. Drugą opcją było Hugo, które okazało się idealnym wyborem.
Dlaczego Hugo?
Hugo to niezwykle szybki generator statycznych stron, który pozwala tworzyć witryny, blogi i dokumentację w oparciu o proste pliki Markdown. Zamiast baz danych czy złożonych frameworków, Hugo konwertuje pliki .md do gotowego HTML, który można łatwo hostować na platformach takich jak GitHub Pages, Netlify, Vercel lub — w naszym przypadku — Oracle Cloud.
Najważniejsze zalety:
- Błyskawiczne czasy kompilacji — strony budują się w milisekundach
- Brak zależności uruchomieniowych — czyste pliki statyczne
- Markdown‑first — łatwe tworzenie treści
- Rozszerzalność — bogaty ekosystem motywów i wtyczek
- Kosztowo efektywne — darmowe opcje hostingu dostępne
Nasza strategia wdrożenia
Naszym celem jest wdrożenie witryny w kontenerze Docker na Oracle Cloud (Always Free), zapewniając solidny hosting bez stałych kosztów.
Instrukcja instalacji krok po kroku
Wymagania wstępne
Pracuję na Windows z zainstalowanym Chocolatey — wykorzystamy go do szybkiej instalacji Hugo CLI.
Uwaga: Jeśli nie masz Chocolatey, odwiedź chocolatey.org, aby zainstalować narzędzie.
Instalacja Hugo Extended
Otwórz terminal jako administrator i uruchom:
choco install hugo-extended -y
Dlaczego Hugo Extended? Wersja rozszerzona jest kluczowa w naszym przypadku. Hugo Extended zawiera:
- Integrację z TailwindCSS — nowoczesny, użytecznościowy framework CSS
- Wbudowany kompilator Sass/SCSS — zaawansowane przetwarzanie CSS
- Obsługę PostCSS — transformacje i optymalizacje CSS
- Przetwarzanie obrazów WebP — wsparcie dla nowoczesnego formatu
Te funkcje są wymagane przez większość współczesnych motywów Hugo, w tym przez motyw, którego użyjemy.
Tworzenie nowego projektu Hugo
Zainicjuj nową witrynę:
hugo new site EasyDeploySaaS
cd EasyDeploySaaS
Dodanie motywu
Użyjemy hugo-saasify-theme — nowoczesnego motywu stworzonego z myślą o stronach SaaS:
git init
git submodule add https://github.com/lukasztomalczyk/hugo-saasify-theme themes/hugo-saasify-theme
Konfiguracja początkowa
Utwórz podstawowy plik konfiguracyjny (hugo.toml):
baseURL = "https://your-domain.com"
title = "Your SaaS Name"
theme = "hugo-saasify-theme"
[module]
[module.hugoVersion]
extended = true
min = "0.80.0"
Testowanie konfiguracji
Uruchom serwer deweloperski, aby sprawdzić, czy wszystko działa:
hugo server -D
Witryna będzie dostępna pod adresem http://localhost:1313.
Budowanie witryny
Gdy treść będzie gotowa, wygeneruj statyczne pliki:
hugo --minify
To polecenie tworzy zoptymalizowane pliki w katalogu public/, gotowe do wdrożenia.
Wdrożenie do Oracle Cloud
Teraz wdrożymy witrynę Hugo do Oracle Cloud, używając Dockera i Azure Pipelines.
Tworzenie Dockerfile
Utwórz Dockerfile w katalogu głównym projektu, korzystając z wieloetapowego builda:
# Etap 1: Budowa Hugo + TailwindCSS
FROM hugomods/hugo:debian-std-exts-0.152.2 AS builder
WORKDIR /src
COPY . .
# Instalacja zależności motywu (TailwindCSS / PostCSS)
RUN npm install
# Budowa CSS/JS i generowanie witryny Hugo
RUN npm run build
# Etap 2: Serwowanie przez Nginx
FROM nginx:alpine
# Usunięcie domyślnej zawartości
RUN rm -rf /usr/share/nginx/html/*
# Kopiowanie zbudowanych plików Hugo
COPY --from=builder /src/public /usr/share/nginx/html
# Kopiowanie niestandardowej konfiguracji Nginx
COPY nginx.conf /etc/nginx/nginx.conf
# Wystawienie niestandardowego portu
EXPOSE 8091
# Start Nginx
CMD ["nginx", "-g", "daemon off;"]
Konfiguracja Azure Pipeline
Użyjemy Azure Pipelines do automatycznego wdrożenia. Należy:
- Skonfigurować połączenie SSH w Azure DevOps
- Ustawić dane połączeniowe serwera
Potok 1: Budowa i wysyłka obrazu Docker
Create website-azure-pipeline-compile.yml:
trigger: none
parameters:
- name: repository
displayName: Repository
type: string
default: 'Production'
values:
- Production
- Test
variables:
docker_tag: '${{ parameters.repository }}'
app_name: 'EasyDeployWebsite'
app_name_lower: 'easy-deploy-website'
resources:
- repo: self
stages:
- stage: Build
displayName: Build Multiarch Docker Image
jobs:
- job: Build
displayName: Build and Push Multiarch Image
pool:
vmImage: ubuntu-latest
steps:
- checkout: self
submodules: true
# Docker Hub login
- task: Docker@2
displayName: Docker Login
inputs:
command: login
containerRegistry: 'hub.docker.com'
# Setup QEMU for ARM emulation
- script: |
docker run --rm --privileged tonistiigi/binfmt --install all
displayName: Setup QEMU for multiarch
# Create buildx builder
- script: |
docker buildx create --use --name mybuilder
docker buildx inspect --bootstrap
displayName: Setup Docker Buildx
# Build and push multiarch image
- script: |
docker buildx build \
--platform linux/arm64 \
-f $(Build.SourcesDirectory)/src/Dockerfile \
-t lukasztomalczyk/sp-craft.$(app_name_lower)-arm64:$(Build.BuildId) \
-t lukasztomalczyk/sp-craft.$(app_name_lower)-arm64:$(docker_tag) \
$(Build.SourcesDirectory)/src \
--push
displayName: Build and Push Multiarch Docker Image
Potok 2: Wdrożenie na serwer
Create website-azure-pipeline-install.yml:
trigger: none
parameters:
- name: server
displayName: Environment
type: string
default: 'Production'
values:
- Production
- Test
variables:
- name: environment
value: '${{ parameters.server }}'
- name: app_name
value: 'EasyDeployWebsite'
- name: server_username
value: 'opc'
resources:
- repo: self
stages:
- stage: Deploy
displayName: Deploy to Server
jobs:
- job: Deploy
displayName: Deploy and Run
pool:
vmImage: ubuntu-latest
steps:
- task: SSH@0
displayName: Create required folders
inputs:
sshEndpoint: 'SSH-$(environment)'
runOptions: 'commands'
commands: >
mkdir -p /home/$(server_username)/$(environment)/SpCraft.$(app_name)
readyTimeout: '20000'
- task: replacetokens@6
displayName: Replace tokens in docker-compose
inputs:
root: '$(Build.SourcesDirectory)/src'
sources: 'docker-compose.yml'
tokenPattern: 'doublebraces'
missingVarAction: 'keep'
- task: CopyFilesOverSSH@0
displayName: Copy docker-compose.yml
inputs:
sshEndpoint: 'SSH-$(environment)'
sourceFolder: '$(Build.SourcesDirectory)/src'
contents: |
docker-compose.yml
targetFolder: >
/home/$(server_username)/$(environment)/SpCraft.$(app_name)
readyTimeout: '20000'
- task: SSH@0
displayName: Stop existing container
continueOnError: true
inputs:
sshEndpoint: 'SSH-$(environment)'
runOptions: 'commands'
commands: >
docker-compose
-f /home/$(server_username)/$(environment)/SpCraft.$(app_name)/docker-compose.yml
down >/dev/null 2>&1
readyTimeout: '20000'
- task: SSH@0
displayName: Pull latest images
continueOnError: true
inputs:
sshEndpoint: 'SSH-$(environment)'
runOptions: 'commands'
commands: >
docker-compose
-f /home/$(server_username)/$(environment)/SpCraft.$(app_name)/docker-compose.yml
pull >/dev/null 2>&1
readyTimeout: '20000'
- task: SSH@0
displayName: Start container
inputs:
sshEndpoint: 'SSH-$(environment)'
runOptions: 'commands'
commands: >
docker-compose
-f /home/$(server_username)/$(environment)/SpCraft.$(app_name)/docker-compose.yml
up -d >/dev/null 2>&1
readyTimeout: '20000'
Zarządzanie środowiskami
Uwaga: Ten układ obejmuje separację środowisk (Production/Test). W prostszych wdrożeniach możesz:
- Usunąć sekcję
parameters - Użyć stałych wartości zamiast zmiennych
- Pominąć konfiguracje specyficzne dla środowisk
Kluczowe korzyści
- Obsługa architektury ARM64 — zoptymalizowane dla instancji ARM Oracle Cloud
- Wieloetapowy build — mniejsze obrazy produkcyjne
- Automatyczne wdrożenia — wdrożenia bez przestojów
- Separacja środowisk — oddzielnie production i test
Podsumowanie
Hugo Extended to doskonała podstawa do budowy szybkich, skalowalnych witryn SaaS. Statyczny charakter stron Hugo zapewnia błyskawiczne działanie i minimalne zużycie zasobów serwera, co świetnie sprawdza się w nowoczesnych aplikacjach webowych.
Kolejne kroki
- Dopasuj motyw do swojej marki
- Przygotuj atrakcyjne treści dla grupy docelowej
- Skonfiguruj proces wdrożenia na wybranej platformie
- Dodaj analitykę i optymalizację SEO