$linuxjunkies
>

Build an Intranet Server on Linux

Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.

IntermediateUbuntuDebianFedoraArch12 min readUpdated May 26, 2026

Before you start

  • A dedicated machine or VM with at least 2 GB RAM and 20 GB disk
  • Root or sudo access on the server
  • Basic familiarity with editing text files and running systemctl
  • LAN access with ability to configure the router's DHCP settings

A single Linux box can serve an entire small office: internal websites, shared files, local DNS resolution, and a team wiki. This guide walks through standing up all four services on one machine, keeping them isolated enough to maintain but simple enough for a team without a dedicated ops department. We use a Debian/Ubuntu base for most examples and note Fedora/RHEL and Arch differences inline.

Prerequisites and Planning

Assign the server a static IP on your LAN before touching anything else. Every service here depends on a stable address. On a systemd-networkd setup, edit your network configuration; on NetworkManager (most desktops and many servers), use nmcli:

sudo nmcli con mod "Wired connection 1" \
  ipv4.addresses 192.168.1.10/24 \
  ipv4.gateway 192.168.1.1 \
  ipv4.dns 127.0.0.1 \
  ipv4.method manual
sudo nmcli con up "Wired connection 1"

Replace the address and interface name to match your network. Setting ipv4.dns 127.0.0.1 points the server at its own DNS daemon, which you will install shortly.

Install and Harden the Web Server

Nginx is a solid choice for an internal web server: low memory footprint, clean virtual-host config, and easy to extend later.

Install Nginx

# Debian / Ubuntu
sudo apt update && sudo apt install -y nginx

# Fedora / RHEL / Rocky
sudo dnf install -y nginx

# Arch
sudo pacman -S --noconfirm nginx
sudo systemctl enable --now nginx

Create the Intranet Virtual Host

Put the intranet root under /srv/intranet and write a minimal virtual host. Adjust the hostname to whatever you will add to DNS in the next section.

sudo mkdir -p /srv/intranet/html
echo '<h1>Office Intranet</h1>' | sudo tee /srv/intranet/html/index.html
sudo tee /etc/nginx/sites-available/intranet <<'EOF'
server {
    listen 80;
    server_name intranet.office.lan;
    root /srv/intranet/html;
    index index.html;
    location / { try_files $uri $uri/ =404; }
}
EOF
sudo ln -s /etc/nginx/sites-available/intranet \
           /etc/nginx/sites-enabled/intranet
sudo nginx -t && sudo systemctl reload nginx

On Fedora/RHEL, there is no sites-available convention; drop the file in /etc/nginx/conf.d/intranet.conf instead and skip the symlink step.

Set Up Local DNS with dnsmasq

dnsmasq is a lightweight DNS forwarder that also handles DHCP if you need it. It lets you give every intranet service a human-readable name like intranet.office.lan without modifying every client's hosts file.

Install dnsmasq

# Debian / Ubuntu
sudo apt install -y dnsmasq

# Fedora / RHEL / Rocky
sudo dnf install -y dnsmasq

# Arch
sudo pacman -S --noconfirm dnsmasq

Note for Ubuntu 18.04+ users: systemd-resolved occupies port 53 by default. Disable its stub listener before starting dnsmasq:

sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' \
         /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved

Configure dnsmasq

sudo tee /etc/dnsmasq.d/office.conf <<'EOF'
# Listen only on the LAN interface and loopback
interface=lo
bind-interfaces

# Forward unresolved queries upstream
server=1.1.1.1
server=8.8.8.8

# Local zone — never forward .lan queries
local=/office.lan/
domain=office.lan

# A records for intranet services
address=/intranet.office.lan/192.168.1.10
address=/files.office.lan/192.168.1.10
address=/wiki.office.lan/192.168.1.10
EOF
sudo systemctl enable --now dnsmasq

Point your router's DHCP server to 192.168.1.10 as the primary DNS so every device on the LAN resolves *.office.lan automatically. If you cannot change the router, push the DNS address via a static DHCP lease or configure workstations individually.

Samba File Sharing

Samba exposes a share that Windows, macOS, and Linux clients can all mount with no extra client software.

Install Samba

# Debian / Ubuntu
sudo apt install -y samba

# Fedora / RHEL / Rocky
sudo dnf install -y samba samba-common

# Arch
sudo pacman -S --noconfirm samba

Create the Share Directory and Users

sudo mkdir -p /srv/shared
sudo chown root:staff /srv/shared    # or create a dedicated group
sudo chmod 2775 /srv/shared

Add a Samba password for each user who needs access. The Linux account must already exist.

sudo smbpasswd -a alice

Configure Samba

Back up the default config and write a minimal one:

sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
sudo tee /etc/samba/smb.conf <<'EOF'
[global]
   workgroup = OFFICE
   server string = Office File Server
   netbios name = fileserver
   security = user
   map to guest = never
   dns proxy = no

[Shared]
   path = /srv/shared
   browseable = yes
   writable = yes
   valid users = @staff
   create mask = 0664
   directory mask = 2775
EOF

sudo testparm -s && sudo systemctl enable --now smbd nmbd

On Fedora/RHEL, also allow Samba through SELinux and the local firewall:

sudo setsebool -P samba_export_all_rw 1
sudo firewall-cmd --permanent --add-service=samba
sudo firewall-cmd --reload

Deploy a Team Wiki with Wiki.js

