개발노트

PC를 재부팅해도 웹서버가 켜지게 만들기: systemd 설정 순서

2026년 9월 28일 FNT-WORKS의 systemctl 실제 출력값을 배치한 자료. active, running, enabled 상태를 보여줍니다.

매번 터미널에서 웹서버를 다시 켜고 있다면 실행을 운영체제에 맡겨보세요. 예제 설정과 FNT-WORKS 서버에서 확인한 실제 상태를 나눠 살펴봅니다.

홈페이지를 띄워놓고 터미널까지 잘 정리했는데, PC를 재부팅하니 사이트가 열리지 않습니다. 다시 접속해서 실행 명령을 입력하면 살아납니다. 이 과정을 매번 반복하고 있다면 웹서버의 실행을 사람 대신 운영체제에 맡길 때입니다.

Ubuntu처럼 systemd를 사용하는 Linux에서는 웹서버를 서비스로 등록할 수 있습니다. 이 글에서는 Python 앱을 예로 들어 실행 파일, 작업 폴더, 자동 시작을 연결합니다. Windows나 macOS에 그대로 적용하는 방법은 아닙니다. 이미 Docker나 다른 관리 도구로 실행 중이라면 같은 앱을 중복 등록하지 마세요.

지금 실행 중인 것과 다음 부팅 때 켜지는 것은 다릅니다

먼저 두 가지를 나눠서 생각하면 덜 헷갈립니다. start는 지금 실행하는 명령이고, enable은 부팅 시 시작하도록 등록하는 명령입니다. 서비스를 한 번 켰다고 다음 부팅까지 준비된 것은 아닙니다. 반대로 등록만 하고 지금은 실행하지 않은 상태도 가능합니다.

확인하고 싶은 것명령
지금 실행 중인가요?systemctl is-active my-web.service
부팅 시 시작하도록 등록됐나요?systemctl is-enabled my-web.service

아래 예제에서는 enable --now로 등록과 현재 실행을 함께 처리합니다. 명령의 구분은 systemctl 공식 문서 원문에서도 확인할 수 있습니다.

1. 실행 명령과 폴더부터 정합니다

터미널에서는 잘 되는데 서비스로 등록하면 실패하는 경우가 있습니다. 실행 위치나 Python 경로가 달라졌을 수 있습니다. 평소에 어느 폴더로 이동한 뒤 어떤 명령을 썼는지 먼저 적어보세요.

항목이 글에서 사용하는 예시
프로젝트 폴더/home/ubuntu/my-web
실행 파일/home/ubuntu/my-web/server.py
Python 실행 파일/usr/bin/python3
실행 계정ubuntu
앱이 사용하는 포트3001

위 경로와 계정은 설명용입니다. 실제 파일과 계정이 있어야 하고, 실행 계정에는 필요한 파일을 읽고 데이터 폴더에 쓸 권한이 있어야 합니다. 가상환경을 쓴다면 Python 경로도 /home/ubuntu/my-web/.venv/bin/python처럼 바꿉니다. 터미널에서 가상환경을 켰던 상태가 서비스에 자동으로 이어지지는 않습니다.

2. 서비스 파일을 작성합니다

sudo nano /etc/systemd/system/my-web.service로 새 파일을 열고 아래 내용을 넣습니다. 같은 이름의 서비스가 이미 있다면 덮어쓰기 전에 기존 설정을 확인하세요. 아래는 직접 계속 실행되는 Python 앱을 위한 예제이지, 모든 프레임워크에 공통으로 쓰는 배포 설정은 아닙니다.

[Unit]
Description=My web application
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/my-web
ExecStart=/usr/bin/python3 /home/ubuntu/my-web/server.py
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

WorkingDirectory는 앱을 시작할 폴더이고, ExecStart는 실행 명령입니다. 웹 프레임워크를 사용한다면 그 프로젝트의 운영용 실행 명령으로 바꿉니다. 개발 서버를 서비스로 감쌌다고 운영에 필요한 보안과 성능 설정까지 끝나는 것은 아닙니다.

Restart=on-failure는 비정상 종료 시 재실행을 시도하게 합니다. RestartSec=3은 그전에 기다리는 시간입니다. 다만 앱이 멈춘 채 프로세스만 살아 있는 상황까지 알아서 치료하지는 않습니다. 반복 실패에는 재시작 제한이 걸릴 수도 있습니다. 자세한 조건은 systemd.service 공식 문서를 참고하세요.

또 After=network.target은 인터넷 연결 성공을 보장하는 설정이 아닙니다. 시작할 때 외부 API나 DB가 꼭 필요한 앱이라면 연결 실패에 대한 재시도도 별도로 설계해야 합니다.

환경변수는 어디에서 읽는지도 확인합니다

앱이 직접 프로젝트의 .env를 읽는다면 그 동작과 경로를 확인하면 됩니다. 그렇지 않다면 서비스의 [Service] 구역에 다음처럼 환경변수 파일을 지정할 수 있습니다. 두 방법을 무작정 섞기보다 어디서 값을 관리할지 먼저 정하는 편이 좋습니다.

EnvironmentFile=/home/ubuntu/my-web/.env

이 예제처럼 앞에 -를 붙이지 않은 필수 파일이 없으면 시작이 실패합니다. 파일에는 PORT=3001 같은 값을 적되, 앱이 실제로 그 변수를 읽어야 효과가 있습니다. 셸 스크립트의 모든 문법이 그대로 통하는 파일은 아닙니다. 환경변수 파일의 형식과 실행 폴더 설정은 systemd.exec 공식 문서에 정리돼 있습니다.

비밀번호나 API 키가 든 파일은 공개 저장소에 올리지 않고 읽기 권한도 제한합니다. 환경변수 자체가 완전한 비밀 저장소는 아닙니다. 설정이나 로그 화면을 공유할 때도 실제 키가 보이지 않는지 먼저 확인하세요.

3. 등록하고 상태를 확인합니다

이미 수동 실행한 앱이 같은 포트를 차지하고 있다면 먼저 정리해야 합니다. 운영 중인 사이트라면 이 전환 동안 잠깐 끊길 수 있으니 작업 시간을 정해 진행하세요. 그다음 아래 명령을 순서대로 실행합니다.

sudo systemctl daemon-reload
sudo systemctl enable --now my-web.service
systemctl is-enabled my-web.service
systemctl is-active my-web.service

이 예제에서는 각각 enabled와 active를 확인하면 됩니다. 하지만 프로세스가 실행됐다는 것과 홈페이지가 정상 응답한다는 것은 다릅니다. 앱이 정말 3001번 포트를 사용한다면 curl -I --max-time 10 http://127.0.0.1:3001/로 HTTP 응답도 봅니다. HEAD를 지원하지 않는 앱은 GET 요청으로 확인하세요.

이 홈페이지에서 확인한 상태는 이렇습니다

2026년 9월 28일 FNT-WORKS 서버에서 서비스 상태를 읽기 전용으로 확인했습니다. 글 상단 이미지는 아래 명령의 실제 출력값을 보기 쉽게 배치한 자료입니다. 터미널 전체를 촬영한 화면은 아닙니다.

systemctl show fntworks.service --property=ActiveState,SubState,UnitFileState,Restart,RestartUSec

항목확인한 값
ActiveState / SubStateactive / running
UnitFileStateenabled
Restart / RestartUSecalways / 3s

현재 서비스는 실행 중이고 자동 시작 등록도 되어 있습니다. 실제 설정은 Restart=always여서 앞의 예제와 다릅니다. 정상 종료까지 재실행 대상으로 삼을지, 실패했을 때만 다시 실행할지는 앱의 용도에 맞춰 정합니다. 관리자가 명시적으로 서비스를 중지한 경우에는 always라고 해서 다시 켜지지 않습니다.

이번 글을 위해 운영 서버를 재부팅하거나 강제로 종료하지는 않았습니다. 따라서 위 결과는 현재 설정과 실행 상태를 확인한 것이며, 오늘 재부팅 복구 시험까지 통과했다는 뜻은 아닙니다.

4. 안 켜지면 설정을 더 넣기 전에 로그를 봅니다

서비스가 실패했다면 먼저 sudo journalctl -u my-web.service -n 50 --no-pager로 최근 로그를 확인합니다. 한 번에 여러 설정을 바꾸지 말고, 처음 나온 오류부터 하나씩 해결하는 편이 낫습니다.

증상먼저 확인할 곳
Python 파일을 찾지 못합니다ExecStart의 경로와 가상환경 위치
권한 오류가 납니다User 계정과 파일·폴더 권한
포트가 이미 사용 중입니다수동 실행한 앱이나 기존 서비스의 중복 실행
필수 설정이 없다고 나옵니다앱의 .env 로딩 방식과 EnvironmentFile 경로
active인데 외부에서 안 열립니다로컬 HTTP 응답 다음에 프록시·터널과 네트워크 확인

서비스 파일을 수정했다면 sudo systemctl daemon-reload 후 sudo systemctl restart my-web.service로 다시 적용합니다. 재시작은 요청을 잠시 끊을 수 있습니다. 실행과 HTTP 응답을 확인한 뒤, 실제 부팅 검증은 복구 수단을 확보한 점검 시간이나 별도 테스트 환경에서 진행하세요.

자동 실행 설정의 마지막은 공개 주소 확인입니다

서버 PC 안에서 홈페이지가 열려도 외부 연결을 담당하는 프록시나 터널이 꺼져 있으면 방문자는 접속하지 못합니다. 앱 서비스만 보지 말고 공개 주소까지 열어보세요. 접속 범위별 확인 방법은 내 PC에서는 열리는데 밖에서는 접속이 안 됩니다에 따로 정리했습니다.

자동 실행은 긴 명령을 외우는 작업이라기보다, 누가 어떤 폴더에서 무엇을 실행하고, 실패하면 어디를 볼지 정해두는 작업에 가깝습니다. 먼저 실행 명령을 정확히 적고, 등록 상태와 현재 응답을 나눠 확인해보세요. 다음에 서버가 멈췄을 때도 같은 순서로 점검할 수 있습니다.

실전노트 목록 문의하기

댓글

0개

아직 표시된 댓글이 없습니다.

Google 계정으로 댓글 작성

이메일은 일부를 가린 아이디로 표시됩니다.