Wiki.js is a modern Node.js wiki with a clean editor, Markdown support, and access controls. It runs well on modest hardware and stores content in PostgreSQL or SQLite.

Install Node.js and Wiki.js

# Install Node.js 20 LTS (all distros via NodeSource)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs    # Debian/Ubuntu
# For Fedora: use 'dnf' after running the NodeSource setup_20.x script
sudo mkdir -p /opt/wikijs && cd /opt/wikijs
sudo curl -fsSL https://github.com/Requarks/wiki/releases/latest/download/wiki-js.tar.gz \
     | sudo tar xz
sudo cp config.sample.yml config.yml

Edit /opt/wikijs/config.yml to set the port (e.g., 3000) and database. For a small team, SQLite requires the least setup:

sudo sed -i 's/type: postgres/type: sqlite/' /opt/wikijs/config.yml
sudo sed -i 's/# storage:/storage: \/opt\/wikijs\/wiki.db/' /opt/wikijs/config.yml

Run Wiki.js as a systemd Service

sudo tee /etc/systemd/system/wikijs.service <<'EOF'
[Unit]
Description=Wiki.js
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/node /opt/wikijs/server
WorkingDirectory=/opt/wikijs
Restart=always
User=www-data

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now wikijs

On Fedora/RHEL, change User=www-data to User=nginx or create a dedicated wikijs system user.

Proxy Wiki.js Through Nginx

Add a virtual host that forwards traffic from wiki.office.lan to the local Node process:

sudo tee /etc/nginx/sites-available/wiki <<'EOF'
server {
    listen 80;
    server_name wiki.office.lan;
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF
sudo ln -s /etc/nginx/sites-available/wiki \
           /etc/nginx/sites-enabled/wiki
sudo nginx -t && sudo systemctl reload nginx

Firewall Configuration

Allow only the ports your services actually need. Examples for ufw (Debian/Ubuntu) and firewalld (Fedora/RHEL):

# ufw — Debian / Ubuntu
sudo ufw allow from 192.168.1.0/24 to any port 80 comment 'Intranet HTTP'
sudo ufw allow from 192.168.1.0/24 to any port 53 comment 'DNS'
sudo ufw allow from 192.168.1.0/24 to any port 445 comment 'Samba'
sudo ufw allow from 192.168.1.0/24 to any port 137:139/tcp comment 'Samba NetBIOS'
sudo ufw enable
# firewalld — Fedora / RHEL / Rocky
sudo firewall-cmd --permanent --add-rich-rule=\
'rule family=ipv4 source address=192.168.1.0/24 service name=http accept'
sudo firewall-cmd --permanent --add-rich-rule=\
'rule family=ipv4 source address=192.168.1.0/24 service name=dns accept'
sudo firewall-cmd --reload

Verify Everything Works

Run these checks from a client machine on the same subnet:

# DNS resolution
dig intranet.office.lan @192.168.1.10 +short

# Web server
curl -si http://intranet.office.lan | head -5

# Wiki
curl -si http://wiki.office.lan | head -5

# Samba
smbclient -L 192.168.1.10 -U alice

Each command should return a valid response. If DNS is not resolving, confirm dnsmasq is running (systemctl status dnsmasq) and that the client's DNS server is set to 192.168.1.10.

Troubleshooting

  • Port 53 conflict on Ubuntu: If dnsmasq fails to start, check whether systemd-resolved is still holding port 53 with sudo ss -tulpn | grep :53. Re-apply the DNSStubListener fix and restart resolved.
  • Samba auth failures: Ensure the user has a Samba password set via smbpasswd and is a member of the valid users group. Check journalctl -u smbd for details.
  • Wiki.js not starting: Run node /opt/wikijs/server manually as the service user to see startup errors directly. Common causes are a missing config.yml key or a port already in use.
  • SELinux blocking Nginx proxy: On RHEL/Fedora, allow Nginx to make network connections: sudo setsebool -P httpd_can_network_connect 1.
  • Clients not resolving .lan names: If you cannot change the router's DNS, push DNS via a static DHCP reservation for each workstation, or add a dnsmasq instance to the router if it runs OpenWrt/DD-WRT.
tested on:Ubuntu 24.04Debian 12Fedora 40Rocky 9

Frequently asked questions

Can I add HTTPS to the intranet services without a public domain?
Yes. Use a private CA with mkcert or step-ca to issue LAN certificates for your .office.lan names. Install the CA root cert on each client device and Nginx will serve TLS just like a public site.
Why use dnsmasq instead of BIND for a small office?
dnsmasq needs a single config file and under 10 MB of RAM. BIND is more powerful but brings real operational overhead for a setup that only needs a handful of A records and upstream forwarding.
Will Samba shares work with macOS clients?
Yes. macOS has native SMB support. In Finder use Go → Connect to Server and enter smb://files.office.lan. Authenticate with the Samba username and password you set via smbpasswd.
How do I back up the wiki and shared files?
For Wiki.js with SQLite, copy /opt/wikijs/wiki.db on a schedule with a systemd timer or cron job. For Samba, rsync /srv/shared to an external drive or a remote host. Always stop or flush the SQLite file before copying to avoid corruption.
What if the office grows and one box is no longer enough?
Separate services onto dedicated VMs or containers (LXC, Docker, or KVM). The Nginx reverse proxy approach used here for Wiki.js scales naturally — just update the proxy_pass address and the DNS A record when you move a service.

Related guides